mirror of
https://github.com/FWGS/xash3d-fwgs.git
synced 2026-08-09 13:51:45 +08:00
Compare commits
223
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
215feb3ba9 | ||
|
|
150e2607d9 | ||
|
|
e8452c68d7 | ||
|
|
7fe0aba71c | ||
|
|
adcc9eb0df | ||
|
|
081d1da640 | ||
|
|
4aadea40a3 | ||
|
|
8deea9dc7e | ||
|
|
d650d8c271 | ||
|
|
eb89c8b222 | ||
|
|
659ffc4519 | ||
|
|
63a63a52de | ||
|
|
e082d76a45 | ||
|
|
cb8e2a4f9f | ||
|
|
5f55930cb7 | ||
|
|
dd03723144 | ||
|
|
26f07196ea | ||
|
|
8c291fdfe3 | ||
|
|
d1e118f07c | ||
|
|
6c531c14e6 | ||
|
|
433213c915 | ||
|
|
ab0c0b18c2 | ||
|
|
29fd5f9fbe | ||
|
|
882d8afc93 | ||
|
|
e11635d15c | ||
|
|
5d79d93aac | ||
|
|
7ccf651fd0 | ||
|
|
67af41cce8 | ||
|
|
e2c96e62e1 | ||
|
|
2ecae442fc | ||
|
|
a1060b0eb5 | ||
|
|
ddd8de888f | ||
|
|
a758dffbc1 | ||
|
|
87775faeca | ||
|
|
ef0fc46ed8 | ||
|
|
138b4fa247 | ||
|
|
47d1f3459c | ||
|
|
4712aae834 | ||
|
|
2900ee1cde | ||
|
|
c6c4178dd2 | ||
|
|
a3ce0e6b1b | ||
|
|
0b1ad3b7f0 | ||
|
|
37fb46f092 | ||
|
|
bc8bf9a9fb | ||
|
|
9e28c98911 | ||
|
|
0a1269d52d | ||
|
|
2e5bc31c9e | ||
|
|
1b335fd945 | ||
|
|
0c8b2d007a | ||
|
|
9ee1b32e2d | ||
|
|
953ad98a16 | ||
|
|
1357057bd8 | ||
|
|
35c9323de6 | ||
|
|
13a0afef06 | ||
|
|
c7ad8e4bf6 | ||
|
|
f1754bdd5f | ||
|
|
c462a1c500 | ||
|
|
0bba184994 | ||
|
|
178602ea1f | ||
|
|
2eb8f88a20 | ||
|
|
96d11df06c | ||
|
|
950d210ec5 | ||
|
|
55c1bddac5 | ||
|
|
ac50c762d7 | ||
|
|
5c2ab150b3 | ||
|
|
0870536405 | ||
|
|
b47ede477a | ||
|
|
eef5cc17b3 | ||
|
|
ad2191333d | ||
|
|
a85cac497d | ||
|
|
e0c69d7df5 | ||
|
|
ff3d91ceb4 | ||
|
|
5777431577 | ||
|
|
cd86f80203 | ||
|
|
8c885d3f37 | ||
|
|
dddb46a6d0 | ||
|
|
6b0f378c5b | ||
|
|
9dd7f37d42 | ||
|
|
9f10fb6472 | ||
|
|
64dbccb9bd | ||
|
|
9a432a5a13 | ||
|
|
842e494fa6 | ||
|
|
7fc9ee154a | ||
|
|
5f84010c2a | ||
|
|
3dcd6cb80b | ||
|
|
79e94bf766 | ||
|
|
3de370f3d5 | ||
|
|
c84d2f4624 | ||
|
|
380a9f7a6f | ||
|
|
a6c7b67d0d | ||
|
|
c13c1f2577 | ||
|
|
151405618f | ||
|
|
70e11cc309 | ||
|
|
7619824d80 | ||
|
|
f3d181b5ee | ||
|
|
55055a70f0 | ||
|
|
22d3ba674e | ||
|
|
ac487a2133 | ||
|
|
4da3a14adc | ||
|
|
69ec810ed0 | ||
|
|
2df01316ce | ||
|
|
3a67aefee2 | ||
|
|
d114dffcb4 | ||
|
|
7bb5d9a67a | ||
|
|
a6b1e57ae1 | ||
|
|
c70c13eb5c | ||
|
|
d905ea354e | ||
|
|
99cec81894 | ||
|
|
5d5bccf1bb | ||
|
|
6fcf0a77af | ||
|
|
e7477c0abf | ||
|
|
85540855c3 | ||
|
|
2dc220b42f | ||
|
|
2d6cadbf1b | ||
|
|
340871e03a | ||
|
|
e222a74960 | ||
|
|
ab499d5095 | ||
|
|
a5f7027229 | ||
|
|
bf5cf897e2 | ||
|
|
d33c1af549 | ||
|
|
677464d04d | ||
|
|
d2d6ed8bd4 | ||
|
|
bd2a44dbdd | ||
|
|
e9ee4beb9f | ||
|
|
3b3f057f6f | ||
|
|
a9dec51e59 | ||
|
|
257312ad7c | ||
|
|
6ee8a2dfa7 | ||
|
|
75c5e9cfa7 | ||
|
|
1a94f2b585 | ||
|
|
f0b4c42c68 | ||
|
|
9be061735f | ||
|
|
6bfa525080 | ||
|
|
8fcaf18897 | ||
|
|
f558cde266 | ||
|
|
b508a33f5d | ||
|
|
b4db99006b | ||
|
|
8994f079a5 | ||
|
|
b2d184cfa5 | ||
|
|
92dc92379f | ||
|
|
2a6862ceb9 | ||
|
|
4c569e1d5f | ||
|
|
4420ffd49e | ||
|
|
fb7f57cf6a | ||
|
|
8be3bdac5d | ||
|
|
2785376bd3 | ||
|
|
d6e77e531d | ||
|
|
e686b1410d | ||
|
|
2c23a1e0a0 | ||
|
|
47eb9e8c8f | ||
|
|
712b354421 | ||
|
|
18ef4922de | ||
|
|
274f9d5846 | ||
|
|
f6fa085fe4 | ||
|
|
9ab0f04ba5 | ||
|
|
fb7854f1ef | ||
|
|
1086c31503 | ||
|
|
3a47248a09 | ||
|
|
71a333261b | ||
|
|
5ea2e295c1 | ||
|
|
1fc7547a53 | ||
|
|
a7d63649f8 | ||
|
|
2f26fcdc2a | ||
|
|
107d4cdd61 | ||
|
|
52f9aad4d0 | ||
|
|
7bb5175084 | ||
|
|
dd570b616b | ||
|
|
943a30af04 | ||
|
|
eabed60e56 | ||
|
|
f793413a79 | ||
|
|
f4a3b8571d | ||
|
|
da6586b847 | ||
|
|
4a5f34089d | ||
|
|
90da9659d1 | ||
|
|
2e30acf611 | ||
|
|
5554d13f7f | ||
|
|
a5ef33b302 | ||
|
|
9a2588f7eb | ||
|
|
cac5852e68 | ||
|
|
d52d50e283 | ||
|
|
6911da8581 | ||
|
|
e70f9a67b8 | ||
|
|
173aa7333a | ||
|
|
2396b2d4db | ||
|
|
6120c0daec | ||
|
|
790f9bde54 | ||
|
|
7a469fb481 | ||
|
|
d4a2011a59 | ||
|
|
9165832caf | ||
|
|
d274a5c13c | ||
|
|
e6bd15c68b | ||
|
|
38bef99f98 | ||
|
|
95ff9e7165 | ||
|
|
2fddbdddee | ||
|
|
465e812ed9 | ||
|
|
3b1fb79a85 | ||
|
|
0f8f35b415 | ||
|
|
a133b1c2a9 | ||
|
|
fa74acb5f0 | ||
|
|
836b4c358f | ||
|
|
982e32d108 | ||
|
|
024a335505 | ||
|
|
963cbf61e4 | ||
|
|
6d98d2c7c3 | ||
|
|
64726f13e1 | ||
|
|
85dfaaa2c2 | ||
|
|
42a915b04a | ||
|
|
42a8aa6c66 | ||
|
|
56464d3291 | ||
|
|
aed96ee753 | ||
|
|
a937320c65 | ||
|
|
a81a0cb059 | ||
|
|
5af9511505 | ||
|
|
14ae9b312d | ||
|
|
2d3e5c2e0b | ||
|
|
17950fec3e | ||
|
|
2009140da8 | ||
|
|
2a394eee62 | ||
|
|
09a7585643 | ||
|
|
a09084ceba | ||
|
|
147e5dceff | ||
|
|
3510afd30b | ||
|
|
d3586c2143 |
+37
-35
@@ -43,80 +43,82 @@ jobs:
|
||||
- os: windows-2019 # always use the oldest possible for 32-bit because of older compilers, and better support of certain legacy OSes
|
||||
targetos: win32
|
||||
targetarch: i386
|
||||
- os: macos-14 # in GitHub documentation, it's an ARM64 machine
|
||||
targetos: apple
|
||||
targetarch: arm64
|
||||
- os: macos-12 # in GitHub documentation, it's an x86 machine
|
||||
targetos: apple
|
||||
targetarch: amd64
|
||||
env:
|
||||
SDL_VERSION: 2.30.3
|
||||
GH_CPU_ARCH: ${{ matrix.targetarch }}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
- name: Install dependencies
|
||||
run: bash scripts/gha/deps_${{ matrix.targetos }}.sh
|
||||
- name: Build engine
|
||||
env:
|
||||
FWGS_PFX_PASSWORD: ${{ secrets.FWGS_PFX_PASSWORD }}
|
||||
run: bash scripts/gha/build_${{ matrix.targetos }}.sh
|
||||
- name: Upload engine (artifacts)
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: artifact-${{ matrix.targetos }}-${{ matrix.targetarch }}
|
||||
path: artifacts/*
|
||||
flatpak:
|
||||
name: "Flatpak"
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- app: su.xash.Engine.Compat.i386
|
||||
container:
|
||||
image: bilelmoussaoui/flatpak-github-actions:freedesktop-22.08
|
||||
image: bilelmoussaoui/flatpak-github-actions:freedesktop-23.08
|
||||
options: --privileged
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
- name: Build flatpak (Compat.i386)
|
||||
uses: FWGS/flatpak-github-actions/flatpak-builder@v6.1
|
||||
uses: FWGS/flatpak-github-actions/flatpak-builder@v6.3
|
||||
with:
|
||||
bundle: ${{ matrix.app }}.flatpak
|
||||
manifest-path: scripts/flatpak/${{ matrix.app }}.yml
|
||||
- name: Upload engine (artifacts)
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: artifact-${{ matrix.targetos }}-${{ matrix.targetarch }}
|
||||
path: artifacts/*
|
||||
release:
|
||||
name: "Upload releases"
|
||||
runs-on: ubuntu-latest
|
||||
needs: [build, flatpak]
|
||||
if: ${{ github.event_name == 'push' }}
|
||||
steps:
|
||||
- name: Remove old release
|
||||
uses: FWGS/delete-tag-and-release@v0.2.1-dev
|
||||
with:
|
||||
tag_name: ${{ github.ref_name == 'master' && 'continuous' || format('continuous-{0}', github.ref_name) }}
|
||||
delete_release: true
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Fetch artifacts
|
||||
uses: actions/download-artifact@v3.0.1
|
||||
with:
|
||||
path: artifacts/
|
||||
- name: Repackage binaries and allow GitHub to process removed release for few seconds
|
||||
- name: Remove old release, fetch artifacts, repackage binaries and upload new release
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
RELEASE_TAG: ${{ github.ref_name == 'master' && 'continuous' || format('continuous-{0}', github.ref_name) }}
|
||||
run: |
|
||||
cd artifacts/
|
||||
for i in artifact-* su.xash.Engine.*; do
|
||||
gh release delete "$RELEASE_TAG" \
|
||||
--yes \
|
||||
--cleanup-tag \
|
||||
--repo "$GITHUB_REPOSITORY" || true
|
||||
sleep 20s
|
||||
gh run download "$GITHUB_RUN_ID" \
|
||||
--dir artifacts/ \
|
||||
--repo "$GITHUB_REPOSITORY"
|
||||
pushd artifacts/
|
||||
echo "Found artifacts:"
|
||||
ls
|
||||
for i in $(find -mindepth 1 -maxdepth 1 -type d); do
|
||||
mv "$i"/* .
|
||||
rm -rf "$i"
|
||||
done
|
||||
ls -R .
|
||||
cd ../
|
||||
echo "Repackaged artifacts:"
|
||||
ls -R
|
||||
popd
|
||||
sleep 20s
|
||||
- name: Upload new release
|
||||
uses: FWGS/action-gh-release@v0.1.15
|
||||
with:
|
||||
name: Xash3D FWGS Continuous ${{ github.ref_name }} Build
|
||||
tag_name: ${{ github.ref_name == 'master' && 'continuous' || format('continuous-{0}', github.ref_name) }}
|
||||
prerelease: true
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
files: artifacts/*
|
||||
draft: false
|
||||
gh release create "$RELEASE_TAG" artifacts/* \
|
||||
--title "Xash3D FWGS Continuous ${{ github.ref_name }} Build" \
|
||||
--target $GITHUB_SHA \
|
||||
--repo "$GITHUB_REPOSITORY" \
|
||||
--prerelease
|
||||
|
||||
@@ -19,3 +19,6 @@
|
||||
[submodule "3rdparty/xash-extras"]
|
||||
path = 3rdparty/extras/xash-extras
|
||||
url = https://github.com/FWGS/xash-extras
|
||||
[submodule "3rdparty/bzip2/bzip2"]
|
||||
path = 3rdparty/bzip2/bzip2
|
||||
url = https://gitlab.com/bzip2/bzip2
|
||||
|
||||
+1
Submodule 3rdparty/bzip2/bzip2 added at 66c46b8c94
Vendored
+35
@@ -0,0 +1,35 @@
|
||||
#! /usr/bin/env python
|
||||
# encoding: utf-8
|
||||
|
||||
BZIP_CHECK='''#include <bzlib.h>
|
||||
int main(void) { return BZ2_bzlibVersion() != NULL; }
|
||||
'''
|
||||
|
||||
def options(opt):
|
||||
pass
|
||||
|
||||
def configure(conf):
|
||||
conf.define('_GNU_SOURCE', 1)
|
||||
|
||||
if conf.env.DEST_OS == 'win32':
|
||||
conf.define('BZ_LCCWIN32', 1)
|
||||
else:
|
||||
conf.define('BZ_UNIX', 1)
|
||||
|
||||
def build(bld):
|
||||
bld(
|
||||
features = 'subst',
|
||||
source = 'bzip2/bz_version.h.in',
|
||||
target = 'bz_version.h',
|
||||
BZ_VERSION='1.1.0-fwgs'
|
||||
)
|
||||
|
||||
bld.stlib(
|
||||
source = bld.path.ant_glob(['bzip2/*.c']),
|
||||
target = 'bzip2',
|
||||
use = 'bz_version.h',
|
||||
features = 'c',
|
||||
includes = ['bzip2/', '.'],
|
||||
subsystem = bld.env.MSVC_SUBSYSTEM,
|
||||
export_includes = ['bzip2/']
|
||||
)
|
||||
Vendored
+1
-1
Submodule 3rdparty/extras/xash-extras updated: 853f633be1...f4ff263d42
Vendored
+1
-1
Submodule 3rdparty/mainui updated: f0c11b141f...b7edbaf2de
@@ -14,3 +14,4 @@ When `-bugcomp` is specified with argument, it interpreted as flags separated wi
|
||||
| ------- | ----------- | ---------------------------- |
|
||||
| `peoei` | Reverts `pfnPEntityOfEntIndex` behavior to GoldSrc, where it returns NULL for last player due to incorrect player index comparison | * Counter-Strike: Condition Zero - Deleted Scenes |
|
||||
| `gsmrf` | Rewrites message at the moment when Game DLL attempts to write an internal engine message, usually specific to GoldSrc protocol. Right now only supports `svc_spawnstaticsound`, more messages added by request. | * MetaMod/AMXModX based mods |
|
||||
| `sp_attn_none` | Makes sounds with attenuation zero spatialized, i.e. have a stereo effect. | Possibly, every game that was made for GoldSrc. |
|
||||
|
||||
@@ -78,6 +78,7 @@ These strings are specific to Xash3D FWGS.
|
||||
| `internal_vgui_support` | boolean | 0 | Only for programmers! Required to be set as 1 for PrimeXT!<br>When set to 1, the engine will not load vgui_support DLL, as VGUI support is done (or intentionally ignored) on the game side. |
|
||||
| `render_picbutton_text` | boolean | 0 | When set to 1, the UI will not use prerendered `btns_main.bmp` and dynamically render them instead |
|
||||
| `quicksave_aged_count` | integer | 2 | Quick saves limit used in saves rotation |
|
||||
| `demomap` | string | Empty string | The name of the demo chapter map (Half-Life Uplink) |
|
||||
|
||||
## Note on GoldSrc liblist.gam support
|
||||
|
||||
|
||||
@@ -19,7 +19,22 @@
|
||||
- [List of XashXT-based mods](#list-of-xashxt-based-mods)
|
||||
- [List of maps for They Hunger](#list-of-maps-for-they-hunger)
|
||||
- [List of games and mods with custom gamedll](#list-of-games-and-mods-with-custom-gamedll)
|
||||
- [List of mods for Counter Strike(Android only)](#list-of-mods-for-counter-strike)
|
||||
- [List of mods for Counter Strike](#list-of-mods-for-counter-strike)
|
||||
- [List of supported mods from mobile_hacks branch of HLSDK Portable by FWGS](#list-of-supported-mods-from-mobile_hacks-branch-of-hlsdk-portable-by-fwgs)
|
||||
|
||||
# List of supported mods from mobile_hacks branch of HLSDK Portable by FWGS
|
||||
1. [Afraid of Monsters](https://www.moddb.com/mods/afraid-of-monsters/downloads/afraid-of-monsters-v1)
|
||||
2. [Big Lolly](https://www.moddb.com/mods/big-lolly)
|
||||
3. [Half-Life: Blue Shift](https://store.steampowered.com/app/130/HalfLife_Blue_Shift/)
|
||||
4. [Half-Secret](https://www.moddb.com/mods/half-secret)
|
||||
5. [Case Closed](https://www.moddb.com/mods/caseclosed)
|
||||
6. [Bloody Pizza - Vendetta](https://www.moddb.com/games/half-life/addons/bloody-pizza-vendetta)
|
||||
7. [Borderlands](https://www.moddb.com/games/half-life/addons/borderlands-v04)
|
||||
8. [Half-Life: Induction](https://www.moddb.com/mods/half-life-induction/downloads/half-life-induction-12)
|
||||
9. [Redemption/Absolute Redemption](https://www.moddb.com/mods/absolute-redemption)
|
||||
10. [Sewer beta](https://www.moddb.com/games/half-life/addons/sewer-beta)
|
||||
11. [Times of Troubles](https://www.moddb.com/mods/times-of-troubles)
|
||||
12. [Half-Life: Urbicide](https://www.moddb.com/mods/half-life-urbicide)
|
||||
|
||||
# List of Half-Life-based mods
|
||||
Originally this list was written by *Qwertyus*(*Qortez*)
|
||||
@@ -176,7 +191,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)](https://web.archive.org/web/20161026104825/http://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)
|
||||
@@ -282,7 +297,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)](https://web.archive.org/web/20110512012317/http://www.richmans-maps.ch.vu/)
|
||||
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 +320,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](https://web.archive.org/web/20110512012317/http://www.richmans-maps.ch.vu/)
|
||||
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](https://web.archive.org/web/20110512012317/http://www.richmans-maps.ch.vu/)
|
||||
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 +394,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)](https://web.archive.org/web/20160407041812/http://half-life.ru/forum/showthread.php?threadid=13959) (download links dead!)
|
||||
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 +455,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://web.archive.org/web/20151030005310/http://www.gamefront.com/files/13532512)
|
||||
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)
|
||||
@@ -498,8 +513,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](https://web.archive.org/web/20170221213409/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!)
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
[](https://builds.sr.ht/~a1batross/xash3d-fwgs?) [](https://github.com/FWGS/xash3d-fwgs/actions/workflows/c-cpp.yml) [](https://cirrus-ci.com/github/FWGS/xash3d-fwgs) [](http://fwgsdiscord.mentality.rip/) \
|
||||
[](https://github.com/FWGS/xash3d-fwgs/releases/latest) [](https://github.com/FWGS/xash3d-fwgs/releases/tag/continuous)
|
||||
|
||||
Xash3D FWGS is a game engine, aimed to provide compatibility with Half-Life Engine and extend it, as well as to give game developers well known workflow.
|
||||
Xash3D (pronounced `[ksɑʂ]`) FWGS is a game engine, aimed to provide compatibility with Half-Life Engine and extend it, as well as to give game developers well known workflow.
|
||||
|
||||
Xash3D FWGS is a heavily modified fork of an original [Xash3D Engine](https://www.moddb.com/engines/xash3d-engine) by Unkle Mike.
|
||||
|
||||
@@ -28,7 +28,7 @@ If you like Xash3D FWGS, consider supporting individual engine maintainers. By s
|
||||
1) Copy engine binaries to some directory.
|
||||
2) Copy `valve` directory from [Half-Life](https://store.steampowered.com/app/70/HalfLife/) to directory with engine binaries.
|
||||
If your CPU is NOT x86 compatible or you're running 64-bit version of the engine, you may want to compile [Half-Life SDK](https://github.com/FWGS/hlsdk-portable).
|
||||
This repository contains our fork of HLSDK and restored source code for some of the mods. Not all of them, of course.
|
||||
This repository contains our fork of HLSDK and restored source code for Half-Life expansions and some mods.
|
||||
You still needed to copy `valve` directory as all game resources located there.
|
||||
3) Run the main executable (`xash3d.exe` or AppImage).
|
||||
|
||||
@@ -46,11 +46,11 @@ NOTE: NEVER USE GitHub's ZIP ARCHIVES. GitHub doesn't include external dependenc
|
||||
|
||||
### Prerequisites
|
||||
|
||||
If your CPU is x86 compatible, we are building 32-bit code by default. This was done to maintain compatibility with Steam releases of Half-Life and based on it's engine games.
|
||||
If your CPU is x86 compatible and you're on Windows or Linux, we are building 32-bit code by default. This was done to maintain compatibility with Steam releases of Half-Life and based on it's engine games.
|
||||
Even if Xash3D FWGS does support targetting 64-bit, you can't load games without recompiling them from source code!
|
||||
|
||||
If your CPU is NOT x86 compatible or you decided build 64-bit version of engine, you may want to compile [Half-Life SDK](https://github.com/FWGS/hlsdk-portable).
|
||||
This repository contains our fork of HLSDK and restored source code for some of the mods. Not all of them, of course.
|
||||
This repository contains our fork of HLSDK and restored source code for Half-Life expansions and some mods.
|
||||
|
||||
#### Windows (Visual Studio)
|
||||
* Install Visual Studio.
|
||||
@@ -67,9 +67,9 @@ This repository contains our fork of HLSDK and restored source code for some of
|
||||
`$ sudo dpkg --add-architecture i386`
|
||||
* Install development tools
|
||||
* For 32-bit engine on amd64: \
|
||||
`$ sudo apt install build-essential gcc-multilib g++-multilib python libsdl2-dev:i386 libfontconfig-dev:i386 libfreetype6-dev:i386`
|
||||
`$ sudo apt install build-essential gcc-multilib g++-multilib python libsdl2-dev:i386 libfontconfig-dev:i386 libfreetype6-dev:i386 libopus-dev:i386 libbz2-dev:i386`
|
||||
* For everything else: \
|
||||
`$ sudo apt install build-essential python libsdl2-dev libfontconfig-dev libfreetype6-dev`
|
||||
`$ sudo apt install build-essential python libsdl2-dev libfontconfig-dev libfreetype6-dev libopus-dev libbz2-dev`
|
||||
* Clone this repostory:
|
||||
`$ git clone --recursive https://github.com/FWGS/xash3d-fwgs`
|
||||
|
||||
|
||||
+21
-18
@@ -127,14 +127,23 @@ typedef struct
|
||||
int flags; // sky or slime, no lightmap or 256 subdivision
|
||||
} mtexinfo_t;
|
||||
|
||||
typedef struct glpoly_s
|
||||
// a1ba: changed size to avoid undefined behavior. Check your allocations if you take this header!
|
||||
// For example:
|
||||
// before: malloc( sizeof( glpoly_t ) + ( numverts - 4 ) * VERTEXSIZE * sizeof( float ))
|
||||
// after (C): malloc( sizeof( glpoly_t ) + numverts * VERTEXSIZE * sizeof( float ))
|
||||
// after (C++): malloc( sizeof( glpoly_t ) + ( numverts - 1 ) * VERTEXSIZE * sizeof( float ))
|
||||
typedef struct glpoly2_s
|
||||
{
|
||||
struct glpoly_s *next;
|
||||
struct glpoly_s *chain;
|
||||
struct glpoly2_s *next;
|
||||
struct glpoly2_s *chain;
|
||||
int numverts;
|
||||
int flags; // for SURF_UNDERWATER
|
||||
float verts[4][VERTEXSIZE]; // variable sized (xyz s1t1 s2t2)
|
||||
} glpoly_t;
|
||||
#ifdef __cplusplus
|
||||
float verts[1][VERTEXSIZE]; // variable sized (xyz s1t1 s2t2)
|
||||
#else
|
||||
float verts[][VERTEXSIZE]; // variable sized (xyz s1t1 s2t2)
|
||||
#endif
|
||||
} glpoly2_t;
|
||||
|
||||
typedef struct mnode_s
|
||||
{
|
||||
@@ -173,7 +182,7 @@ struct decal_s
|
||||
short entityIndex; // Entity this is attached to
|
||||
// Xash3D specific
|
||||
vec3_t position; // location of the decal center in world space.
|
||||
glpoly_t *polys; // precomputed decal vertices
|
||||
glpoly2_t *polys; // precomputed decal vertices
|
||||
intptr_t reserved[4]; // just for future expansions or mod-makers
|
||||
};
|
||||
|
||||
@@ -246,7 +255,7 @@ struct msurface_s
|
||||
|
||||
int light_s, light_t; // gl lightmap coordinates
|
||||
|
||||
glpoly_t *polys; // multiple if warped
|
||||
glpoly2_t *polys; // multiple if warped
|
||||
struct msurface_s *texturechain;
|
||||
|
||||
mtexinfo_t *texinfo;
|
||||
@@ -488,7 +497,8 @@ typedef struct
|
||||
int flags;
|
||||
float size;
|
||||
|
||||
int reserved[8]; // VBO offsets
|
||||
const trivertex_t **pposeverts; // only valid during loading, used to build GL mesh
|
||||
intptr_t reserved[7]; // VBO offsets
|
||||
|
||||
int numposes;
|
||||
int poseverts;
|
||||
@@ -531,17 +541,10 @@ typedef struct
|
||||
#define MAX_MOVIES 8
|
||||
#define MAX_CDTRACKS 32
|
||||
#define MAX_CLIENT_SPRITES 512 // SpriteTextures (0-256 hud, 256-512 client)
|
||||
#define MAX_EFRAGS 8192 // Arcane Dimensions required
|
||||
#define MAX_REQUESTS 64
|
||||
|
||||
#if ! XASH_64BIT
|
||||
STATIC_ASSERT( sizeof( mextrasurf_t ) == 324, "mextrasurf_t unexpected size" );
|
||||
STATIC_ASSERT( sizeof( decal_t ) == 60, "decal_t unexpected size");
|
||||
STATIC_ASSERT( sizeof( mfaceinfo_t ) == 176, "mfaceinfo_t unexpected size");
|
||||
#else
|
||||
STATIC_ASSERT( sizeof( mextrasurf_t) == 496, "mextrasurf_t unexpected size");
|
||||
STATIC_ASSERT( sizeof( decal_t ) == 88, "decal_t unexpected size");
|
||||
STATIC_ASSERT( sizeof( mfaceinfo_t ) == 304, "mfaceinfo_t unexpected size");
|
||||
#endif
|
||||
STATIC_CHECK_SIZEOF( mextrasurf_t, 324, 496 );
|
||||
STATIC_CHECK_SIZEOF( decal_t, 60, 88 );
|
||||
STATIC_CHECK_SIZEOF( mfaceinfo_t, 176, 304 );
|
||||
|
||||
#endif//COM_MODEL_H
|
||||
|
||||
+116
-43
@@ -1,49 +1,122 @@
|
||||
/***
|
||||
*
|
||||
* Copyright (c) 1996-2002, Valve LLC. All rights reserved.
|
||||
*
|
||||
* This product contains software technology licensed from Id
|
||||
* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Use, distribution, and modification of this source code and/or resulting
|
||||
* object code is restricted to non-commercial enhancements to products from
|
||||
* Valve LLC. All other use, distribution, or modification is prohibited
|
||||
* without written permission from Valve LLC.
|
||||
*
|
||||
****/
|
||||
#ifndef CVARDEF_H
|
||||
#define CVARDEF_H
|
||||
/*
|
||||
cvardef.h - quake cvar definition
|
||||
Copyright (C) 1997-2001 Id Software, Inc.
|
||||
Copyright (C) 2024 Alibek Omarov
|
||||
|
||||
#define FCVAR_ARCHIVE (1<<0) // set to cause it to be saved to vars.rc
|
||||
#define FCVAR_USERINFO (1<<1) // changes the client's info string
|
||||
#define FCVAR_SERVER (1<<2) // notifies players when changed
|
||||
#define FCVAR_EXTDLL (1<<3) // defined by external DLL
|
||||
#define FCVAR_CLIENTDLL (1<<4) // defined by the client dll
|
||||
#define FCVAR_PROTECTED (1<<5) // It's a server cvar, but we don't send the data since it's a password, etc. Sends 1 if it's not bland/zero, 0 otherwise as value
|
||||
#define FCVAR_SPONLY (1<<6) // This cvar cannot be changed by clients connected to a multiplayer server.
|
||||
#define FCVAR_PRINTABLEONLY (1<<7) // This cvar's string cannot contain unprintable characters ( e.g., used for player name etc ).
|
||||
#define FCVAR_UNLOGGED (1<<8) // If this is a FCVAR_SERVER, don't log changes to the log file / console if we are creating a log
|
||||
#define FCVAR_NOEXTRAWHITEPACE (1<<9) // strip trailing/leading white space from this cvar
|
||||
#define FCVAR_PRIVILEGED (1<<10) // only available in privileged mode
|
||||
#define FCVAR_FILTERABLE (1<<11) // filtered in unprivileged mode if cl_filterstuffcmd is 1
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
// Xash3D extensions
|
||||
#define FCVAR_GLCONFIG (1<<12) // write it into <renderer>.cfg(see RefAPI)
|
||||
#define FCVAR_CHANGED (1<<13) // set each time the cvar is changed
|
||||
#define FCVAR_GAMEUIDLL (1<<14) // defined by the menu DLL
|
||||
#define FCVAR_CHEAT (1<<15) // can not be changed if cheats are disabled
|
||||
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.
|
||||
|
||||
// a1ba: let's reuse higher bits for flags extensions from now on
|
||||
#define FCVAR_LATCH (1<<30) // notify client what this cvar will be applied only after server restart (but don't does more nothing)
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
typedef struct cvar_s
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
#ifndef CVAR
|
||||
#define CVAR
|
||||
|
||||
#include STDINT_H
|
||||
#include "xash3d_types.h"
|
||||
|
||||
/*
|
||||
|
||||
cvar_t variables are used to hold scalar or string variables that can be changed
|
||||
or displayed at the console or prog code as well as accessed directly
|
||||
in C code.
|
||||
|
||||
The user can access cvars from the console in three ways:
|
||||
r_draworder prints the current value
|
||||
r_draworder 0 sets the current value to 0
|
||||
set r_draworder 0 as above, but creates the cvar if not present
|
||||
|
||||
Cvars are restricted from having the same names as commands to keep this
|
||||
interface from being ambiguous.
|
||||
|
||||
The are also occasionally used to communicated information between different
|
||||
modules of the program.
|
||||
|
||||
*/
|
||||
|
||||
enum
|
||||
{
|
||||
char *name;
|
||||
char *string;
|
||||
int flags;
|
||||
float value;
|
||||
struct cvar_s *next;
|
||||
} cvar_t;
|
||||
// GoldSrc compatibility flags
|
||||
FCVAR_ARCHIVE = 1 << 0, // set to cause it to be saved to vars.rc
|
||||
FCVAR_USERINFO = 1 << 1, // added to userinfo when changed
|
||||
FCVAR_SERVER = 1 << 2, // added to serverinfo when changed, will notify clients by default
|
||||
FCVAR_EXTDLL = 1 << 3, // defined by server.dll
|
||||
FCVAR_CLIENTDLL = 1 << 4, // defined by client.dll
|
||||
FCVAR_PROTECTED = 1 << 5, // private server cvar
|
||||
FCVAR_SPONLY = 1 << 6, // can be set only in singleplayer
|
||||
FCVAR_PRINTABLEONLY = 1 << 7, // only allows printable characters
|
||||
FCVAR_UNLOGGED = 1 << 8, // disables notifying client about server cvar change
|
||||
FCVAR_NOEXTRAWHITESPACE = 1 << 9, // removes space characters from the beginning and the end of the string
|
||||
FCVAR_PRIVILEGED = 1 << 10, // only available in privileged mode
|
||||
FCVAR_FILTERABLE = 1 << 11, // treated as privileged if cl_filterstuffcmd is 1, otherwise ignored
|
||||
|
||||
#endif//CVARDEF_H
|
||||
// Xash3D public flags
|
||||
// FCVAR_LATCH = 1 << 11, // deprecated Xash3D flag, conflicts with FCVAR_FILTERABLE. Use another FCVAR_LATCH!
|
||||
FCVAR_GLCONFIG = 1 << 12, // set to cause it to be saved to <renderer>.cfg (see RefAPI)
|
||||
FCVAR_CHANGED = 1 << 13, // set each time the cvar changed
|
||||
FCVAR_GAMEUIDLL = 1 << 14, // defined by menu.dll
|
||||
FCVAR_CHEAT = 1 << 15, // cannot be changed if sv_cheats is 0
|
||||
|
||||
#if REF_DLL || ENGINE_DLL // Xash3D internal flags, MUST NOT be used outside of engine
|
||||
FCVAR_RENDERINFO = 1 << 16, // set to cause it to be saved to video.cfg
|
||||
FCVAR_READ_ONLY = 1 << 17, // display only, cannot be set by user at all
|
||||
FCVAR_EXTENDED = 1 << 18, // extended cvar structure
|
||||
FCVAR_ALLOCATED = 1 << 19, // allocated by the engine, must be freed with Mem_Free
|
||||
FCVAR_VIDRESTART = 1 << 20, // triggers video subsystem to recreate/modify window parameters
|
||||
FCVAR_TEMPORARY = 1 << 21, // only used to temporarly hold some value, can be unlinked
|
||||
FCVAR_MOVEVARS = 1 << 22, // access to movevars_t structure, synchornized between client and server
|
||||
FCVAR_USER_CREATED = 1 << 23, // created by a set command
|
||||
|
||||
FCVAR_REFDLL = 1 << 29, // (Xash3D FWGS internal flag) defined by the renderer DLL
|
||||
#endif // REF_DLL || ENGINE_DLL
|
||||
|
||||
FCVAR_LATCH = 1 << 30, // (Xash3D FWGS public flag, was FCVAR_FILTERABLE in Xash3D) save changes until server restart
|
||||
};
|
||||
|
||||
struct cvar_s {
|
||||
char *name;
|
||||
char *string;
|
||||
uint32_t flags;
|
||||
float value;
|
||||
struct cvar_s *next;
|
||||
};
|
||||
typedef struct cvar_s cvar_t;
|
||||
|
||||
STATIC_CHECK_SIZEOF( struct cvar_s, 20, 32 );
|
||||
|
||||
#if REF_DLL || ENGINE_DLL // Xash3D internal cvar format, MUST NOT be used outside of engine
|
||||
struct convar_s {
|
||||
char *name;
|
||||
char *string;
|
||||
uint32_t flags;
|
||||
float value;
|
||||
struct convar_s *next;
|
||||
char *desc;
|
||||
char *def_string;
|
||||
};
|
||||
typedef struct convar_s convar_t;
|
||||
|
||||
#if XASH_64BIT
|
||||
#define CVAR_SENTINEL (uintptr_t)0xDEADBEEFDEADBEEF
|
||||
#else
|
||||
#define CVAR_SENTINEL (uintptr_t)0xDEADBEEF
|
||||
#endif
|
||||
|
||||
#define CVAR_CHECK_SENTINEL( cv ) ((uintptr_t)(cv)->next == CVAR_SENTINEL)
|
||||
|
||||
#define CVAR_DEFINE( cv, cvname, cvstr, cvflags, cvdesc ) \
|
||||
convar_t cv = { (char*)cvname, (char*)cvstr, cvflags, 0.0f, (void *)CVAR_SENTINEL, (char*)cvdesc, NULL }
|
||||
|
||||
#define CVAR_DEFINE_AUTO( cv, cvstr, cvflags, cvdesc ) CVAR_DEFINE( cv, #cv, cvstr, cvflags, cvdesc )
|
||||
#endif // REF_DLL || ENGINE_DLL
|
||||
|
||||
#endif // CVAR
|
||||
|
||||
+45
-1
@@ -30,7 +30,7 @@ GAMEINFO stuff
|
||||
internal shared gameinfo structure (readonly for engine parts)
|
||||
========================================================================
|
||||
*/
|
||||
typedef struct
|
||||
typedef struct GAMEINFO_s
|
||||
{
|
||||
// filesystem info
|
||||
char gamefolder[64]; // used for change game '-game x'
|
||||
@@ -50,4 +50,48 @@ typedef struct
|
||||
int gamemode;
|
||||
} GAMEINFO;
|
||||
|
||||
/*
|
||||
========================================================================
|
||||
|
||||
Extended GameInfo struct introduced in Xash3D FWGS
|
||||
|
||||
GAMEINFO can't be reliably extended, as nor engine, nor menu can't be
|
||||
sure about struct size. By adding struct versioning, we can check the
|
||||
presense for extra fields.
|
||||
========================================================================
|
||||
*/
|
||||
|
||||
#define GAMEINFO_VERSION 2
|
||||
|
||||
typedef enum gametype_e
|
||||
{
|
||||
GAME_NORMAL,
|
||||
GAME_SINGLEPLAYER_ONLY,
|
||||
GAME_MULTIPLAYER_ONLY,
|
||||
} gametype_t;
|
||||
|
||||
typedef struct gameinfo2_s
|
||||
{
|
||||
int gi_version; // should be set to desired struct version, e.g. GAMEINFO_VERSION
|
||||
|
||||
// filesystem info
|
||||
char gamefolder[64]; // used for change game
|
||||
char startmap[64]; // map to start singleplayer game from
|
||||
char trainmap[64]; // map to start hazardous course from (if specified)
|
||||
char demomap[64]; // map to start demo chapter from (if specified)
|
||||
char title[64]; // game title
|
||||
char iconpath[64]; // path to game icon
|
||||
char version[16]; // game version (optional)
|
||||
uint32_t flags; // gameinfo flags, extended to fit more flags
|
||||
|
||||
// mod info
|
||||
char game_url[256]; // link to a developer's site
|
||||
char update_url[256]; // link to updates page
|
||||
char type[64]; // single, toolkit, multiplayer, etc
|
||||
char date[64]; // release date
|
||||
uint64_t size; // size in bytes
|
||||
|
||||
gametype_t gamemode;
|
||||
} gameinfo2_t;
|
||||
|
||||
#endif//GAMEINFO_H
|
||||
|
||||
+1
-1
@@ -30,6 +30,6 @@ typedef struct
|
||||
int state; // low bit is down state
|
||||
} kbutton_t;
|
||||
|
||||
STATIC_ASSERT( sizeof( kbutton_t ) == 12, "kbutton_t isn't 12 bytes!" );
|
||||
STATIC_CHECK_SIZEOF( kbutton_t, 12, 12 );
|
||||
|
||||
#endif // KBUTTON_H
|
||||
|
||||
+1
-1
@@ -69,6 +69,6 @@ typedef struct netadr_s
|
||||
} netadr_t;
|
||||
#pragma pack( pop )
|
||||
|
||||
STATIC_ASSERT( sizeof( netadr_t ) == 20, "netadr_t isn't 20 bytes!" );
|
||||
STATIC_CHECK_SIZEOF( netadr_t, 20, 20 );
|
||||
|
||||
#endif // NET_ADR_H
|
||||
|
||||
@@ -56,6 +56,8 @@ color24 gTracerColors[] =
|
||||
};
|
||||
*/
|
||||
|
||||
#define TRACER_COLORINDEX_DEFAULT 4
|
||||
|
||||
// Temporary entity array
|
||||
#define TENTPRIORITY_LOW 0
|
||||
#define TENTPRIORITY_HIGH 1
|
||||
|
||||
@@ -79,11 +79,22 @@ typedef uint64_t longtime_t;
|
||||
#define GAME_EXPORT
|
||||
#endif
|
||||
|
||||
#define MALLOC __attribute__(( malloc ))
|
||||
|
||||
// added in GCC 11
|
||||
#if __GNUC__ >= 11
|
||||
// might want to set noclone due to https://gcc.gnu.org/bugzilla/show_bug.cgi?id=116893
|
||||
// but it's easier to not force mismatched-dealloc to error yet
|
||||
#define MALLOC_LIKE( x, y ) __attribute__(( malloc( x, y )))
|
||||
#else
|
||||
#define MALLOC_LIKE( x, y ) MALLOC
|
||||
#endif
|
||||
#define NORETURN __attribute__(( noreturn ))
|
||||
#define NONNULL __attribute__(( nonnull ))
|
||||
#define _format( x ) __attribute__(( format( printf, x, x + 1 )))
|
||||
#define ALLOC_CHECK( x ) __attribute__(( alloc_size( x )))
|
||||
#define NO_ASAN __attribute__(( no_sanitize( "address" )))
|
||||
#define WARN_UNUSED_RESULT __attribute__(( warn_unused_result ))
|
||||
#define RENAME_SYMBOL( x ) asm( x )
|
||||
#else
|
||||
#if defined( _MSC_VER )
|
||||
@@ -99,6 +110,9 @@ typedef uint64_t longtime_t;
|
||||
#define _format( x )
|
||||
#define ALLOC_CHECK( x )
|
||||
#define RENAME_SYMBOL( x )
|
||||
#define MALLOC
|
||||
#define MALLOC_LIKE( x, y )
|
||||
#define WARN_UNUSED_RESULT
|
||||
#endif
|
||||
|
||||
#if __GNUC__ >= 3
|
||||
@@ -130,6 +144,15 @@ typedef uint64_t longtime_t;
|
||||
#define STATIC_ASSERT( x, y ) STATIC_ASSERT_2( __LINE__, x, y )
|
||||
#endif
|
||||
|
||||
// at least, statically check size of some public structures
|
||||
#if XASH_64BIT
|
||||
#define STATIC_CHECK_SIZEOF( type, size32, size64 ) \
|
||||
STATIC_ASSERT( sizeof( type ) == size64, #type " unexpected size" )
|
||||
#else
|
||||
#define STATIC_CHECK_SIZEOF( type, size32, size64 ) \
|
||||
STATIC_ASSERT( sizeof( type ) == size32, #type " unexpected size" )
|
||||
#endif
|
||||
|
||||
#if !defined( __cplusplus ) && __STDC_VERSION__ >= 199101L // not C++ and C99 or newer
|
||||
#define XASH_RESTRICT restrict
|
||||
#elif _MSC_VER || __GNUC__ || __clang__ // compiler-specific extensions
|
||||
|
||||
+10
-10
@@ -74,7 +74,7 @@ typedef struct
|
||||
float size;
|
||||
} daliashdr_t;
|
||||
|
||||
STATIC_ASSERT( sizeof( daliashdr_t ) == 84, "invalid daliashdr_t size" );
|
||||
STATIC_CHECK_SIZEOF( daliashdr_t, 84, 84 );
|
||||
|
||||
typedef struct
|
||||
{
|
||||
@@ -83,7 +83,7 @@ typedef struct
|
||||
int32_t t;
|
||||
} stvert_t;
|
||||
|
||||
STATIC_ASSERT( sizeof( stvert_t ) == 12, "invalid stvert_t size" );
|
||||
STATIC_CHECK_SIZEOF( stvert_t, 12, 12 );
|
||||
|
||||
typedef struct dtriangle_s
|
||||
{
|
||||
@@ -91,7 +91,7 @@ typedef struct dtriangle_s
|
||||
int32_t vertindex[3];
|
||||
} dtriangle_t;
|
||||
|
||||
STATIC_ASSERT( sizeof( dtriangle_t ) == 16, "invalid dtriangle_t size" );
|
||||
STATIC_CHECK_SIZEOF( dtriangle_t, 16, 16 );
|
||||
|
||||
#define DT_FACES_FRONT 0x0010
|
||||
#define ALIAS_ONSEAM 0x0020
|
||||
@@ -103,7 +103,7 @@ typedef struct
|
||||
char name[16]; // frame name from grabbing
|
||||
} daliasframe_t;
|
||||
|
||||
STATIC_ASSERT( sizeof( daliasframe_t ) == 24, "invalid daliasframe_t size" );
|
||||
STATIC_CHECK_SIZEOF( daliasframe_t, 24, 24 );
|
||||
|
||||
typedef struct
|
||||
{
|
||||
@@ -112,41 +112,41 @@ typedef struct
|
||||
trivertex_t bboxmax; // lightnormal isn't used
|
||||
} daliasgroup_t;
|
||||
|
||||
STATIC_ASSERT( sizeof( daliasgroup_t ) == 12, "invalid daliasgrou_t size" );
|
||||
STATIC_CHECK_SIZEOF( daliasgroup_t, 12, 12 );
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int32_t numskins;
|
||||
} daliasskingroup_t;
|
||||
|
||||
STATIC_ASSERT( sizeof( daliasskingroup_t ) == 4, "invalid daliasskingroup_t size" );
|
||||
STATIC_CHECK_SIZEOF( daliasskingroup_t, 4, 4 );
|
||||
|
||||
typedef struct
|
||||
{
|
||||
float interval;
|
||||
} daliasinterval_t;
|
||||
|
||||
STATIC_ASSERT( sizeof( daliasinterval_t ) == 4, "invalid daliasinterval_t size" );
|
||||
STATIC_CHECK_SIZEOF( daliasinterval_t, 4, 4 );
|
||||
|
||||
typedef struct
|
||||
{
|
||||
float interval;
|
||||
} daliasskininterval_t;
|
||||
|
||||
STATIC_ASSERT( sizeof( daliasskininterval_t ) == 4, "invalid daliasskininterval_t size" );
|
||||
STATIC_CHECK_SIZEOF( daliasskininterval_t, 4, 4 );
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint32_t type; // was aliasframetype_t
|
||||
} daliasframetype_t;
|
||||
|
||||
STATIC_ASSERT( sizeof( daliasframetype_t ) == 4, "invalid daliasframetype_t size" );
|
||||
STATIC_CHECK_SIZEOF( daliasframetype_t, 4, 4 );
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint32_t type; // was aliasskintype_t
|
||||
} daliasskintype_t;
|
||||
|
||||
STATIC_ASSERT( sizeof( daliasskintype_t ) == 4, "invalid daliasskintype_t size" );
|
||||
STATIC_CHECK_SIZEOF( daliasskintype_t, 4, 4 );
|
||||
|
||||
#endif//ALIAS_H
|
||||
|
||||
@@ -274,6 +274,13 @@ void CL_GenericShot_f( void )
|
||||
string checkname;
|
||||
int i;
|
||||
|
||||
// allow overriding screenshot by users request
|
||||
if( Cmd_Argc() > 1 )
|
||||
{
|
||||
Q_strncpy( cls.shotname, Cmd_Argv( 1 ), sizeof( cls.shotname ));
|
||||
break;
|
||||
}
|
||||
|
||||
if( type == scrshot_snapshot )
|
||||
{
|
||||
fmt = "../%s_%04d.png";
|
||||
|
||||
+142
-43
@@ -40,6 +40,8 @@ GNU General Public License for more details.
|
||||
#define IDEMOHEADER (('M'<<24)+('E'<<16)+('D'<<8)+'I') // little-endian "IDEM"
|
||||
#define DEMO_PROTOCOL 3
|
||||
|
||||
#define PROTOCOL_GOLDSRC_VERSION_DEMO (PROTOCOL_GOLDSRC_VERSION | (BIT( 7 ))) // should be 48, only to differentiate it from PROTOCOL_LEGACY_VERSION
|
||||
|
||||
const char *demo_cmd[dem_lastcmd+1] =
|
||||
{
|
||||
"dem_unknown",
|
||||
@@ -79,7 +81,7 @@ typedef struct
|
||||
typedef struct
|
||||
{
|
||||
demoentry_t *entries; // track entry info
|
||||
int numentries; // number of tracks
|
||||
int32_t numentries; // number of tracks
|
||||
} demodirectory_t;
|
||||
|
||||
// add angles
|
||||
@@ -120,7 +122,7 @@ static int CL_GetDemoNetProtocol( connprotocol_t proto )
|
||||
case PROTO_QUAKE:
|
||||
return PROTOCOL_VERSION_QUAKE;
|
||||
case PROTO_GOLDSRC:
|
||||
return PROTOCOL_GOLDSRC_VERSION;
|
||||
return PROTOCOL_GOLDSRC_VERSION_DEMO;
|
||||
}
|
||||
|
||||
return PROTOCOL_VERSION;
|
||||
@@ -136,7 +138,7 @@ static connprotocol_t CL_GetProtocolFromDemo( int net_protocol )
|
||||
return PROTO_LEGACY;
|
||||
case PROTOCOL_VERSION_QUAKE:
|
||||
return PROTO_QUAKE;
|
||||
case PROTOCOL_GOLDSRC_VERSION:
|
||||
case PROTOCOL_GOLDSRC_VERSION_DEMO:
|
||||
return PROTO_GOLDSRC;
|
||||
}
|
||||
|
||||
@@ -327,10 +329,6 @@ void CL_WriteDemoMessage( qboolean startup, int start, sizebuf_t *msg )
|
||||
|
||||
if( !file ) return;
|
||||
|
||||
// past the start but not recording a demo.
|
||||
if( !startup && !cls.demorecording )
|
||||
return;
|
||||
|
||||
swlen = MSG_GetNumBytesWritten( msg ) - start;
|
||||
if( swlen <= 0 ) return;
|
||||
|
||||
@@ -710,7 +708,7 @@ static void CL_DemoStartPlayback( int mode )
|
||||
|
||||
demo.starttime = CL_GetDemoPlaybackClock(); // for determining whether to read another message
|
||||
|
||||
Netchan_Setup( NS_CLIENT, &cls.netchan, net_from, Cvar_VariableInteger( "net_qport" ), NULL, CL_GetFragmentSize );
|
||||
Netchan_Setup( NS_CLIENT, &cls.netchan, net_from, Cvar_VariableInteger( "net_qport" ), NULL, CL_GetFragmentSize, 0 );
|
||||
|
||||
memset( demo.cmds, 0, sizeof( demo.cmds ));
|
||||
demo.angle_position = 1;
|
||||
@@ -1150,6 +1148,7 @@ show stats
|
||||
*/
|
||||
static void CL_FinishTimeDemo( void )
|
||||
{
|
||||
qboolean temp = host.allow_console;
|
||||
int frames;
|
||||
double time;
|
||||
|
||||
@@ -1160,7 +1159,9 @@ static void CL_FinishTimeDemo( void )
|
||||
time = host.realtime - cls.td_starttime;
|
||||
if( !time ) time = 1.0;
|
||||
|
||||
host.allow_console = true;
|
||||
Con_Printf( "timedemo result: %i frames %5.3f seconds %5.3f fps\n", frames, time, frames / time );
|
||||
host.allow_console = temp;
|
||||
|
||||
if( Sys_CheckParm( "-timedemo" ))
|
||||
CL_Quit_f();
|
||||
@@ -1449,6 +1450,51 @@ void CL_Record_f( void )
|
||||
CL_WriteDemoHeader( demopath );
|
||||
}
|
||||
|
||||
static qboolean CL_ParseDemoHeader( const char *callee, const char *filename, file_t *f, demoheader_t *hdr, int32_t *numentries )
|
||||
{
|
||||
if( FS_Read( f, hdr, sizeof( *hdr )) != sizeof( *hdr ) || hdr->id != IDEMOHEADER )
|
||||
{
|
||||
Con_Printf( S_ERROR "%s: %s is not in supported format or not a demo file\n", callee, filename );
|
||||
return false;
|
||||
}
|
||||
|
||||
// force null terminate strings
|
||||
hdr->mapname[sizeof( hdr->mapname ) - 1] = 0;
|
||||
hdr->comment[sizeof( hdr->comment ) - 1] = 0;
|
||||
hdr->gamedir[sizeof( hdr->gamedir ) - 1] = 0;
|
||||
|
||||
if( hdr->dem_protocol != DEMO_PROTOCOL )
|
||||
{
|
||||
Con_Printf( S_ERROR "%s: demo protocol outdated (%i should be %i)\n",
|
||||
callee, hdr->net_protocol, DEMO_PROTOCOL );
|
||||
return false;
|
||||
}
|
||||
|
||||
if( hdr->net_protocol != PROTOCOL_VERSION && hdr->net_protocol != PROTOCOL_LEGACY_VERSION )
|
||||
{
|
||||
Con_Printf( S_ERROR "%s: net protocol outdated (%i should be %i or %i)\n",
|
||||
callee, hdr->net_protocol, PROTOCOL_VERSION, PROTOCOL_LEGACY_VERSION );
|
||||
return false;
|
||||
}
|
||||
|
||||
if( FS_Seek( f, hdr->directory_offset, SEEK_SET ) < 0
|
||||
|| FS_Read( f, numentries, sizeof( *numentries )) != sizeof( *numentries ))
|
||||
{
|
||||
Con_Printf( S_ERROR "%s: can't find directory offset in %s, demo file corrupted\n",
|
||||
callee, filename );
|
||||
return false;
|
||||
}
|
||||
|
||||
if(( *numentries < 1 ) || ( *numentries > 1024 ))
|
||||
{
|
||||
Con_Printf( S_ERROR "%s: demo have bogus # of directory entries: %i\n",
|
||||
callee, *numentries );
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
====================
|
||||
CL_PlayDemo_f
|
||||
@@ -1469,9 +1515,7 @@ void CL_PlayDemo_f( void )
|
||||
}
|
||||
|
||||
if( cls.demoplayback )
|
||||
{
|
||||
CL_StopPlayback();
|
||||
}
|
||||
|
||||
if( cls.demorecording )
|
||||
{
|
||||
@@ -1520,53 +1564,33 @@ void CL_PlayDemo_f( void )
|
||||
}
|
||||
|
||||
if( neg ) cls.forcetrack = -cls.forcetrack;
|
||||
cls.legacymode = PROTO_QUAKE;
|
||||
CL_DemoStartPlayback( DEMO_QUAKE1 );
|
||||
cls.legacymode = PROTO_QUAKE;
|
||||
return; // quake demo is started
|
||||
}
|
||||
|
||||
// read in the demo header
|
||||
FS_Read( cls.demofile, &demo.header, sizeof( demoheader_t ));
|
||||
|
||||
if( demo.header.id != IDEMOHEADER )
|
||||
if( !CL_ParseDemoHeader( Cmd_Argv( 0 ), filename, cls.demofile, &demo.header, &demo.directory.numentries ))
|
||||
{
|
||||
Con_Printf( S_ERROR "%s is not a demo file\n", demoname );
|
||||
CL_DemoAborted();
|
||||
return;
|
||||
}
|
||||
|
||||
if( demo.header.dem_protocol != DEMO_PROTOCOL )
|
||||
{
|
||||
Con_Printf( S_ERROR "playdemo: demo protocol outdated (%i should be %i)\n", demo.header.dem_protocol, DEMO_PROTOCOL );
|
||||
CL_DemoAborted();
|
||||
return;
|
||||
}
|
||||
|
||||
if( demo.header.net_protocol != PROTOCOL_VERSION &&
|
||||
demo.header.net_protocol != PROTOCOL_LEGACY_VERSION )
|
||||
{
|
||||
Con_Printf( S_ERROR "playdemo: net protocol outdated (%i should be %i)\n", demo.header.net_protocol, PROTOCOL_VERSION );
|
||||
CL_DemoAborted();
|
||||
return;
|
||||
}
|
||||
|
||||
// now read in the directory structure.
|
||||
FS_Seek( cls.demofile, demo.header.directory_offset, SEEK_SET );
|
||||
FS_Read( cls.demofile, &demo.directory.numentries, sizeof( int ));
|
||||
|
||||
if( demo.directory.numentries < 1 || demo.directory.numentries > 1024 )
|
||||
{
|
||||
Con_Printf( S_ERROR "demo had bogus # of directory entries: %i\n", demo.directory.numentries );
|
||||
CL_DemoAborted();
|
||||
return;
|
||||
}
|
||||
|
||||
// allocate demo entries
|
||||
demo.directory.entries = Mem_Malloc( cls.mempool, sizeof( demoentry_t ) * demo.directory.numentries );
|
||||
demo.directory.entries = Mem_Malloc( cls.mempool, sizeof( *demo.directory.entries ) * demo.directory.numentries );
|
||||
|
||||
for( i = 0; i < demo.directory.numentries; i++ )
|
||||
{
|
||||
FS_Read( cls.demofile, &demo.directory.entries[i], sizeof( demoentry_t ));
|
||||
demoentry_t *entry = &demo.directory.entries[i];
|
||||
|
||||
if( FS_Read( cls.demofile, entry, sizeof( *entry )) != sizeof( *entry ))
|
||||
{
|
||||
Con_Printf( S_ERROR "%s: demo entry %i of %s corrupted", Cmd_Argv( 0 ), i, filename );
|
||||
CL_DemoAborted();
|
||||
return;
|
||||
}
|
||||
|
||||
entry->description[sizeof( entry->description ) - 1] = 0;
|
||||
}
|
||||
|
||||
demo.entryIndex = 0;
|
||||
@@ -1680,3 +1704,78 @@ void CL_Stop_f( void )
|
||||
S_StopBackgroundTrack();
|
||||
}
|
||||
}
|
||||
|
||||
void CL_ListDemo_f( void )
|
||||
{
|
||||
demoheader_t hdr;
|
||||
int32_t num_entries;
|
||||
file_t *f;
|
||||
char filename[MAX_QPATH];
|
||||
char demoname[MAX_QPATH];
|
||||
int i;
|
||||
|
||||
if( Cmd_Argc() < 2 )
|
||||
{
|
||||
Con_Printf( S_USAGE "%s <demoname>\n", Cmd_Argv( 0 ));
|
||||
return;
|
||||
}
|
||||
|
||||
Q_strncpy( demoname, Cmd_Argv( 1 ), sizeof( demoname ));
|
||||
COM_StripExtension( demoname );
|
||||
Q_snprintf( filename, sizeof( filename ), "%s.dem", demoname );
|
||||
|
||||
f = FS_Open( filename, "rb", true );
|
||||
if( !f )
|
||||
{
|
||||
Con_Printf( S_ERROR "couldn't open %s\n", filename );
|
||||
return;
|
||||
}
|
||||
|
||||
if( !CL_ParseDemoHeader( Cmd_Argv( 0 ), filename, f, &hdr, &num_entries ))
|
||||
{
|
||||
FS_Close( f );
|
||||
return;
|
||||
}
|
||||
|
||||
Con_Printf( "Demo contents for %s:\n"
|
||||
"\tProtocol: %i net/%i demo\n"
|
||||
"\tFPS: %g\n"
|
||||
"\tMap: %s\n"
|
||||
"\tComment: %s\n"
|
||||
"\tGame: %s\n",
|
||||
filename, hdr.net_protocol, hdr.dem_protocol, hdr.host_fps, hdr.mapname,
|
||||
hdr.comment, hdr.gamedir );
|
||||
|
||||
for( i = 0; i < num_entries; i++ )
|
||||
{
|
||||
demoentry_t entry;
|
||||
|
||||
Con_Printf( "Demo entry #%i:\n", i );
|
||||
|
||||
if( FS_Read( f, &entry, sizeof( entry )) != sizeof( entry ))
|
||||
{
|
||||
Con_Printf( S_ERROR "can't read demo entry\n" );
|
||||
FS_Close( f );
|
||||
return;
|
||||
}
|
||||
|
||||
entry.description[sizeof( entry.description ) - 1] = 0;
|
||||
|
||||
if( entry.entrytype == DEMO_STARTUP )
|
||||
{
|
||||
// startup entries don't have anything useful
|
||||
Con_Printf( "\tEntry type: " S_YELLOW "startup" S_DEFAULT "\n" );
|
||||
}
|
||||
else
|
||||
{
|
||||
Con_Printf( "\tEntry type: " S_GREEN "normal" S_DEFAULT " (%i)\n"
|
||||
"\tEntry playback time/frames: %.2f seconds/%i frames\n"
|
||||
"\tEntry flags: 0x%x\n"
|
||||
"\tEntry description: %s\n",
|
||||
entry.entrytype, entry.playback_time, entry.playback_frames,
|
||||
entry.flags, entry.description );
|
||||
}
|
||||
}
|
||||
|
||||
FS_Close( f );
|
||||
}
|
||||
|
||||
+60
-28
@@ -28,10 +28,51 @@ GNU General Public License for more details.
|
||||
===============================================================================
|
||||
*/
|
||||
|
||||
#define NUM_EFRAGS_ALLOC 64 // alloc 64 efrags (1-2kb each alloc)
|
||||
|
||||
static efrag_t **lastlink;
|
||||
static mnode_t *r_pefragtopnode;
|
||||
static vec3_t r_emins, r_emaxs;
|
||||
static cl_entity_t *r_addent;
|
||||
static int cl_efrags_num;
|
||||
static efrag_t *cl_efrags;
|
||||
|
||||
static efrag_t *CL_AllocEfrags( int num )
|
||||
{
|
||||
int i;
|
||||
efrag_t *efrags;
|
||||
|
||||
if( !cl.worldmodel )
|
||||
{
|
||||
Host_Error( "%s: called with NULL world\n", __func__ );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if( num == 0 )
|
||||
return NULL;
|
||||
|
||||
// set world to be the owner, so it will get automatically cleaned up
|
||||
efrags = Mem_Calloc( cl.worldmodel->mempool, sizeof( *efrags ) * num );
|
||||
|
||||
// initialize linked list
|
||||
for( i = 0; i < num - 1; i++ )
|
||||
efrags[i].entnext = &efrags[i + 1];
|
||||
|
||||
cl_efrags_num += num;
|
||||
|
||||
return efrags;
|
||||
}
|
||||
|
||||
/*
|
||||
==============
|
||||
CL_ClearEfrags
|
||||
==============
|
||||
*/
|
||||
void CL_ClearEfrags( void )
|
||||
{
|
||||
cl_efrags_num = 0;
|
||||
cl_efrags = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
===================
|
||||
@@ -56,14 +97,11 @@ static void R_SplitEntityOnNode( mnode_t *node )
|
||||
leaf = (mleaf_t *)node;
|
||||
|
||||
// grab an efrag off the free list
|
||||
ef = clgame.free_efrags;
|
||||
ef = cl_efrags;
|
||||
if( !ef )
|
||||
{
|
||||
Con_Printf( S_ERROR "too many efrags!\n" );
|
||||
return; // no free fragments...
|
||||
}
|
||||
ef = CL_AllocEfrags( NUM_EFRAGS_ALLOC );
|
||||
|
||||
clgame.free_efrags = ef->entnext;
|
||||
cl_efrags = ef->entnext;
|
||||
ef->entity = r_addent;
|
||||
|
||||
// add the entity link
|
||||
@@ -133,35 +171,29 @@ R_StoreEfrags
|
||||
*/
|
||||
void R_StoreEfrags( efrag_t **ppefrag, int framecount )
|
||||
{
|
||||
cl_entity_t *pent;
|
||||
model_t *clmodel;
|
||||
efrag_t *pefrag;
|
||||
efrag_t *pefrag;
|
||||
cl_entity_t *pent;
|
||||
model_t *clmodel;
|
||||
|
||||
while(( pefrag = *ppefrag ) != NULL )
|
||||
{
|
||||
pent = pefrag->entity;
|
||||
clmodel = pent->model;
|
||||
|
||||
switch( clmodel->type )
|
||||
{
|
||||
case mod_alias:
|
||||
case mod_brush:
|
||||
case mod_studio:
|
||||
case mod_sprite:
|
||||
if( pent->visframe != framecount )
|
||||
{
|
||||
if( CL_AddVisibleEntity( pent, ET_FRAGMENTED ))
|
||||
{
|
||||
// mark that we've recorded this entity for this frame
|
||||
pent->curstate.messagenum = cl.parsecount;
|
||||
pent->visframe = framecount;
|
||||
}
|
||||
}
|
||||
// how this could happen?
|
||||
if( unlikely( clmodel->type < mod_brush || clmodel->type > mod_studio ))
|
||||
continue;
|
||||
|
||||
ppefrag = &pefrag->leafnext;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
if( pent->visframe != framecount )
|
||||
{
|
||||
if( CL_AddVisibleEntity( pent, ET_FRAGMENTED ))
|
||||
{
|
||||
// mark that we've recorded this entity for this frame
|
||||
pent->curstate.messagenum = cl.parsecount;
|
||||
pent->visframe = framecount;
|
||||
}
|
||||
}
|
||||
|
||||
ppefrag = &pefrag->leafnext;
|
||||
}
|
||||
}
|
||||
|
||||
+19
-11
@@ -250,7 +250,7 @@ static particle_t *R_AllocTracer( const vec3_t org, const vec3_t vel, float life
|
||||
VectorCopy( vel, p->vel );
|
||||
p->die = cl.time + life;
|
||||
p->ramp = tracerlength.value;
|
||||
p->color = 4; // select custom color
|
||||
p->color = TRACER_COLORINDEX_DEFAULT; // select custom color
|
||||
p->packedColor = 255; // alpha
|
||||
|
||||
return p;
|
||||
@@ -636,12 +636,24 @@ and all particle trails (if this is a beamfollow)
|
||||
*/
|
||||
void GAME_EXPORT R_BeamKill( int deadEntity )
|
||||
{
|
||||
cl_entity_t *pDeadEntity;
|
||||
BEAM *beam;
|
||||
|
||||
pDeadEntity = R_BeamGetEntity( deadEntity );
|
||||
if( !pDeadEntity ) return;
|
||||
for( beam = cl_active_beams; beam; beam = beam->next )
|
||||
{
|
||||
if( FBitSet( beam->flags, FBEAM_STARTENTITY ) && beam->startEntity == deadEntity )
|
||||
{
|
||||
if( beam->type != TE_BEAMFOLLOW )
|
||||
beam->die = cl.time;
|
||||
|
||||
CL_KillDeadBeams( pDeadEntity );
|
||||
ClearBits( beam->flags, FBEAM_STARTENTITY );
|
||||
}
|
||||
|
||||
if( FBitSet( beam->flags, FBEAM_ENDENTITY ) && beam->endEntity == deadEntity )
|
||||
{
|
||||
beam->die = cl.time;
|
||||
ClearBits( beam->flags, FBEAM_ENDENTITY );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1094,9 +1106,7 @@ void GAME_EXPORT R_ParticleExplosion2( const vec3_t org, int colorStart, int col
|
||||
int colorMod = 0, packedColor;
|
||||
particle_t *p;
|
||||
|
||||
if( FBitSet( host.features, ENGINE_QUAKE_COMPATIBLE ))
|
||||
packedColor = 255; // use old code for blob particles
|
||||
else packedColor = 0;
|
||||
packedColor = Host_IsQuakeCompatible( ) ? 255 : 0; // use old code for blob particles
|
||||
|
||||
for( i = 0; i < 512; i++ )
|
||||
{
|
||||
@@ -1129,9 +1139,7 @@ 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;
|
||||
packedColor = Host_IsQuakeCompatible( ) ? 255 : 0; // use old code for blob particles
|
||||
|
||||
for( i = 0; i < 1024; i++ )
|
||||
{
|
||||
|
||||
@@ -380,7 +380,7 @@ CL_ParseReliableEvent
|
||||
|
||||
=============
|
||||
*/
|
||||
void CL_ParseReliableEvent( sizebuf_t *msg )
|
||||
void CL_ParseReliableEvent( sizebuf_t *msg, connprotocol_t proto )
|
||||
{
|
||||
int event_index;
|
||||
event_args_t nullargs, args;
|
||||
@@ -390,11 +390,19 @@ void CL_ParseReliableEvent( sizebuf_t *msg )
|
||||
|
||||
event_index = MSG_ReadUBitLong( msg, MAX_EVENT_BITS );
|
||||
|
||||
if( MSG_ReadOneBit( msg ))
|
||||
delay = (float)MSG_ReadWord( msg ) * (1.0f / 100.0f);
|
||||
|
||||
// reliable events not use delta-compression just null-compression
|
||||
MSG_ReadDeltaEvent( msg, &nullargs, &args );
|
||||
if( proto == PROTO_GOLDSRC )
|
||||
{
|
||||
Delta_ReadGSFields( msg, DT_EVENT_T, &nullargs, &args, 0.0f );
|
||||
if( MSG_ReadOneBit( msg ))
|
||||
delay = (float)MSG_ReadWord( msg ) * (1.0f / 100.0f);
|
||||
}
|
||||
else
|
||||
{
|
||||
if( MSG_ReadOneBit( msg ))
|
||||
delay = (float)MSG_ReadWord( msg ) * (1.0f / 100.0f);
|
||||
MSG_ReadDeltaEvent( msg, &nullargs, &args );
|
||||
}
|
||||
|
||||
if( args.entindex > 0 && args.entindex <= cl.maxclients )
|
||||
args.angles[PITCH] *= -3.0f;
|
||||
@@ -409,7 +417,7 @@ CL_ParseEvent
|
||||
|
||||
=============
|
||||
*/
|
||||
void CL_ParseEvent( sizebuf_t *msg )
|
||||
void CL_ParseEvent( sizebuf_t *msg, connprotocol_t proto )
|
||||
{
|
||||
int event_index;
|
||||
int i, num_events;
|
||||
@@ -417,24 +425,33 @@ void CL_ParseEvent( sizebuf_t *msg )
|
||||
event_args_t nullargs, args;
|
||||
entity_state_t *state;
|
||||
float delay;
|
||||
int entity_bits;
|
||||
|
||||
memset( &nullargs, 0, sizeof( nullargs ));
|
||||
memset( &args, 0, sizeof( args ));
|
||||
|
||||
num_events = MSG_ReadUBitLong( msg, 5 );
|
||||
|
||||
if( proto == PROTO_GOLDSRC )
|
||||
entity_bits = MAX_GOLDSRC_ENTITY_BITS;
|
||||
else if( proto == PROTO_LEGACY )
|
||||
entity_bits = MAX_LEGACY_ENTITY_BITS;
|
||||
else entity_bits = MAX_ENTITY_BITS;
|
||||
|
||||
// parse events queue
|
||||
for( i = 0 ; i < num_events; i++ )
|
||||
{
|
||||
event_index = MSG_ReadUBitLong( msg, MAX_EVENT_BITS );
|
||||
|
||||
if( MSG_ReadOneBit( msg ))
|
||||
packet_index = MSG_ReadUBitLong( msg, cls.legacymode ? MAX_LEGACY_ENTITY_BITS : MAX_ENTITY_BITS );
|
||||
packet_index = MSG_ReadUBitLong( msg, entity_bits );
|
||||
else packet_index = -1;
|
||||
|
||||
if( MSG_ReadOneBit( msg ))
|
||||
{
|
||||
MSG_ReadDeltaEvent( msg, &nullargs, &args );
|
||||
if( proto == PROTO_GOLDSRC )
|
||||
Delta_ReadGSFields( msg, DT_EVENT_T, &nullargs, &args, 0.0f );
|
||||
else MSG_ReadDeltaEvent( msg, &nullargs, &args );
|
||||
}
|
||||
|
||||
if( MSG_ReadOneBit( msg ))
|
||||
|
||||
+58
-84
@@ -95,8 +95,7 @@ static void CL_ResetPositions( cl_entity_t *ent )
|
||||
ent->current_position = 1;
|
||||
|
||||
memset( ent->ph, 0, sizeof( position_history_t ) * HISTORY_MAX );
|
||||
memcpy( &ent->ph[1], &store, sizeof( position_history_t ));
|
||||
memcpy( &ent->ph[0], &store, sizeof( position_history_t ));
|
||||
ent->ph[1] = ent->ph[0] = store;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -670,9 +669,9 @@ FRAME PARSING
|
||||
|
||||
=========================================================================
|
||||
*/
|
||||
static qboolean CL_ParseEntityNumFromPacket( sizebuf_t *msg, int *newnum )
|
||||
static qboolean CL_ParseEntityNumFromPacket( sizebuf_t *msg, int *newnum, connprotocol_t proto )
|
||||
{
|
||||
if( cls.legacymode )
|
||||
if( proto == PROTO_LEGACY )
|
||||
{
|
||||
*newnum = MSG_ReadWord( msg );
|
||||
if( *newnum == 0 )
|
||||
@@ -695,7 +694,7 @@ CL_FlushEntityPacket
|
||||
Read and ignore whole entity packet.
|
||||
=================
|
||||
*/
|
||||
static void CL_FlushEntityPacket( sizebuf_t *msg )
|
||||
static void CL_FlushEntityPacket( sizebuf_t *msg, connprotocol_t proto )
|
||||
{
|
||||
int newnum;
|
||||
entity_state_t from, to;
|
||||
@@ -708,7 +707,7 @@ static void CL_FlushEntityPacket( sizebuf_t *msg )
|
||||
// read it all, but ignore it
|
||||
while( 1 )
|
||||
{
|
||||
if( !CL_ParseEntityNumFromPacket( msg, &newnum ))
|
||||
if( !CL_ParseEntityNumFromPacket( msg, &newnum, proto ))
|
||||
break; // done
|
||||
|
||||
if( MSG_CheckOverflow( msg ))
|
||||
@@ -718,6 +717,47 @@ static void CL_FlushEntityPacket( sizebuf_t *msg )
|
||||
}
|
||||
}
|
||||
|
||||
qboolean CL_ValidateDeltaPacket( uint oldpacket, frame_t *oldframe )
|
||||
{
|
||||
int subtracted = ( cls.netchan.incoming_sequence - oldpacket ) & 0xFF;
|
||||
|
||||
if( subtracted == 0 )
|
||||
{
|
||||
Con_NPrintf( 2, "^3Warning:^1 update too old\n^7\n" );
|
||||
return false;
|
||||
}
|
||||
|
||||
if( subtracted >= CL_UPDATE_MASK )
|
||||
{
|
||||
// we can't use this, it is too old
|
||||
Con_NPrintf( 2, "^3Warning:^1 delta frame is too old^7\n" );
|
||||
return false;
|
||||
}
|
||||
|
||||
if(( cls.next_client_entities - oldframe->first_entity ) > ( cls.num_client_entities - NUM_PACKET_ENTITIES ))
|
||||
{
|
||||
Con_NPrintf( 2, "^3Warning:^1 delta frame is too old^7\n" );
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int CL_UpdateOldEntNum( int oldindex, frame_t *oldframe, entity_state_t **oldent )
|
||||
{
|
||||
if( !oldframe )
|
||||
{
|
||||
*oldent = NULL;
|
||||
return MAX_ENTNUMBER;
|
||||
}
|
||||
|
||||
if( oldindex >= oldframe->num_entities )
|
||||
return MAX_ENTNUMBER;
|
||||
|
||||
*oldent = &cls.packet_entities[(oldframe->first_entity + oldindex) % cls.num_client_entities];
|
||||
return (*oldent)->number;
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
CL_DeltaEntity
|
||||
@@ -752,7 +792,7 @@ static void CL_DeltaEntity( sizebuf_t *msg, frame_t *frame, int newnum, entity_s
|
||||
|
||||
if( has_update )
|
||||
alive = MSG_ReadDeltaEntity( msg, old, state, newnum, delta_type, cl.mtime[0] );
|
||||
else memcpy( state, old, sizeof( entity_state_t ));
|
||||
else *state = *old;
|
||||
|
||||
if( !alive )
|
||||
{
|
||||
@@ -788,7 +828,7 @@ An svc_packetentities has just been parsed, deal with the
|
||||
rest of the data stream.
|
||||
==================
|
||||
*/
|
||||
int CL_ParsePacketEntities( sizebuf_t *msg, qboolean delta )
|
||||
int CL_ParsePacketEntities( sizebuf_t *msg, qboolean delta, connprotocol_t proto )
|
||||
{
|
||||
frame_t *newframe, *oldframe;
|
||||
int oldindex, newnum, oldnum;
|
||||
@@ -804,7 +844,7 @@ int CL_ParsePacketEntities( sizebuf_t *msg, qboolean delta )
|
||||
CL_WriteDemoJumpTime();
|
||||
|
||||
// sentinel count. save it for debug checking
|
||||
if( cls.legacymode )
|
||||
if( proto == PROTO_LEGACY )
|
||||
count = MSG_ReadWord( msg );
|
||||
else count = MSG_ReadUBitLong( msg, MAX_VISIBLE_PACKET_BITS ) + 1;
|
||||
|
||||
@@ -818,32 +858,12 @@ int CL_ParsePacketEntities( sizebuf_t *msg, qboolean delta )
|
||||
|
||||
if( delta )
|
||||
{
|
||||
int subtracted;
|
||||
|
||||
oldpacket = MSG_ReadByte( msg );
|
||||
subtracted = ( cls.netchan.incoming_sequence - oldpacket ) & 0xFF;
|
||||
|
||||
if( subtracted == 0 )
|
||||
{
|
||||
Con_NPrintf( 2, "^3Warning:^1 update too old\n^7\n" );
|
||||
CL_FlushEntityPacket( msg );
|
||||
return playerbytes;
|
||||
}
|
||||
|
||||
if( subtracted >= CL_UPDATE_MASK )
|
||||
{
|
||||
// we can't use this, it is too old
|
||||
Con_NPrintf( 2, "^3Warning:^1 delta frame is too old^7\n" );
|
||||
CL_FlushEntityPacket( msg );
|
||||
return playerbytes;
|
||||
}
|
||||
|
||||
uint oldpacket = MSG_ReadByte( msg );
|
||||
oldframe = &cl.frames[oldpacket & CL_UPDATE_MASK];
|
||||
|
||||
if(( cls.next_client_entities - oldframe->first_entity ) > ( cls.num_client_entities - NUM_PACKET_ENTITIES ))
|
||||
if( !CL_ValidateDeltaPacket( oldpacket, oldframe ))
|
||||
{
|
||||
Con_NPrintf( 2, "^3Warning:^1 delta frame is too old^7\n" );
|
||||
CL_FlushEntityPacket( msg );
|
||||
CL_FlushEntityPacket( msg, proto );
|
||||
return playerbytes;
|
||||
}
|
||||
}
|
||||
@@ -861,27 +881,11 @@ int CL_ParsePacketEntities( sizebuf_t *msg, qboolean delta )
|
||||
|
||||
oldent = NULL;
|
||||
oldindex = 0;
|
||||
|
||||
if( !oldframe )
|
||||
{
|
||||
oldnum = MAX_ENTNUMBER;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( oldindex >= oldframe->num_entities )
|
||||
{
|
||||
oldnum = MAX_ENTNUMBER;
|
||||
}
|
||||
else
|
||||
{
|
||||
oldent = &cls.packet_entities[(oldframe->first_entity+oldindex) % cls.num_client_entities];
|
||||
oldnum = oldent->number;
|
||||
}
|
||||
}
|
||||
oldnum = CL_UpdateOldEntNum( oldindex, oldframe, &oldent );
|
||||
|
||||
while( 1 )
|
||||
{
|
||||
if( !CL_ParseEntityNumFromPacket( msg, &newnum ))
|
||||
if( !CL_ParseEntityNumFromPacket( msg, &newnum, proto ))
|
||||
break; // done
|
||||
|
||||
if( MSG_CheckOverflow( msg ))
|
||||
@@ -893,17 +897,7 @@ int CL_ParsePacketEntities( sizebuf_t *msg, qboolean delta )
|
||||
{
|
||||
// one or more entities from the old packet are unchanged
|
||||
CL_DeltaEntity( msg, newframe, oldnum, oldent, false );
|
||||
oldindex++;
|
||||
|
||||
if( oldindex >= oldframe->num_entities )
|
||||
{
|
||||
oldnum = MAX_ENTNUMBER;
|
||||
}
|
||||
else
|
||||
{
|
||||
oldent = &cls.packet_entities[(oldframe->first_entity+oldindex) % cls.num_client_entities];
|
||||
oldnum = oldent->number;
|
||||
}
|
||||
oldnum = CL_UpdateOldEntNum( ++oldindex, oldframe, &oldent );
|
||||
}
|
||||
|
||||
if( oldnum == newnum )
|
||||
@@ -912,17 +906,7 @@ int CL_ParsePacketEntities( sizebuf_t *msg, qboolean delta )
|
||||
bufStart = MSG_GetNumBytesRead( msg );
|
||||
CL_DeltaEntity( msg, newframe, newnum, oldent, true );
|
||||
if( player ) playerbytes += MSG_GetNumBytesRead( msg ) - bufStart;
|
||||
oldindex++;
|
||||
|
||||
if( oldindex >= oldframe->num_entities )
|
||||
{
|
||||
oldnum = MAX_ENTNUMBER;
|
||||
}
|
||||
else
|
||||
{
|
||||
oldent = &cls.packet_entities[(oldframe->first_entity+oldindex) % cls.num_client_entities];
|
||||
oldnum = oldent->number;
|
||||
}
|
||||
oldnum = CL_UpdateOldEntNum( ++oldindex, oldframe, &oldent );
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -941,17 +925,7 @@ int CL_ParsePacketEntities( sizebuf_t *msg, qboolean delta )
|
||||
{
|
||||
// one or more entities from the old packet are unchanged
|
||||
CL_DeltaEntity( msg, newframe, oldnum, oldent, false );
|
||||
oldindex++;
|
||||
|
||||
if( oldindex >= oldframe->num_entities )
|
||||
{
|
||||
oldnum = MAX_ENTNUMBER;
|
||||
}
|
||||
else
|
||||
{
|
||||
oldent = &cls.packet_entities[(oldframe->first_entity+oldindex) % cls.num_client_entities];
|
||||
oldnum = oldent->number;
|
||||
}
|
||||
oldnum = CL_UpdateOldEntNum( ++oldindex, oldframe, &oldent );
|
||||
}
|
||||
|
||||
if( newframe->num_entities != count && newframe->num_entities != 0 )
|
||||
@@ -973,7 +947,7 @@ int CL_ParsePacketEntities( sizebuf_t *msg, qboolean delta )
|
||||
cls.signon = SIGNONS;
|
||||
|
||||
// Clear loading plaque.
|
||||
CL_SignonReply ();
|
||||
CL_SignonReply( proto );
|
||||
}
|
||||
|
||||
return playerbytes;
|
||||
|
||||
+48
-28
@@ -252,18 +252,18 @@ static int CL_AdjustXPos( float x, int width, int totalWidth )
|
||||
|
||||
if( x == -1 )
|
||||
{
|
||||
xPos = ( refState.width - width ) * 0.5f;
|
||||
xPos = ( clgame.scrInfo.iWidth - width ) * 0.5f;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( x < 0 )
|
||||
xPos = (1.0f + x) * refState.width - totalWidth; // Alight right
|
||||
xPos = (1.0f + x) * clgame.scrInfo.iWidth - totalWidth; // Alight right
|
||||
else // align left
|
||||
xPos = x * refState.width;
|
||||
xPos = x * clgame.scrInfo.iWidth;
|
||||
}
|
||||
|
||||
if( xPos + width > refState.width )
|
||||
xPos = refState.width - width;
|
||||
if( xPos + width > clgame.scrInfo.iWidth )
|
||||
xPos = clgame.scrInfo.iWidth - width;
|
||||
else if( xPos < 0 )
|
||||
xPos = 0;
|
||||
|
||||
@@ -283,19 +283,19 @@ static int CL_AdjustYPos( float y, int height )
|
||||
|
||||
if( y == -1 ) // centered?
|
||||
{
|
||||
yPos = ( refState.height - height ) * 0.5f;
|
||||
yPos = ( clgame.scrInfo.iHeight - height ) * 0.5f;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Alight bottom?
|
||||
if( y < 0 )
|
||||
yPos = (1.0f + y) * refState.height - height; // Alight bottom
|
||||
yPos = (1.0f + y) * clgame.scrInfo.iHeight - height; // Alight bottom
|
||||
else // align top
|
||||
yPos = y * refState.height;
|
||||
yPos = y * clgame.scrInfo.iHeight;
|
||||
}
|
||||
|
||||
if( yPos + height > refState.height )
|
||||
yPos = refState.height - height;
|
||||
if( yPos + height > clgame.scrInfo.iHeight )
|
||||
yPos = clgame.scrInfo.iHeight - height;
|
||||
else if( yPos < 0 )
|
||||
yPos = 0;
|
||||
|
||||
@@ -560,7 +560,19 @@ static void CL_DrawScreenFade( void )
|
||||
if( !alpha )
|
||||
return;
|
||||
|
||||
if( FBitSet( sf->fadeFlags, FFADE_MODULATE ))
|
||||
if( !FBitSet( sf->fadeFlags, FFADE_MODULATE ))
|
||||
{
|
||||
ref.dllFuncs.GL_SetRenderMode( kRenderTransTexture );
|
||||
ref.dllFuncs.Color4ub( sf->fader, sf->fadeg, sf->fadeb, alpha );
|
||||
}
|
||||
else if( Host_IsQuakeCompatible( ))
|
||||
{
|
||||
// Quake Wrapper and Quake Remake use FFADE_MODULATE for item pickups
|
||||
// so hack the check here
|
||||
ref.dllFuncs.GL_SetRenderMode( kRenderTransAdd );
|
||||
ref.dllFuncs.Color4ub( sf->fader, sf->fadeg, sf->fadeb, alpha );
|
||||
}
|
||||
else
|
||||
{
|
||||
ref.dllFuncs.GL_SetRenderMode( kRenderScreenFadeModulate );
|
||||
|
||||
@@ -570,11 +582,6 @@ static void CL_DrawScreenFade( void )
|
||||
(uint16_t)( sf->fadeb * alpha + ( 255 - alpha ) * 255 ) >> 8,
|
||||
255 );
|
||||
}
|
||||
else
|
||||
{
|
||||
ref.dllFuncs.GL_SetRenderMode( kRenderTransTexture );
|
||||
ref.dllFuncs.Color4ub( sf->fader, sf->fadeg, sf->fadeb, alpha );
|
||||
}
|
||||
|
||||
ref.dllFuncs.R_DrawStretchPic( 0, 0, refState.width, refState.height, 0, 0, 1, 1,
|
||||
R_GetBuiltinTexture( REF_WHITE_TEXTURE ));
|
||||
@@ -1182,7 +1189,7 @@ static qboolean CL_LoadHudSprite( const char *szSpriteName, model_t *m_pSprite,
|
||||
if( type == SPR_CLIENT || type == SPR_HUDSPRITE )
|
||||
SetBits( m_pSprite->flags, MODEL_CLIENT );
|
||||
|
||||
m_pSprite->numtexinfo = texFlags; // store texFlags into numtexinfo
|
||||
m_pSprite->numtexinfo = texFlags; // store texFlags for renderer into numtexinfo
|
||||
|
||||
if( !FS_FileExists( szSpriteName, false ) )
|
||||
{
|
||||
@@ -1209,7 +1216,7 @@ static qboolean CL_LoadHudSprite( const char *szSpriteName, model_t *m_pSprite,
|
||||
ref.dllFuncs.Mod_LoadMapSprite( m_pSprite, buf, size, &loaded );
|
||||
else
|
||||
{
|
||||
Mod_LoadSpriteModel( m_pSprite, buf, &loaded, texFlags );
|
||||
Mod_LoadSpriteModel( m_pSprite, buf, &loaded );
|
||||
ref.dllFuncs.Mod_ProcessRenderData( m_pSprite, true, buf );
|
||||
}
|
||||
|
||||
@@ -2428,8 +2435,8 @@ static void GAME_EXPORT pfnLocalPlayerBounds( int hull, float *mins, float *maxs
|
||||
{
|
||||
if( hull >= 0 && hull < 4 )
|
||||
{
|
||||
if( mins ) VectorCopy( clgame.pmove->player_mins[hull], mins );
|
||||
if( maxs ) VectorCopy( clgame.pmove->player_maxs[hull], maxs );
|
||||
if( mins ) VectorCopy( host.player_mins[hull], mins );
|
||||
if( maxs ) VectorCopy( host.player_maxs[hull], maxs );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2497,9 +2504,17 @@ CL_PushTraceBounds
|
||||
*/
|
||||
static void GAME_EXPORT CL_PushTraceBounds( int hullnum, const float *mins, const float *maxs )
|
||||
{
|
||||
if( !host.trace_bounds_pushed )
|
||||
{
|
||||
memcpy( host.player_mins_backup, host.player_mins, sizeof( host.player_mins_backup ));
|
||||
memcpy( host.player_maxs_backup, host.player_maxs, sizeof( host.player_maxs_backup ));
|
||||
|
||||
host.trace_bounds_pushed = true;
|
||||
}
|
||||
|
||||
hullnum = bound( 0, hullnum, 3 );
|
||||
VectorCopy( mins, clgame.pmove->player_mins[hullnum] );
|
||||
VectorCopy( maxs, clgame.pmove->player_maxs[hullnum] );
|
||||
VectorCopy( mins, host.player_mins[hullnum] );
|
||||
VectorCopy( maxs, host.player_maxs[hullnum] );
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2510,8 +2525,15 @@ CL_PopTraceBounds
|
||||
*/
|
||||
static void GAME_EXPORT CL_PopTraceBounds( void )
|
||||
{
|
||||
memcpy( clgame.pmove->player_mins, host.player_mins, sizeof( host.player_mins ));
|
||||
memcpy( clgame.pmove->player_maxs, host.player_maxs, sizeof( host.player_maxs ));
|
||||
if( !host.trace_bounds_pushed )
|
||||
{
|
||||
Con_Reportf( S_ERROR "%s called without push!\n", __func__ );
|
||||
return;
|
||||
}
|
||||
|
||||
host.trace_bounds_pushed = false;
|
||||
memcpy( host.player_mins, host.player_mins_backup, sizeof( host.player_mins ));
|
||||
memcpy( host.player_maxs, host.player_maxs_backup, sizeof( host.player_maxs ));
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -3283,7 +3305,7 @@ Heavy legacy of Quake...
|
||||
*/
|
||||
void TriColor4fRendermode( float r, float g, float b, float a, int rendermode )
|
||||
{
|
||||
if( clgame.ds.renderMode == kRenderTransAlpha )
|
||||
if( rendermode == kRenderTransAlpha )
|
||||
{
|
||||
clgame.ds.triRGBA[3] = a / 255.0f;
|
||||
ref.dllFuncs.Color4f( r, g, b, a );
|
||||
@@ -3415,7 +3437,6 @@ NetAPI_SendRequest
|
||||
static void GAME_EXPORT NetAPI_SendRequest( int context, int request, int flags, double timeout, netadr_t *remote_address, net_api_response_func_t response )
|
||||
{
|
||||
net_request_t *nr = NULL;
|
||||
string req;
|
||||
int i;
|
||||
|
||||
if( !response )
|
||||
@@ -3467,8 +3488,7 @@ static void GAME_EXPORT NetAPI_SendRequest( int context, int request, int flags,
|
||||
nr->flags = flags;
|
||||
|
||||
// local servers request
|
||||
Q_snprintf( req, sizeof( req ), "netinfo %i %i %i", FBitSet( flags, FNETAPI_LEGACY_PROTOCOL ) ? PROTOCOL_LEGACY_VERSION : PROTOCOL_VERSION, context, request );
|
||||
Netchan_OutOfBandPrint( NS_CLIENT, nr->resp.remote_address, "%s", req );
|
||||
Netchan_OutOfBandPrint( NS_CLIENT, nr->resp.remote_address, "netinfo %i %i %i", FBitSet( flags, FNETAPI_LEGACY_PROTOCOL ) ? PROTOCOL_LEGACY_VERSION : PROTOCOL_VERSION, context, request );
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
+93
-18
@@ -25,6 +25,14 @@ static void UI_UpdateUserinfo( void );
|
||||
|
||||
gameui_static_t gameui;
|
||||
|
||||
static void UI_ToggleAllowConsole_f( void )
|
||||
{
|
||||
host.allow_console = host.allow_console_init = true;
|
||||
|
||||
if( gameui.globals )
|
||||
gameui.globals->developer = true;
|
||||
}
|
||||
|
||||
void UI_UpdateMenu( float realtime )
|
||||
{
|
||||
if( !gameui.hInstance ) return;
|
||||
@@ -399,17 +407,21 @@ void Host_Credits( void )
|
||||
gameui.dllFuncs.pfnFinalCredits();
|
||||
}
|
||||
|
||||
static void UI_ConvertGameInfo( GAMEINFO *out, gameinfo_t *in )
|
||||
static void UI_ConvertGameInfo( gameinfo2_t *out, const gameinfo_t *in )
|
||||
{
|
||||
out->gi_version = GAMEINFO_VERSION;
|
||||
|
||||
Q_strncpy( out->gamefolder, in->gamefolder, sizeof( out->gamefolder ));
|
||||
Q_strncpy( out->startmap, in->startmap, sizeof( out->startmap ));
|
||||
Q_strncpy( out->trainmap, in->trainmap, sizeof( out->trainmap ));
|
||||
Q_strncpy( out->demomap, in->demomap, sizeof( out->demomap ));
|
||||
Q_strncpy( out->title, in->title, sizeof( out->title ));
|
||||
Q_snprintf( out->version, sizeof( out->version ), "%g", in->version );
|
||||
Q_strncpy( out->iconpath, in->iconpath, sizeof( out->iconpath ));
|
||||
|
||||
Q_strncpy( out->game_url, in->game_url, sizeof( out->game_url ));
|
||||
Q_strncpy( out->update_url, in->update_url, sizeof( out->update_url ));
|
||||
Q_strncpy( out->size, Q_pretifymem( in->size, 0 ), sizeof( out->size ));
|
||||
out->size = in->size;
|
||||
Q_strncpy( out->type, in->type, sizeof( out->type ));
|
||||
Q_strncpy( out->date, in->date, sizeof( out->date ));
|
||||
|
||||
@@ -427,6 +439,31 @@ static void UI_ConvertGameInfo( GAMEINFO *out, gameinfo_t *in )
|
||||
SetBits( out->flags, GFL_ANIMATED_TITLE );
|
||||
}
|
||||
|
||||
static void UI_ToOldGameInfo( GAMEINFO *out, const gameinfo2_t *in )
|
||||
{
|
||||
Q_strncpy( out->gamefolder, in->gamefolder, sizeof( out->gamefolder ));
|
||||
Q_strncpy( out->startmap, in->startmap, sizeof( out->startmap ));
|
||||
Q_strncpy( out->trainmap, in->trainmap, sizeof( out->trainmap ));
|
||||
Q_strncpy( out->title, in->title, sizeof( out->title ));
|
||||
Q_strncpy( out->version, in->version, sizeof( out->version ));
|
||||
out->flags = in->flags & 0xFFFF;
|
||||
Q_strncpy( out->game_url, in->game_url, sizeof( out->game_url ));
|
||||
Q_strncpy( out->update_url, in->update_url, sizeof( out->update_url ));
|
||||
Q_strncpy( out->size, Q_memprint( in->size ), sizeof( out->size ));
|
||||
Q_strncpy( out->type, in->type, sizeof( out->type ));
|
||||
Q_strncpy( out->date, in->date, sizeof( out->date ));
|
||||
out->gamemode = in->gamemode;
|
||||
}
|
||||
|
||||
static void UI_GetModsInfo( void )
|
||||
{
|
||||
int i;
|
||||
|
||||
gameui.modsInfo = Mem_Calloc( gameui.mempool, sizeof( *gameui.modsInfo ) * FI->numgames );
|
||||
for( i = 0; i < FI->numgames; i++ )
|
||||
UI_ConvertGameInfo( &gameui.modsInfo[i], FI->games[i] );
|
||||
}
|
||||
|
||||
/*
|
||||
====================
|
||||
PIC_DrawGeneric
|
||||
@@ -924,11 +961,12 @@ pfnGetGameInfo
|
||||
|
||||
=========
|
||||
*/
|
||||
static int GAME_EXPORT pfnGetGameInfo( GAMEINFO *pgameinfo )
|
||||
static int GAME_EXPORT pfnGetOldGameInfo( GAMEINFO *pgameinfo )
|
||||
{
|
||||
if( !pgameinfo ) return 0;
|
||||
if( !pgameinfo )
|
||||
return 0;
|
||||
|
||||
*pgameinfo = gameui.gameInfo;
|
||||
UI_ToOldGameInfo( pgameinfo, &gameui.gameInfo );
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -940,8 +978,26 @@ pfnGetGamesList
|
||||
*/
|
||||
static GAMEINFO ** GAME_EXPORT pfnGetGamesList( int *numGames )
|
||||
{
|
||||
if( numGames ) *numGames = FI->numgames;
|
||||
return gameui.modsInfo;
|
||||
if( numGames )
|
||||
*numGames = FI->numgames;
|
||||
|
||||
if( !gameui.oldModsInfo )
|
||||
{
|
||||
int i;
|
||||
|
||||
if( !gameui.modsInfo )
|
||||
UI_GetModsInfo();
|
||||
|
||||
// first allocate array of pointers
|
||||
gameui.oldModsInfo = Mem_Calloc( gameui.mempool, sizeof( *gameui.oldModsInfo ) * FI->numgames );
|
||||
for( i = 0; i < FI->numgames; i++ )
|
||||
{
|
||||
gameui.oldModsInfo[i] = Mem_Calloc( gameui.mempool, sizeof( *gameui.oldModsInfo[i] ));
|
||||
UI_ToOldGameInfo( gameui.oldModsInfo[i], &gameui.modsInfo[i] );
|
||||
}
|
||||
}
|
||||
|
||||
return gameui.oldModsInfo;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1114,7 +1170,7 @@ static void GAME_EXPORT pfnSetCursor( void *hCursor )
|
||||
}
|
||||
|
||||
// engine callbacks
|
||||
static ui_enginefuncs_t gEngfuncs =
|
||||
static const ui_enginefuncs_t gEngfuncs =
|
||||
{
|
||||
pfnPIC_Load,
|
||||
GL_FreeImage,
|
||||
@@ -1178,7 +1234,7 @@ static ui_enginefuncs_t gEngfuncs =
|
||||
pfnKeyGetState,
|
||||
pfnMemAlloc,
|
||||
pfnMemFree,
|
||||
pfnGetGameInfo,
|
||||
pfnGetOldGameInfo,
|
||||
pfnGetGamesList,
|
||||
pfnGetFilesList,
|
||||
SV_GetSaveComment,
|
||||
@@ -1225,6 +1281,28 @@ static char *pfnParseFileSafe( char *data, char *buf, const int size, unsigned i
|
||||
return COM_ParseFileSafe( data, buf, size, flags, len, NULL );
|
||||
}
|
||||
|
||||
static gameinfo2_t *pfnGetGameInfo( int gi_version )
|
||||
{
|
||||
if( gi_version != gameui.gameInfo.gi_version )
|
||||
return NULL;
|
||||
|
||||
return &gameui.gameInfo;
|
||||
}
|
||||
|
||||
static gameinfo2_t *pfnGetModInfo( int gi_version, int i )
|
||||
{
|
||||
if( i < 0 || i >= FI->numgames )
|
||||
return NULL;
|
||||
|
||||
if( !gameui.modsInfo )
|
||||
UI_GetModsInfo();
|
||||
|
||||
if( gi_version != gameui.modsInfo[i].gi_version )
|
||||
return NULL;
|
||||
|
||||
return &gameui.modsInfo[i];
|
||||
}
|
||||
|
||||
static ui_extendedfuncs_t gExtendedfuncs =
|
||||
{
|
||||
pfnEnableTextInput,
|
||||
@@ -1238,6 +1316,8 @@ static ui_extendedfuncs_t gExtendedfuncs =
|
||||
NET_CompareAdrSort,
|
||||
Sys_GetNativeObject,
|
||||
&gNetApi,
|
||||
pfnGetGameInfo,
|
||||
pfnGetModInfo,
|
||||
};
|
||||
|
||||
void UI_UnloadProgs( void )
|
||||
@@ -1247,6 +1327,7 @@ void UI_UnloadProgs( void )
|
||||
// deinitialize game
|
||||
gameui.dllFuncs.pfnShutdown();
|
||||
|
||||
Cmd_RemoveCommand( "ui_allowconsole" );
|
||||
Cvar_FullSet( "host_gameuiloaded", "0", FCVAR_READ_ONLY );
|
||||
|
||||
Cvar_Unlink( FCVAR_GAMEUIDLL );
|
||||
@@ -1306,7 +1387,7 @@ qboolean UI_LoadProgs( void )
|
||||
gameui.use_extended_api = false;
|
||||
|
||||
// make local copy of engfuncs to prevent overwrite it with user dll
|
||||
memcpy( &gpEngfuncs, &gEngfuncs, sizeof( gpEngfuncs ));
|
||||
gpEngfuncs = gEngfuncs;
|
||||
|
||||
gameui.mempool = Mem_AllocPool( "Menu Pool" );
|
||||
|
||||
@@ -1320,7 +1401,7 @@ qboolean UI_LoadProgs( void )
|
||||
}
|
||||
|
||||
// make local copy of engfuncs to prevent overwrite it with user dll
|
||||
memcpy( &gpExtendedfuncs, &gExtendedfuncs, sizeof( gExtendedfuncs ));
|
||||
gpExtendedfuncs = gExtendedfuncs;
|
||||
memset( &gameui.dllFuncs2, 0, sizeof( gameui.dllFuncs2 ));
|
||||
|
||||
// try to initialize new extended API
|
||||
@@ -1355,13 +1436,7 @@ qboolean UI_LoadProgs( void )
|
||||
}
|
||||
|
||||
Cvar_FullSet( "host_gameuiloaded", "1", FCVAR_READ_ONLY );
|
||||
|
||||
// setup gameinfo
|
||||
for( i = 0; i < FI->numgames; i++ )
|
||||
{
|
||||
gameui.modsInfo[i] = Mem_Calloc( gameui.mempool, sizeof( GAMEINFO ));
|
||||
UI_ConvertGameInfo( gameui.modsInfo[i], FI->games[i] );
|
||||
}
|
||||
Cmd_AddRestrictedCommand( "ui_allowconsole", UI_ToggleAllowConsole_f, "unlocks developer console" );
|
||||
|
||||
UI_ConvertGameInfo( &gameui.gameInfo, FI->GameInfo ); // current gameinfo
|
||||
|
||||
|
||||
+97
-37
@@ -87,12 +87,14 @@ CVAR_DEFINE_AUTO( cl_fixmodelinterpolationartifacts, "1", 0, "try to fix up mode
|
||||
//
|
||||
// userinfo
|
||||
//
|
||||
static CVAR_DEFINE_AUTO( name, "player", FCVAR_USERINFO|FCVAR_ARCHIVE|FCVAR_PRINTABLEONLY|FCVAR_FILTERABLE, "player name" );
|
||||
static char username[32];
|
||||
static CVAR_DEFINE_AUTO( name, username, FCVAR_USERINFO|FCVAR_ARCHIVE|FCVAR_PRINTABLEONLY|FCVAR_FILTERABLE, "player name" );
|
||||
static CVAR_DEFINE_AUTO( model, "", FCVAR_USERINFO|FCVAR_ARCHIVE|FCVAR_FILTERABLE, "player model ('player' is a singleplayer model)" );
|
||||
static CVAR_DEFINE_AUTO( topcolor, "0", FCVAR_USERINFO|FCVAR_ARCHIVE|FCVAR_FILTERABLE, "player top color" );
|
||||
static CVAR_DEFINE_AUTO( bottomcolor, "0", FCVAR_USERINFO|FCVAR_ARCHIVE|FCVAR_FILTERABLE, "player bottom color" );
|
||||
CVAR_DEFINE_AUTO( rate, "3500", FCVAR_USERINFO|FCVAR_ARCHIVE|FCVAR_FILTERABLE, "player network rate" );
|
||||
|
||||
|
||||
client_t cl;
|
||||
client_static_t cls;
|
||||
clgame_static_t clgame;
|
||||
@@ -168,6 +170,11 @@ int CL_IsDevOverviewMode( void )
|
||||
return 0;
|
||||
}
|
||||
|
||||
connprotocol_t CL_Protocol( void )
|
||||
{
|
||||
return cls.legacymode;
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
CL_CheckClientState
|
||||
@@ -215,7 +222,7 @@ CL_SignonReply
|
||||
An svc_signonnum has been received, perform a client side setup
|
||||
=====================
|
||||
*/
|
||||
void CL_SignonReply( void )
|
||||
void CL_SignonReply( connprotocol_t proto )
|
||||
{
|
||||
// g-cont. my favorite message :-)
|
||||
Con_Reportf( "%s: %i\n", __func__, cls.signon );
|
||||
@@ -223,7 +230,7 @@ void CL_SignonReply( void )
|
||||
switch( cls.signon )
|
||||
{
|
||||
case 1:
|
||||
CL_ServerCommand( true, "begin" );
|
||||
CL_ServerCommand( true, proto == PROTO_GOLDSRC ? "sendents" : "begin" );
|
||||
if( host_developer.value >= DEV_EXTENDED )
|
||||
Mem_PrintStats();
|
||||
break;
|
||||
@@ -691,7 +698,13 @@ void CL_WriteUsercmd( sizebuf_t *msg, int from, int to )
|
||||
t = &cl.commands[to].cmd;
|
||||
|
||||
// write it into the buffer
|
||||
MSG_WriteDeltaUsercmd( msg, f, t );
|
||||
if( cls.legacymode == PROTO_GOLDSRC )
|
||||
{
|
||||
MSG_StartBitWriting( msg );
|
||||
Delta_WriteGSFields( msg, DT_USERCMD_T, f, t, 0.0f );
|
||||
MSG_EndBitWriting( msg );
|
||||
}
|
||||
else MSG_WriteDeltaUsercmd( msg, f, t );
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -790,6 +803,9 @@ static void CL_WritePacket( void )
|
||||
// begin a client move command
|
||||
MSG_BeginClientCmd( &buf, clc_move );
|
||||
|
||||
if( cls.legacymode == PROTO_GOLDSRC )
|
||||
MSG_WriteByte( &buf, 0 );
|
||||
|
||||
// save the position for a checksum byte
|
||||
key = MSG_GetRealBytesWritten( &buf );
|
||||
MSG_WriteByte( &buf, 0 );
|
||||
@@ -827,8 +843,16 @@ static void CL_WritePacket( void )
|
||||
|
||||
// calculate a checksum over the move commands
|
||||
size = MSG_GetRealBytesWritten( &buf ) - key - 1;
|
||||
if( cls.legacymode == PROTO_GOLDSRC )
|
||||
{
|
||||
size = Q_min( size, 255 );
|
||||
buf.pData[key - 1] = size;
|
||||
}
|
||||
buf.pData[key] = CRC32_BlockSequence( buf.pData + key + 1, size, cls.netchan.outgoing_sequence );
|
||||
|
||||
if( cls.legacymode == PROTO_GOLDSRC )
|
||||
COM_Munge( buf.pData + key + 1, size, cls.netchan.outgoing_sequence );
|
||||
|
||||
// message we are constructing.
|
||||
i = cls.netchan.outgoing_sequence & CL_UPDATE_MASK;
|
||||
|
||||
@@ -1046,7 +1070,31 @@ static void CL_SendConnectPacket( void )
|
||||
Info_SetValueForKey( protinfo, "a", Q_buildarch(), sizeof( protinfo ) );
|
||||
}
|
||||
|
||||
if( cls.legacymode )
|
||||
if( cls.legacymode == PROTO_GOLDSRC )
|
||||
{
|
||||
byte send_buf[MAX_PRINT_MSG];
|
||||
byte steam_cert[512];
|
||||
sizebuf_t send;
|
||||
|
||||
protinfo[0] = 0;
|
||||
|
||||
memset( steam_cert, 0, sizeof( steam_cert ));
|
||||
|
||||
Info_SetValueForKey( protinfo, "prot", "3", sizeof( protinfo )); // steam auth type
|
||||
Info_SetValueForKey( protinfo, "raw", "steam", sizeof( protinfo ));
|
||||
Info_SetValueForKey( protinfo, "cdkey", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", sizeof( protinfo ));
|
||||
|
||||
Info_SetValueForStarKey( cls.userinfo, "*hltv", "0", sizeof( cls.userinfo ));
|
||||
|
||||
MSG_Init( &send, "GoldSrcConnect", send_buf, sizeof( send_buf ));
|
||||
MSG_WriteLong( &send, NET_HEADER_OUTOFBANDPACKET );
|
||||
MSG_WriteStringf( &send, "connect %i %i \"%s\" \"%s\"\n",
|
||||
PROTOCOL_GOLDSRC_VERSION, cls.challenge, protinfo, cls.userinfo );
|
||||
MSG_WriteBytes( &send, steam_cert, sizeof( steam_cert ));
|
||||
|
||||
NET_SendPacket( NS_CLIENT, MSG_GetNumBytesWritten( &send ), MSG_GetData( &send ), adr );
|
||||
}
|
||||
else if( cls.legacymode == PROTO_LEGACY )
|
||||
{
|
||||
// set related userinfo keys
|
||||
if( cl_dlmax.value >= 40000 || cl_dlmax.value < 100 )
|
||||
@@ -1145,7 +1193,7 @@ static void CL_CheckForResend( void )
|
||||
if(( host.realtime - cls.connect_time ) < resendTime )
|
||||
return;
|
||||
|
||||
res = NET_StringToAdrNB( cls.servername, &adr );
|
||||
res = NET_StringToAdrNB( cls.servername, &adr, false );
|
||||
|
||||
if( res == NET_EAI_NONAME )
|
||||
{
|
||||
@@ -1276,11 +1324,12 @@ static void CL_Connect_f( void )
|
||||
proto = PROTO_CURRENT;
|
||||
else if( !Q_strcmp( s, "legacy" ) || !Q_strcmp( s, "48" ))
|
||||
proto = PROTO_LEGACY;
|
||||
else if( !Q_strcmp( s, "goldsrc" ))
|
||||
proto = PROTO_GOLDSRC;
|
||||
else
|
||||
{
|
||||
// quake protocol only used for demos
|
||||
// goldsrc protocol is not supported yet
|
||||
Con_Printf( "Unknown protocol. Supported are: current, legacy\n" );
|
||||
Con_Printf( "Unknown protocol. Supported are: current, legacy, goldsrc\n" );
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -1475,16 +1524,19 @@ static void CL_Reconnect( qboolean setup_netchan )
|
||||
{
|
||||
if( setup_netchan )
|
||||
{
|
||||
Netchan_Setup( NS_CLIENT, &cls.netchan, net_from, Cvar_VariableInteger( "net_qport" ), NULL, CL_GetFragmentSize );
|
||||
uint flags = 0;
|
||||
|
||||
if( cls.legacymode )
|
||||
if( cls.legacymode == PROTO_GOLDSRC )
|
||||
{
|
||||
SetBits( flags, NETCHAN_USE_MUNGE | NETCHAN_USE_BZIP2 | NETCHAN_GOLDSRC );
|
||||
}
|
||||
else if( cls.legacymode == PROTO_LEGACY )
|
||||
{
|
||||
unsigned int extensions = Q_atoi( Cmd_Argv( 1 ) );
|
||||
|
||||
if( extensions & NET_LEGACY_EXT_SPLIT )
|
||||
if( FBitSet( extensions, NET_LEGACY_EXT_SPLIT ))
|
||||
{
|
||||
// only enable incoming split for legacy mode
|
||||
cls.netchan.split = true;
|
||||
SetBits( flags, NETCHAN_USE_LEGACY_SPLIT );
|
||||
Con_Reportf( "^2NET_EXT_SPLIT enabled^7 (packet sizes is %d/%d)\n", (int)cl_dlmax.value, 65536 );
|
||||
}
|
||||
}
|
||||
@@ -1492,12 +1544,11 @@ static void CL_Reconnect( qboolean setup_netchan )
|
||||
{
|
||||
cls.extensions = Q_atoi( Info_ValueForKey( Cmd_Argv( 1 ), "ext" ));
|
||||
|
||||
if( cls.extensions & NET_EXT_SPLITSIZE )
|
||||
{
|
||||
if( FBitSet( cls.extensions, NET_EXT_SPLITSIZE ))
|
||||
Con_Reportf( "^2NET_EXT_SPLITSIZE enabled^7 (packet size is %d)\n", (int)cl_dlmax.value );
|
||||
}
|
||||
}
|
||||
|
||||
Netchan_Setup( NS_CLIENT, &cls.netchan, net_from, Cvar_VariableInteger( "net_qport" ), NULL, CL_GetFragmentSize, flags );
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -2045,7 +2096,7 @@ static void CL_ConnectionlessPacket( netadr_t from, sizebuf_t *msg )
|
||||
Con_Reportf( "%s: %s : %s\n", __func__, NET_AdrToString( from ), c );
|
||||
|
||||
// server connection
|
||||
if( !Q_strcmp( c, "client_connect" ))
|
||||
if( !Q_strcmp( c, "client_connect" ) || !Q_strcmp( c, S2C_CONNECTION ))
|
||||
{
|
||||
if( !CL_IsFromConnectingServer( from ))
|
||||
return;
|
||||
@@ -2167,7 +2218,7 @@ static void CL_ConnectionlessPacket( netadr_t from, sizebuf_t *msg )
|
||||
// ping from somewhere
|
||||
Netchan_OutOfBandPrint( NS_CLIENT, from, "ack" );
|
||||
}
|
||||
else if( !Q_strcmp( c, "challenge" ))
|
||||
else if( !Q_strcmp( c, "challenge" ) || !Q_strcmp( c, S2C_CHALLENGE ))
|
||||
{
|
||||
// this message only used during connection
|
||||
// it doesn't make sense after client_connect
|
||||
@@ -2204,7 +2255,7 @@ static void CL_ConnectionlessPacket( netadr_t from, sizebuf_t *msg )
|
||||
// dropped the connection but it is still getting packets from us
|
||||
CL_Disconnect_f();
|
||||
}
|
||||
else if( !Q_strcmp( c, "errormsg" ))
|
||||
else if( !Q_strcmp( c, "errormsg" ) || c[0] == S2C_REJECT || c[0] == S2C_REJECT_BADPASSWORD )
|
||||
{
|
||||
char formatted_msg[MAX_VA_STRING];
|
||||
|
||||
@@ -2212,6 +2263,8 @@ static void CL_ConnectionlessPacket( netadr_t from, sizebuf_t *msg )
|
||||
return;
|
||||
|
||||
args = MSG_ReadString( msg );
|
||||
if( c[0] == S2C_REJECT || c[0] == S2C_REJECT_BADPASSWORD )
|
||||
args++; // skip one byte
|
||||
|
||||
Q_snprintf( formatted_msg, sizeof( formatted_msg ), "^3Server message^7\n%s", args );
|
||||
|
||||
@@ -2345,14 +2398,11 @@ static void CL_ParseNetMessage( sizebuf_t *msg, void (*parsefn)( sizebuf_t * ))
|
||||
// after we have parsed the frame
|
||||
if( !cls.demoplayback )
|
||||
{
|
||||
if( cls.demorecording && !cls.demowaiting )
|
||||
{
|
||||
CL_WriteDemoMessage( false, cls.starting_count, msg );
|
||||
}
|
||||
else if( cls.state != ca_active )
|
||||
{
|
||||
if( cls.state != ca_active )
|
||||
CL_WriteDemoMessage( true, cls.starting_count, msg );
|
||||
}
|
||||
|
||||
if( cls.demorecording && !cls.demowaiting )
|
||||
CL_WriteDemoMessage( false, cls.starting_count, msg );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2379,6 +2429,8 @@ static void CL_ReadNetMessage( void )
|
||||
parsefn = CL_ParseQuakeMessage;
|
||||
break;
|
||||
case PROTO_GOLDSRC:
|
||||
parsefn = CL_ParseGoldSrcServerMessage;
|
||||
break;
|
||||
default:
|
||||
ASSERT( 0 );
|
||||
return;
|
||||
@@ -2592,7 +2644,6 @@ void CL_ProcessFile( qboolean successfully_received, const char *filename )
|
||||
{
|
||||
int sound_len = sizeof( DEFAULT_SOUNDPATH ) - 1;
|
||||
byte rgucMD5_hash[16];
|
||||
const char *pfilename;
|
||||
resource_t *p;
|
||||
|
||||
if( COM_CheckString( filename ) && successfully_received )
|
||||
@@ -2600,10 +2651,10 @@ void CL_ProcessFile( qboolean successfully_received, const char *filename )
|
||||
if( filename[0] != '!' )
|
||||
Con_Printf( "processing %s\n", filename );
|
||||
|
||||
if( !Q_strnicmp( filename, "downloaded/", 11 ))
|
||||
if( !Q_strnicmp( filename, DEFAULT_DOWNLOADED_DIRECTORY, sizeof( DEFAULT_DOWNLOADED_DIRECTORY ) - 1 ))
|
||||
{
|
||||
// skip "downloaded/" part to avoid mismatch with needed resources list
|
||||
filename += 11;
|
||||
filename += sizeof( DEFAULT_DOWNLOADED_DIRECTORY ) - 1;
|
||||
}
|
||||
}
|
||||
else if( !successfully_received )
|
||||
@@ -2669,7 +2720,7 @@ void CL_ProcessFile( qboolean successfully_received, const char *filename )
|
||||
else
|
||||
{
|
||||
Con_Printf( "Downloaded %i bytes for purported %i byte file, ignoring download\n",
|
||||
cls.netchan.tempbuffersize, p->nDownloadSize );
|
||||
cls.netchan.tempbuffersize, p->nDownloadSize );
|
||||
}
|
||||
|
||||
if( cls.netchan.tempbuffer )
|
||||
@@ -2699,7 +2750,7 @@ void CL_ProcessFile( qboolean successfully_received, const char *filename )
|
||||
MSG_Init( &msg, "Resource Registration", msg_buf, sizeof( msg_buf ));
|
||||
|
||||
if( CL_PrecacheResources( ))
|
||||
CL_RegisterResources( &msg );
|
||||
CL_RegisterResources( &msg, cls.legacymode );
|
||||
|
||||
if( MSG_GetNumBytesWritten( &msg ) > 0 )
|
||||
{
|
||||
@@ -2829,19 +2880,26 @@ static void CL_Physinfo_f( void )
|
||||
static qboolean CL_ShouldRescanFilesystem( void )
|
||||
{
|
||||
resource_t *res;
|
||||
qboolean retval = false;
|
||||
|
||||
for( res = cl.resourcesonhand.pNext; res && res != &cl.resourcesonhand; res = res->pNext )
|
||||
{
|
||||
if( res->type == t_generic )
|
||||
{
|
||||
const char *ext = COM_FileExtension( res->szFileName );
|
||||
// TODO: query supported archives format from fs_stdio
|
||||
// TODO: query if was already opened
|
||||
if( !Q_stricmp( ext, "wad" ) || !Q_stricmp( ext, "pk3" ) || !Q_stricmp( ext, "pak" ))
|
||||
return true;
|
||||
|
||||
if( !g_fsapi.IsArchiveExtensionSupported( ext, IAES_ONLY_REAL_ARCHIVES ))
|
||||
continue;
|
||||
|
||||
if( FBitSet( res->ucExtraFlags, RES_EXTRA_ARCHIVE_CHECKED ))
|
||||
continue;
|
||||
|
||||
SetBits( res->ucExtraFlags, RES_EXTRA_ARCHIVE_CHECKED );
|
||||
retval = true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
qboolean CL_PrecacheResources( void )
|
||||
@@ -3074,8 +3132,9 @@ static void CL_InitLocal( void )
|
||||
|
||||
// userinfo
|
||||
Cvar_RegisterVariable( &cl_nopred );
|
||||
Q_strncpy( username, Sys_GetCurrentUser(), sizeof( username )); // initialize before registering variable
|
||||
Cvar_RegisterVariable( &name );
|
||||
Cvar_DirectSet( &name, Sys_GetCurrentUser( ));
|
||||
Cvar_Get( "ui_username", username, FCVAR_READ_ONLY|FCVAR_PRIVILEGED, "default user name" );
|
||||
Cvar_RegisterVariable( &model );
|
||||
Cvar_RegisterVariable( &cl_updaterate );
|
||||
Cvar_RegisterVariable( &cl_dlmax );
|
||||
@@ -3151,6 +3210,7 @@ static void CL_InitLocal( void )
|
||||
Cmd_AddCommand ("demos", CL_Demos_f, "restart looping demos defined by the last startdemos command" );
|
||||
Cmd_AddCommand ("movie", CL_PlayVideo_f, "play a movie" );
|
||||
Cmd_AddCommand ("stop", CL_Stop_f, "stop playing or recording a demo" );
|
||||
Cmd_AddCommand( "listdemo", CL_ListDemo_f, "list demo entries" );
|
||||
Cmd_AddCommand ("info", NULL, "collect info about local servers with specified protocol" );
|
||||
Cmd_AddCommand ("escape", CL_Escape_f, "escape from game to menu" );
|
||||
Cmd_AddCommand ("togglemenu", CL_Escape_f, "toggle between game and menu" );
|
||||
|
||||
+30
-23
@@ -20,8 +20,6 @@ GNU General Public License for more details.
|
||||
#include "input.h"
|
||||
#include "platform/platform.h"
|
||||
|
||||
static mobile_engfuncs_t *gMobileEngfuncs;
|
||||
|
||||
static CVAR_DEFINE_AUTO( vibration_length, "1.0", FCVAR_ARCHIVE | FCVAR_PRIVILEGED, "vibration length" );
|
||||
static CVAR_DEFINE_AUTO( vibration_enable, "1", FCVAR_ARCHIVE | FCVAR_PRIVILEGED, "enable vibration" );
|
||||
|
||||
@@ -30,17 +28,9 @@ static float g_font_scale;
|
||||
|
||||
static void pfnVibrate( float life, char flags )
|
||||
{
|
||||
if( !vibration_enable.value )
|
||||
if( !vibration_enable.value || life < 0.0f )
|
||||
return;
|
||||
|
||||
if( life < 0.0f )
|
||||
{
|
||||
Con_Reportf( S_WARN "Negative vibrate time: %f\n", life );
|
||||
return;
|
||||
}
|
||||
|
||||
//Con_Reportf( "Vibrate: %f %d\n", life, flags );
|
||||
|
||||
// here goes platform-specific backends
|
||||
Platform_Vibrate( life * vibration_length.value, flags );
|
||||
}
|
||||
@@ -53,7 +43,7 @@ static void Vibrate_f( void )
|
||||
return;
|
||||
}
|
||||
|
||||
pfnVibrate( Q_atof( Cmd_Argv(1) ), VIBRATE_NORMAL );
|
||||
pfnVibrate( Q_atof( Cmd_Argv( 1 )), VIBRATE_NORMAL );
|
||||
}
|
||||
|
||||
static void pfnEnableTextInput( int enable )
|
||||
@@ -102,7 +92,7 @@ static char *pfnParseFileSafe( char *data, char *buf, const int size, unsigned i
|
||||
return COM_ParseFileSafe( data, buf, size, flags, len, NULL );
|
||||
}
|
||||
|
||||
static mobile_engfuncs_t gpMobileEngfuncs =
|
||||
static const mobile_engfuncs_t gMobileEngfuncs =
|
||||
{
|
||||
MOBILITY_API_VERSION,
|
||||
pfnVibrate,
|
||||
@@ -122,21 +112,38 @@ static mobile_engfuncs_t gpMobileEngfuncs =
|
||||
|
||||
qboolean Mobile_Init( void )
|
||||
{
|
||||
qboolean success = false;
|
||||
pfnMobilityInterface ExportToClient;
|
||||
|
||||
// find a mobility interface
|
||||
ExportToClient = COM_GetProcAddress( clgame.hInstance, MOBILITY_CLIENT_EXPORT );
|
||||
gMobileEngfuncs = &gpMobileEngfuncs;
|
||||
|
||||
if( ExportToClient && !ExportToClient( gMobileEngfuncs ) )
|
||||
success = true;
|
||||
|
||||
Cmd_AddCommand( "vibrate", (xcommand_t)Vibrate_f, "Vibrate for specified time");
|
||||
Cmd_AddCommand( "vibrate", Vibrate_f, "Vibrate for specified time");
|
||||
Cvar_RegisterVariable( &vibration_length );
|
||||
Cvar_RegisterVariable( &vibration_enable );
|
||||
|
||||
return success;
|
||||
// find mobility interface
|
||||
if(( ExportToClient = COM_GetProcAddress( clgame.hInstance, MOBILITY_CLIENT_EXPORT )))
|
||||
{
|
||||
static mobile_engfuncs_t mobile_engfuncs; // keep a copy, don't let user change engine pointers
|
||||
|
||||
mobile_engfuncs = gMobileEngfuncs;
|
||||
|
||||
if( !ExportToClient( &mobile_engfuncs ))
|
||||
{
|
||||
Con_Reportf( "%s: ^2initailized extended MobilityAPI ^7ver. %i\n", __func__, MOBILITY_API_VERSION );
|
||||
return true;
|
||||
}
|
||||
|
||||
// make sure that mobile functions are cleared
|
||||
#if 1
|
||||
// some SDKs define export as returning void, breaking the contract
|
||||
// ignore result for now...
|
||||
return true;
|
||||
#else
|
||||
memset( &mobile_engfuncs, 0, sizeof( mobile_engfuncs ));
|
||||
|
||||
return false; // just tell user about problems
|
||||
#endif
|
||||
}
|
||||
|
||||
return true; // mobile interface is missed
|
||||
}
|
||||
|
||||
void Mobile_Shutdown( void )
|
||||
|
||||
+175
-88
@@ -216,7 +216,7 @@ CL_ParseSignon
|
||||
|
||||
==================
|
||||
*/
|
||||
void CL_ParseSignon( sizebuf_t *msg )
|
||||
void CL_ParseSignon( sizebuf_t *msg, connprotocol_t proto )
|
||||
{
|
||||
int i = MSG_ReadByte( msg );
|
||||
|
||||
@@ -228,7 +228,7 @@ void CL_ParseSignon( sizebuf_t *msg )
|
||||
}
|
||||
|
||||
cls.signon = i;
|
||||
CL_SignonReply();
|
||||
CL_SignonReply( proto );
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -251,7 +251,7 @@ void CL_ParseMovevars( sizebuf_t *msg )
|
||||
if( Q_strcmp( clgame.oldmovevars.skyName, clgame.movevars.skyName ) && cl.video_prepped )
|
||||
R_SetupSky( clgame.movevars.skyName );
|
||||
|
||||
memcpy( &clgame.oldmovevars, &clgame.movevars, sizeof( movevars_t ));
|
||||
clgame.oldmovevars = clgame.movevars;
|
||||
clgame.entities->curstate.scale = clgame.movevars.waveHeight;
|
||||
|
||||
// keep features an actual!
|
||||
@@ -304,7 +304,7 @@ CL_ParseStaticEntity
|
||||
static client entity
|
||||
==================
|
||||
*/
|
||||
static void CL_ParseStaticEntity( sizebuf_t *msg )
|
||||
void CL_ParseStaticEntity( sizebuf_t *msg )
|
||||
{
|
||||
int i, newnum;
|
||||
entity_state_t from, to;
|
||||
@@ -388,7 +388,6 @@ void CL_ParseStaticDecal( sizebuf_t *msg )
|
||||
{
|
||||
vec3_t origin;
|
||||
int decalIndex, entityIndex, modelIndex;
|
||||
cl_entity_t *ent = NULL;
|
||||
float scale;
|
||||
int flags;
|
||||
|
||||
@@ -532,7 +531,7 @@ void CL_BatchResourceRequest( qboolean initialize )
|
||||
{
|
||||
if( done_downloading && CL_PrecacheResources( ))
|
||||
{
|
||||
CL_RegisterResources( &msg );
|
||||
CL_RegisterResources( &msg, cls.legacymode );
|
||||
}
|
||||
|
||||
Netchan_CreateFragments( &cls.netchan, &msg );
|
||||
@@ -846,7 +845,7 @@ void CL_ParseFileTransferFailed( sizebuf_t *msg )
|
||||
CL_ParseServerData
|
||||
==================
|
||||
*/
|
||||
void CL_ParseServerData( sizebuf_t *msg, qboolean legacy )
|
||||
void CL_ParseServerData( sizebuf_t *msg, connprotocol_t proto )
|
||||
{
|
||||
char gamefolder[MAX_QPATH];
|
||||
string mapfile;
|
||||
@@ -856,7 +855,18 @@ void CL_ParseServerData( sizebuf_t *msg, qboolean legacy )
|
||||
|
||||
HPAK_CheckSize( hpk_custom_file.string );
|
||||
|
||||
Con_Reportf( "%s packet received.\n", legacy ? "Legacy serverdata" : "Serverdata" );
|
||||
switch( proto )
|
||||
{
|
||||
case PROTO_LEGACY:
|
||||
Con_Reportf( "Legacy serverdata packet received.\n" );
|
||||
break;
|
||||
case PROTO_GOLDSRC:
|
||||
Con_Reportf( "GoldSrc serverdata packet received.\n" );
|
||||
break;
|
||||
default:
|
||||
Con_Reportf( "Serverdata packet received.\n" );
|
||||
break;
|
||||
}
|
||||
|
||||
cls.timestart = Sys_DoubleTime();
|
||||
cls.demowaiting = false; // server is changed
|
||||
@@ -873,7 +883,7 @@ void CL_ParseServerData( sizebuf_t *msg, qboolean legacy )
|
||||
// parse protocol version number
|
||||
i = MSG_ReadLong( msg );
|
||||
|
||||
if( legacy )
|
||||
if( proto == PROTO_LEGACY || proto == PROTO_GOLDSRC ) // GoldSrc protocol version is 48, same as Xash3D 48
|
||||
{
|
||||
if( i != PROTOCOL_LEGACY_VERSION )
|
||||
Host_Error( "Server use invalid protocol (%i should be %i)\n", i, PROTOCOL_LEGACY_VERSION );
|
||||
@@ -886,40 +896,64 @@ void CL_ParseServerData( sizebuf_t *msg, qboolean legacy )
|
||||
|
||||
cl.servercount = MSG_ReadLong( msg );
|
||||
cl.checksum = MSG_ReadLong( msg );
|
||||
cl.playernum = MSG_ReadByte( msg );
|
||||
cl.maxclients = MSG_ReadByte( msg );
|
||||
clgame.maxEntities = MSG_ReadWord( msg );
|
||||
if( legacy )
|
||||
if( proto == PROTO_GOLDSRC )
|
||||
{
|
||||
clgame.maxEntities = bound( MIN_LEGACY_EDICTS, clgame.maxEntities, MAX_LEGACY_EDICTS );
|
||||
byte clientdllmd5[16];
|
||||
byte unused;
|
||||
|
||||
MSG_ReadBytes( msg, clientdllmd5, sizeof( clientdllmd5 ));
|
||||
cl.maxclients = MSG_ReadByte( msg );
|
||||
cl.playernum = MSG_ReadByte( msg );
|
||||
unused = MSG_ReadByte( msg ); // coop flag
|
||||
Q_strncpy( gamefolder, MSG_ReadString( msg ), sizeof( gamefolder ));
|
||||
MSG_ReadString( msg ); // hostname
|
||||
Q_strncpy( clgame.mapname, MSG_ReadString( msg ), sizeof( clgame.mapname ));
|
||||
MSG_ReadString( msg ); // mapcycle?????
|
||||
unused = MSG_ReadByte( msg ); // vac secure
|
||||
|
||||
background = false;
|
||||
clgame.maxEntities = GI->max_edicts + (( cl.maxclients - 1 ) * 15 );
|
||||
clgame.maxEntities = bound( MIN_LEGACY_EDICTS, clgame.maxEntities, MAX_GOLDSRC_EDICTS );
|
||||
clgame.maxModels = 512; // ???
|
||||
Q_strncpy( clgame.maptitle, clgame.mapname, sizeof( clgame.maptitle ));
|
||||
}
|
||||
else
|
||||
{
|
||||
clgame.maxEntities = bound( MIN_EDICTS, clgame.maxEntities, MAX_EDICTS );
|
||||
clgame.maxModels = MSG_ReadWord( msg );
|
||||
}
|
||||
Q_strncpy( clgame.mapname, MSG_ReadString( msg ), sizeof( clgame.mapname ));
|
||||
Q_strncpy( clgame.maptitle, MSG_ReadString( msg ), sizeof( clgame.maptitle ));
|
||||
background = MSG_ReadOneBit( msg );
|
||||
Q_strncpy( gamefolder, MSG_ReadString( msg ), sizeof( gamefolder ));
|
||||
Host_ValidateEngineFeatures( MSG_ReadDword( msg ));
|
||||
|
||||
if( !legacy )
|
||||
{
|
||||
// receive the player hulls
|
||||
for( i = 0; i < MAX_MAP_HULLS * 3; i++ )
|
||||
cl.playernum = MSG_ReadByte( msg );
|
||||
cl.maxclients = MSG_ReadByte( msg );
|
||||
clgame.maxEntities = MSG_ReadWord( msg );
|
||||
if( proto == PROTO_LEGACY )
|
||||
{
|
||||
host.player_mins[i/3][i%3] = MSG_ReadChar( msg );
|
||||
host.player_maxs[i/3][i%3] = MSG_ReadChar( msg );
|
||||
clgame.maxEntities = bound( MIN_LEGACY_EDICTS, clgame.maxEntities, MAX_LEGACY_EDICTS );
|
||||
clgame.maxModels = 512; // ???
|
||||
}
|
||||
else
|
||||
{
|
||||
clgame.maxEntities = bound( MIN_EDICTS, clgame.maxEntities, MAX_EDICTS );
|
||||
clgame.maxModels = MSG_ReadWord( msg );
|
||||
}
|
||||
Q_strncpy( clgame.mapname, MSG_ReadString( msg ), sizeof( clgame.mapname ));
|
||||
Q_strncpy( clgame.maptitle, MSG_ReadString( msg ), sizeof( clgame.maptitle ));
|
||||
background = MSG_ReadOneBit( msg );
|
||||
Q_strncpy( gamefolder, MSG_ReadString( msg ), sizeof( gamefolder ));
|
||||
Host_ValidateEngineFeatures( MSG_ReadDword( msg ));
|
||||
|
||||
if( proto == PROTO_LEGACY )
|
||||
{
|
||||
// receive the player hulls
|
||||
for( i = 0; i < MAX_MAP_HULLS * 3; i++ )
|
||||
{
|
||||
host.player_mins[i/3][i%3] = MSG_ReadChar( msg );
|
||||
host.player_maxs[i/3][i%3] = MSG_ReadChar( msg );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Q_snprintf( mapfile, sizeof( mapfile ), "maps/%s.bsp", clgame.mapname );
|
||||
if( CRC32_MapFile( &mapCRC, mapfile, cl.maxclients > 1 ))
|
||||
if( CRC32_MapFile( &cl.worldmapCRC, mapfile, cl.maxclients > 1 ))
|
||||
{
|
||||
// validate map checksum
|
||||
if( mapCRC != cl.checksum )
|
||||
if( cl.worldmapCRC != cl.checksum )
|
||||
{
|
||||
Con_Printf( S_ERROR "Your map [%s] differs from the server's.\n", clgame.mapname );
|
||||
CL_Disconnect_f(); // for local game, call EndGame
|
||||
@@ -1000,7 +1034,7 @@ void CL_ParseServerData( sizebuf_t *msg, qboolean legacy )
|
||||
COM_ClearCustomizationList( &cl.players[i].customdata, true );
|
||||
CL_CreateCustomizationList();
|
||||
|
||||
if( !legacy )
|
||||
if( proto != PROTO_LEGACY )
|
||||
{
|
||||
// request resources from server
|
||||
CL_ServerCommand( true, "sendres %i\n", cl.servercount );
|
||||
@@ -1018,7 +1052,7 @@ void CL_ParseServerData( sizebuf_t *msg, qboolean legacy )
|
||||
CL_ParseClientData
|
||||
===================
|
||||
*/
|
||||
void CL_ParseClientData( sizebuf_t *msg )
|
||||
void CL_ParseClientData( sizebuf_t *msg, connprotocol_t proto )
|
||||
{
|
||||
float parsecounttime;
|
||||
int i, j, command_ack;
|
||||
@@ -1152,7 +1186,9 @@ void CL_ParseClientData( sizebuf_t *msg )
|
||||
from_wd = nullwd;
|
||||
}
|
||||
|
||||
MSG_ReadClientData( msg, from_cd, to_cd, cl.mtime[0] );
|
||||
if( proto == PROTO_GOLDSRC )
|
||||
Delta_ReadGSFields( msg, DT_CLIENTDATA_T, from_cd, to_cd, cl.mtime[0] );
|
||||
else MSG_ReadClientData( msg, from_cd, to_cd, cl.mtime[0] );
|
||||
|
||||
for( i = 0; i < 64; i++ )
|
||||
{
|
||||
@@ -1160,9 +1196,11 @@ void CL_ParseClientData( sizebuf_t *msg )
|
||||
if( !MSG_ReadOneBit( msg )) break;
|
||||
|
||||
// read the weapon idx
|
||||
idx = MSG_ReadUBitLong( msg, cls.legacymode ? MAX_LEGACY_WEAPON_BITS : MAX_WEAPON_BITS );
|
||||
idx = MSG_ReadUBitLong( msg, proto == PROTO_LEGACY ? MAX_LEGACY_WEAPON_BITS : MAX_WEAPON_BITS );
|
||||
|
||||
MSG_ReadWeaponData( msg, &from_wd[idx], &to_wd[idx], cl.mtime[0] );
|
||||
if( proto == PROTO_GOLDSRC )
|
||||
Delta_ReadGSFields( msg, DT_WEAPONDATA_T, &from_wd[idx], &to_wd[idx], cl.mtime[0] );
|
||||
else MSG_ReadWeaponData( msg, &from_wd[idx], &to_wd[idx], cl.mtime[0] );
|
||||
}
|
||||
|
||||
// make a local copy of physinfo
|
||||
@@ -1179,55 +1217,87 @@ void CL_ParseClientData( sizebuf_t *msg )
|
||||
CL_ParseBaseline
|
||||
==================
|
||||
*/
|
||||
void CL_ParseBaseline( sizebuf_t *msg, qboolean legacy )
|
||||
void CL_ParseBaseline( sizebuf_t *msg, connprotocol_t proto )
|
||||
{
|
||||
int i, newnum;
|
||||
entity_state_t nullstate;
|
||||
qboolean player;
|
||||
cl_entity_t *ent;
|
||||
const entity_state_t nullstate = { 0 };
|
||||
|
||||
Delta_InitClient (); // finalize client delta's
|
||||
|
||||
memset( &nullstate, 0, sizeof( nullstate ));
|
||||
if( proto == PROTO_GOLDSRC )
|
||||
MSG_StartBitWriting( msg );
|
||||
|
||||
while( 1 )
|
||||
{
|
||||
if( legacy )
|
||||
cl_entity_t *ent;
|
||||
qboolean player;
|
||||
int newnum;
|
||||
|
||||
if( proto == PROTO_LEGACY )
|
||||
{
|
||||
newnum = MSG_ReadWord( msg );
|
||||
}
|
||||
else if( proto == PROTO_GOLDSRC )
|
||||
{
|
||||
uint value = MSG_ReadWord( msg );
|
||||
|
||||
if( value == 0xffff ) break; // end of baselines
|
||||
|
||||
MSG_SeekToBit( msg, -16, SEEK_CUR );
|
||||
newnum = MSG_ReadUBitLong( msg, MAX_GOLDSRC_ENTITY_BITS );
|
||||
}
|
||||
else
|
||||
{
|
||||
newnum = MSG_ReadUBitLong( msg, MAX_ENTITY_BITS );
|
||||
if( newnum == LAST_EDICT ) break; // end of baselines
|
||||
}
|
||||
|
||||
player = CL_IsPlayerIndex( newnum );
|
||||
|
||||
if( newnum >= clgame.maxEntities )
|
||||
Host_Error( "%s: no free edicts\n", __func__ );
|
||||
|
||||
ent = CL_EDICT_NUM( newnum );
|
||||
memset( &ent->prevstate, 0, sizeof( ent->prevstate ));
|
||||
ent->prevstate = nullstate;
|
||||
ent->index = newnum;
|
||||
|
||||
MSG_ReadDeltaEntity( msg, &ent->prevstate, &ent->baseline, newnum, player, 1.0f );
|
||||
|
||||
if( legacy )
|
||||
if( proto == PROTO_GOLDSRC )
|
||||
{
|
||||
break; // only one baseline allowed in legacy protocol
|
||||
int type = MSG_ReadUBitLong( msg, 2 );
|
||||
int bits = MSG_GetNumBitsWritten( msg );
|
||||
int delta_type;
|
||||
|
||||
if( player ) delta_type = DT_ENTITY_STATE_PLAYER_T;
|
||||
else if( type != ENTITY_NORMAL ) delta_type = DT_CUSTOM_ENTITY_STATE_T;
|
||||
else delta_type = DT_ENTITY_STATE_T;
|
||||
|
||||
Delta_ReadGSFields( msg, delta_type, &ent->prevstate, &ent->baseline, 1.0f );
|
||||
}
|
||||
else MSG_ReadDeltaEntity( msg, &nullstate, &ent->baseline, newnum, player, 1.0f );
|
||||
|
||||
if( proto == PROTO_LEGACY )
|
||||
break; // only one baseline allowed in legacy protocol
|
||||
}
|
||||
|
||||
if( !legacy )
|
||||
if( proto != PROTO_LEGACY )
|
||||
{
|
||||
int i;
|
||||
|
||||
cl.instanced_baseline_count = MSG_ReadUBitLong( msg, 6 );
|
||||
|
||||
for( i = 0; i < cl.instanced_baseline_count; i++ )
|
||||
{
|
||||
newnum = MSG_ReadUBitLong( msg, MAX_ENTITY_BITS );
|
||||
MSG_ReadDeltaEntity( msg, &nullstate, &cl.instanced_baseline[i], newnum, false, 1.0f );
|
||||
if( proto == PROTO_GOLDSRC )
|
||||
Delta_ReadGSFields( msg, DT_ENTITY_STATE_T, &nullstate, &cl.instanced_baseline[i], 1.0f );
|
||||
else
|
||||
{
|
||||
int newnum = MSG_ReadUBitLong( msg, MAX_ENTITY_BITS );
|
||||
MSG_ReadDeltaEntity( msg, &nullstate, &cl.instanced_baseline[i], newnum, false, 1.0f );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( proto == PROTO_GOLDSRC )
|
||||
MSG_EndBitWriting( msg );
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1235,15 +1305,16 @@ void CL_ParseBaseline( sizebuf_t *msg, qboolean legacy )
|
||||
CL_ParseLightStyle
|
||||
================
|
||||
*/
|
||||
void CL_ParseLightStyle( sizebuf_t *msg )
|
||||
void CL_ParseLightStyle( sizebuf_t *msg, connprotocol_t proto )
|
||||
{
|
||||
int style;
|
||||
const char *s;
|
||||
float f;
|
||||
float f = 0.0f;
|
||||
|
||||
style = MSG_ReadByte( msg );
|
||||
s = MSG_ReadString( msg );
|
||||
f = MSG_ReadFloat( msg );
|
||||
if( proto != PROTO_GOLDSRC )
|
||||
f = MSG_ReadFloat( msg );
|
||||
|
||||
CL_SetLightstyle( style, s, f );
|
||||
}
|
||||
@@ -1372,26 +1443,36 @@ CL_UpdateUserinfo
|
||||
collect userinfo from all players
|
||||
================
|
||||
*/
|
||||
void CL_UpdateUserinfo( sizebuf_t *msg, qboolean legacy )
|
||||
void CL_UpdateUserinfo( sizebuf_t *msg, connprotocol_t proto )
|
||||
{
|
||||
int slot, id;
|
||||
qboolean active;
|
||||
player_info_t *player;
|
||||
|
||||
slot = MSG_ReadUBitLong( msg, MAX_CLIENT_BITS );
|
||||
if( proto == PROTO_GOLDSRC )
|
||||
{
|
||||
slot = MSG_ReadByte( msg );
|
||||
id = MSG_ReadLong( msg );
|
||||
active = true;
|
||||
}
|
||||
else if( proto == PROTO_LEGACY )
|
||||
{
|
||||
slot = MSG_ReadUBitLong( msg, MAX_CLIENT_BITS );
|
||||
id = 0; // bogus
|
||||
active = MSG_ReadOneBit( msg ) ? true : false;
|
||||
}
|
||||
else
|
||||
{
|
||||
slot = MSG_ReadUBitLong( msg, MAX_CLIENT_BITS );
|
||||
id = MSG_ReadLong( msg ); // unique user ID
|
||||
active = MSG_ReadOneBit( msg ) ? true : false;
|
||||
}
|
||||
|
||||
if( slot >= MAX_CLIENTS )
|
||||
Host_Error( "%s: svc_updateuserinfo >= MAX_CLIENTS\n", __func__ );
|
||||
|
||||
player = &cl.players[slot];
|
||||
|
||||
if( !legacy )
|
||||
id = MSG_ReadLong( msg ); // unique user ID
|
||||
else
|
||||
id = 0; // bogus
|
||||
|
||||
active = MSG_ReadOneBit( msg ) ? true : false;
|
||||
|
||||
if( active )
|
||||
{
|
||||
Q_strncpy( player->userinfo, MSG_ReadString( msg ), sizeof( player->userinfo ));
|
||||
@@ -1400,10 +1481,10 @@ void CL_UpdateUserinfo( sizebuf_t *msg, qboolean legacy )
|
||||
player->topcolor = Q_atoi( Info_ValueForKey( player->userinfo, "topcolor" ));
|
||||
player->bottomcolor = Q_atoi( Info_ValueForKey( player->userinfo, "bottomcolor" ));
|
||||
player->spectator = Q_atoi( Info_ValueForKey( player->userinfo, "*hltv" ));
|
||||
if( !legacy )
|
||||
if( proto != PROTO_LEGACY )
|
||||
MSG_ReadBytes( msg, player->hashedcdkey, sizeof( player->hashedcdkey ));
|
||||
|
||||
if( slot == cl.playernum ) memcpy( &gameui.playerinfo, player, sizeof( player_info_t ));
|
||||
if( slot == cl.playernum ) gameui.playerinfo = *player;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1610,7 +1691,7 @@ CL_RegisterResources
|
||||
Clean up and move to next part of sequence.
|
||||
==================
|
||||
*/
|
||||
void CL_RegisterResources( sizebuf_t *msg )
|
||||
void CL_RegisterResources( sizebuf_t *msg, connprotocol_t proto )
|
||||
{
|
||||
model_t *mod;
|
||||
int i;
|
||||
@@ -1672,7 +1753,13 @@ void CL_RegisterResources( sizebuf_t *msg )
|
||||
// done with all resources, issue prespawn command.
|
||||
// Include server count in case server disconnects and changes level during d/l
|
||||
MSG_BeginClientCmd( msg, clc_stringcmd );
|
||||
MSG_WriteStringf( msg, "spawn %i", cl.servercount );
|
||||
if( proto == PROTO_GOLDSRC )
|
||||
{
|
||||
int32_t crc = cl.worldmapCRC;
|
||||
COM_Munge2((byte*)&crc, sizeof( crc ), ( 0xff - cl.servercount ) & 0xff );
|
||||
MSG_WriteStringf( msg, "spawn %i %i", cl.servercount, crc );
|
||||
}
|
||||
else MSG_WriteStringf( msg, "spawn %i", cl.servercount );
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -1682,7 +1769,7 @@ void CL_RegisterResources( sizebuf_t *msg )
|
||||
}
|
||||
}
|
||||
|
||||
static void CL_ParseConsistencyInfo( sizebuf_t *msg )
|
||||
static void CL_ParseConsistencyInfo( sizebuf_t *msg, connprotocol_t proto )
|
||||
{
|
||||
int lastcheck;
|
||||
int delta;
|
||||
@@ -1710,7 +1797,7 @@ static void CL_ParseConsistencyInfo( sizebuf_t *msg )
|
||||
isdelta = MSG_ReadOneBit( msg );
|
||||
|
||||
if( isdelta ) delta = MSG_ReadUBitLong( msg, 5 ) + lastcheck;
|
||||
else delta = MSG_ReadUBitLong( msg, MAX_MODEL_BITS );
|
||||
else delta = MSG_ReadUBitLong( msg, proto == PROTO_GOLDSRC ? MAX_GOLDSRC_MODEL_BITS : MAX_MODEL_BITS );
|
||||
|
||||
skip = delta - lastcheck;
|
||||
|
||||
@@ -1747,12 +1834,12 @@ CL_ParseResourceList
|
||||
|
||||
==============
|
||||
*/
|
||||
static void CL_ParseResourceList( sizebuf_t *msg )
|
||||
void CL_ParseResourceList( sizebuf_t *msg, connprotocol_t proto )
|
||||
{
|
||||
resource_t *pResource;
|
||||
int i, total;
|
||||
|
||||
total = MSG_ReadUBitLong( msg, MAX_RESOURCE_BITS );
|
||||
total = MSG_ReadUBitLong( msg, proto == PROTO_GOLDSRC ? MAX_GOLDSRC_RESOURCE_BITS : MAX_RESOURCE_BITS );
|
||||
|
||||
for( i = 0; i < total; i++ )
|
||||
{
|
||||
@@ -1761,7 +1848,7 @@ static void CL_ParseResourceList( sizebuf_t *msg )
|
||||
|
||||
Q_strncpy( pResource->szFileName, MSG_ReadString( msg ), sizeof( pResource->szFileName ));
|
||||
pResource->nIndex = MSG_ReadUBitLong( msg, MAX_MODEL_BITS );
|
||||
pResource->nDownloadSize = MSG_ReadSBitLong( msg, 24 );
|
||||
pResource->nDownloadSize = MSG_ReadBitLong( msg, 24, proto != PROTO_GOLDSRC );
|
||||
pResource->ucFlags = MSG_ReadUBitLong( msg, 3 ) & ~RES_WASMISSING;
|
||||
|
||||
if( FBitSet( pResource->ucFlags, RES_CUSTOM ))
|
||||
@@ -1773,7 +1860,7 @@ static void CL_ParseResourceList( sizebuf_t *msg )
|
||||
CL_AddToResourceList( pResource, &cl.resourcesneeded );
|
||||
}
|
||||
|
||||
CL_ParseConsistencyInfo( msg );
|
||||
CL_ParseConsistencyInfo( msg, proto );
|
||||
|
||||
CL_StartResourceDownloading( "Verifying and downloading resources...\n", false );
|
||||
}
|
||||
@@ -1784,7 +1871,7 @@ CL_ParseVoiceInit
|
||||
|
||||
==================
|
||||
*/
|
||||
static void CL_ParseVoiceInit( sizebuf_t *msg )
|
||||
void CL_ParseVoiceInit( sizebuf_t *msg )
|
||||
{
|
||||
char *pszCodec = MSG_ReadString( msg );
|
||||
int quality = MSG_ReadByte( msg );
|
||||
@@ -1798,7 +1885,7 @@ CL_ParseVoiceData
|
||||
|
||||
==================
|
||||
*/
|
||||
static void CL_ParseVoiceData( sizebuf_t *msg )
|
||||
void CL_ParseVoiceData( sizebuf_t *msg )
|
||||
{
|
||||
int size, idx, frames;
|
||||
byte received[8192];
|
||||
@@ -2045,7 +2132,7 @@ CL_ParseExec
|
||||
Exec map/class specific configs
|
||||
==============
|
||||
*/
|
||||
static void CL_ParseExec( sizebuf_t *msg )
|
||||
void CL_ParseExec( sizebuf_t *msg )
|
||||
{
|
||||
qboolean is_class;
|
||||
int class_idx;
|
||||
@@ -2268,7 +2355,7 @@ void CL_ParseServerMessage( sizebuf_t *msg )
|
||||
Host_AbortCurrentFrame ();
|
||||
break;
|
||||
case svc_event:
|
||||
CL_ParseEvent( msg );
|
||||
CL_ParseEvent( msg, PROTO_CURRENT );
|
||||
cl.frames[cl.parsecountmod].graphdata.event += MSG_GetNumBytesRead( msg ) - bufStart;
|
||||
break;
|
||||
case svc_changing:
|
||||
@@ -2343,19 +2430,19 @@ void CL_ParseServerMessage( sizebuf_t *msg )
|
||||
break;
|
||||
case svc_serverdata:
|
||||
Cbuf_Execute(); // make sure any stuffed commands are done
|
||||
CL_ParseServerData( msg, false );
|
||||
CL_ParseServerData( msg, PROTO_CURRENT );
|
||||
break;
|
||||
case svc_lightstyle:
|
||||
CL_ParseLightStyle( msg );
|
||||
CL_ParseLightStyle( msg, PROTO_CURRENT );
|
||||
break;
|
||||
case svc_updateuserinfo:
|
||||
CL_UpdateUserinfo( msg, false );
|
||||
CL_UpdateUserinfo( msg, PROTO_CURRENT );
|
||||
break;
|
||||
case svc_deltatable:
|
||||
Delta_ParseTableField( msg );
|
||||
break;
|
||||
case svc_clientdata:
|
||||
CL_ParseClientData( msg );
|
||||
CL_ParseClientData( msg, PROTO_CURRENT );
|
||||
cl.frames[cl.parsecountmod].graphdata.client += MSG_GetNumBytesRead( msg ) - bufStart;
|
||||
break;
|
||||
case svc_resource:
|
||||
@@ -2375,21 +2462,21 @@ void CL_ParseServerMessage( sizebuf_t *msg )
|
||||
CL_ParseStaticEntity( msg );
|
||||
break;
|
||||
case svc_event_reliable:
|
||||
CL_ParseReliableEvent( msg );
|
||||
CL_ParseReliableEvent( msg, PROTO_CURRENT );
|
||||
cl.frames[cl.parsecountmod].graphdata.event += MSG_GetNumBytesRead( msg ) - bufStart;
|
||||
break;
|
||||
case svc_spawnbaseline:
|
||||
CL_ParseBaseline( msg, false );
|
||||
CL_ParseBaseline( msg, PROTO_CURRENT );
|
||||
break;
|
||||
case svc_temp_entity:
|
||||
CL_ParseTempEntity( msg );
|
||||
CL_ParseTempEntity( msg, PROTO_CURRENT );
|
||||
cl.frames[cl.parsecountmod].graphdata.tentities += MSG_GetNumBytesRead( msg ) - bufStart;
|
||||
break;
|
||||
case svc_setpause:
|
||||
cl.paused = ( MSG_ReadOneBit( msg ) != 0 );
|
||||
break;
|
||||
case svc_signonnum:
|
||||
CL_ParseSignon( msg );
|
||||
CL_ParseSignon( msg, PROTO_CURRENT );
|
||||
break;
|
||||
case svc_centerprint:
|
||||
CL_CenterPrint( MSG_ReadString( msg ), 0.25f );
|
||||
@@ -2432,12 +2519,12 @@ void CL_ParseServerMessage( sizebuf_t *msg )
|
||||
CL_RegisterUserMessage( msg );
|
||||
break;
|
||||
case svc_packetentities:
|
||||
playerbytes = CL_ParsePacketEntities( msg, false );
|
||||
playerbytes = CL_ParsePacketEntities( msg, false, PROTO_CURRENT );
|
||||
cl.frames[cl.parsecountmod].graphdata.players += playerbytes;
|
||||
cl.frames[cl.parsecountmod].graphdata.entities += MSG_GetNumBytesRead( msg ) - bufStart - playerbytes;
|
||||
break;
|
||||
case svc_deltapacketentities:
|
||||
playerbytes = CL_ParsePacketEntities( msg, true );
|
||||
playerbytes = CL_ParsePacketEntities( msg, true, PROTO_CURRENT );
|
||||
cl.frames[cl.parsecountmod].graphdata.players += playerbytes;
|
||||
cl.frames[cl.parsecountmod].graphdata.entities += MSG_GetNumBytesRead( msg ) - bufStart - playerbytes;
|
||||
break;
|
||||
@@ -2446,7 +2533,7 @@ void CL_ParseServerMessage( sizebuf_t *msg )
|
||||
cl.frames[cls.netchan.incoming_sequence & CL_UPDATE_MASK].receivedtime = -2.0;
|
||||
break;
|
||||
case svc_resourcelist:
|
||||
CL_ParseResourceList( msg );
|
||||
CL_ParseResourceList( msg, PROTO_CURRENT );
|
||||
break;
|
||||
case svc_deltamovevars:
|
||||
CL_ParseMovevars( msg );
|
||||
|
||||
+12
-17
@@ -359,7 +359,7 @@ void CL_ParseLegacyServerMessage( sizebuf_t *msg )
|
||||
Host_AbortCurrentFrame ();
|
||||
break;
|
||||
case svc_legacy_event:
|
||||
CL_ParseEvent( msg );
|
||||
CL_ParseEvent( msg, PROTO_LEGACY );
|
||||
cl.frames[cl.parsecountmod].graphdata.event += MSG_GetNumBytesRead( msg ) - bufStart;
|
||||
break;
|
||||
case svc_legacy_changing:
|
||||
@@ -446,19 +446,19 @@ void CL_ParseLegacyServerMessage( sizebuf_t *msg )
|
||||
break;
|
||||
case svc_serverdata:
|
||||
Cbuf_Execute(); // make sure any stuffed commands are done
|
||||
CL_ParseServerData( msg, true );
|
||||
CL_ParseServerData( msg, PROTO_LEGACY );
|
||||
break;
|
||||
case svc_lightstyle:
|
||||
CL_ParseLightStyle( msg );
|
||||
CL_ParseLightStyle( msg, PROTO_LEGACY );
|
||||
break;
|
||||
case svc_updateuserinfo:
|
||||
CL_UpdateUserinfo( msg, true );
|
||||
CL_UpdateUserinfo( msg, PROTO_LEGACY );
|
||||
break;
|
||||
case svc_deltatable:
|
||||
Delta_ParseTableField( msg );
|
||||
break;
|
||||
case svc_clientdata:
|
||||
CL_ParseClientData( msg );
|
||||
CL_ParseClientData( msg, PROTO_LEGACY );
|
||||
cl.frames[cl.parsecountmod].graphdata.client += MSG_GetNumBytesRead( msg ) - bufStart;
|
||||
break;
|
||||
case svc_resource:
|
||||
@@ -478,21 +478,21 @@ void CL_ParseLegacyServerMessage( sizebuf_t *msg )
|
||||
CL_LegacyParseStaticEntity( msg );
|
||||
break;
|
||||
case svc_event_reliable:
|
||||
CL_ParseReliableEvent( msg );
|
||||
CL_ParseReliableEvent( msg, PROTO_LEGACY );
|
||||
cl.frames[cl.parsecountmod].graphdata.event += MSG_GetNumBytesRead( msg ) - bufStart;
|
||||
break;
|
||||
case svc_spawnbaseline:
|
||||
CL_ParseBaseline( msg, true );
|
||||
CL_ParseBaseline( msg, PROTO_LEGACY );
|
||||
break;
|
||||
case svc_temp_entity:
|
||||
CL_ParseTempEntity( msg );
|
||||
CL_ParseTempEntity( msg, PROTO_LEGACY );
|
||||
cl.frames[cl.parsecountmod].graphdata.tentities += MSG_GetNumBytesRead( msg ) - bufStart;
|
||||
break;
|
||||
case svc_setpause:
|
||||
cl.paused = ( MSG_ReadOneBit( msg ) != 0 );
|
||||
break;
|
||||
case svc_signonnum:
|
||||
CL_ParseSignon( msg );
|
||||
CL_ParseSignon( msg, PROTO_LEGACY );
|
||||
break;
|
||||
case svc_centerprint:
|
||||
CL_CenterPrint( MSG_ReadString( msg ), 0.25f );
|
||||
@@ -538,12 +538,12 @@ void CL_ParseLegacyServerMessage( sizebuf_t *msg )
|
||||
CL_RegisterUserMessage( msg );
|
||||
break;
|
||||
case svc_packetentities:
|
||||
playerbytes = CL_ParsePacketEntities( msg, false );
|
||||
playerbytes = CL_ParsePacketEntities( msg, false, PROTO_LEGACY );
|
||||
cl.frames[cl.parsecountmod].graphdata.players += playerbytes;
|
||||
cl.frames[cl.parsecountmod].graphdata.entities += MSG_GetNumBytesRead( msg ) - bufStart - playerbytes;
|
||||
break;
|
||||
case svc_deltapacketentities:
|
||||
playerbytes = CL_ParsePacketEntities( msg, true );
|
||||
playerbytes = CL_ParsePacketEntities( msg, true, PROTO_LEGACY );
|
||||
cl.frames[cl.parsecountmod].graphdata.players += playerbytes;
|
||||
cl.frames[cl.parsecountmod].graphdata.entities += MSG_GetNumBytesRead( msg ) - bufStart - playerbytes;
|
||||
break;
|
||||
@@ -656,10 +656,5 @@ void CL_LegacyPrecache_f( void )
|
||||
// Include server count in case server disconnects and changes level during d/l
|
||||
MSG_BeginClientCmd( &cls.netchan.message, clc_stringcmd );
|
||||
MSG_WriteStringf( &cls.netchan.message, "begin %i", spawncount );
|
||||
cls.signon = SIGNONS;
|
||||
}
|
||||
|
||||
qboolean CL_LegacyMode( void )
|
||||
{
|
||||
return cls.legacymode == PROTO_LEGACY;
|
||||
cls.signon = SIGNONS - 1;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,761 @@
|
||||
/*
|
||||
cl_parse.c - parse a message received from the server (GoldSrc 48 protocol)
|
||||
Copyright (C) 2008 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 "client.h"
|
||||
#include "net_encode.h"
|
||||
#include "particledef.h"
|
||||
#include "cl_tent.h"
|
||||
#include "shake.h"
|
||||
#include "hltv.h"
|
||||
#include "input.h"
|
||||
#include "server.h"
|
||||
|
||||
static void CL_ParseExtraInfo( sizebuf_t *msg )
|
||||
{
|
||||
string clientfallback;
|
||||
|
||||
Q_strncpy( clientfallback, MSG_ReadString( msg ), sizeof( clientfallback ));
|
||||
Cvar_FullSet( "sv_cheats", MSG_ReadByte( msg ) ? "1" : "0", FCVAR_READ_ONLY | FCVAR_SERVER );
|
||||
}
|
||||
|
||||
static void CL_ParseNewMovevars( sizebuf_t *msg )
|
||||
{
|
||||
Delta_InitClient(); // finalize client delta's
|
||||
|
||||
clgame.movevars.gravity = MSG_ReadFloat( msg );
|
||||
clgame.movevars.stopspeed = MSG_ReadFloat( msg );
|
||||
clgame.movevars.maxspeed = MSG_ReadFloat( msg );
|
||||
clgame.movevars.spectatormaxspeed = MSG_ReadFloat( msg );
|
||||
clgame.movevars.accelerate = MSG_ReadFloat( msg );
|
||||
clgame.movevars.airaccelerate = MSG_ReadFloat( msg );
|
||||
clgame.movevars.wateraccelerate = MSG_ReadFloat( msg );
|
||||
clgame.movevars.friction = MSG_ReadFloat( msg );
|
||||
clgame.movevars.edgefriction = MSG_ReadFloat( msg );
|
||||
clgame.movevars.waterfriction = MSG_ReadFloat( msg );
|
||||
clgame.movevars.entgravity = MSG_ReadFloat( msg );
|
||||
clgame.movevars.bounce = MSG_ReadFloat( msg );
|
||||
clgame.movevars.stepsize = MSG_ReadFloat( msg );
|
||||
clgame.movevars.maxvelocity = MSG_ReadFloat( msg );
|
||||
clgame.movevars.zmax = MSG_ReadFloat( msg );
|
||||
clgame.movevars.waveHeight = MSG_ReadFloat( msg );
|
||||
clgame.movevars.footsteps = MSG_ReadByte( msg );
|
||||
clgame.movevars.rollangle = MSG_ReadFloat( msg );
|
||||
clgame.movevars.rollspeed = MSG_ReadFloat( msg );
|
||||
clgame.movevars.skycolor_r = MSG_ReadFloat( msg );
|
||||
clgame.movevars.skycolor_g = MSG_ReadFloat( msg );
|
||||
clgame.movevars.skycolor_b = MSG_ReadFloat( msg );
|
||||
clgame.movevars.skyvec_x = MSG_ReadFloat( msg );
|
||||
clgame.movevars.skyvec_y = MSG_ReadFloat( msg );
|
||||
clgame.movevars.skyvec_z = MSG_ReadFloat( msg );
|
||||
|
||||
Q_strncpy( clgame.movevars.skyName, MSG_ReadString( msg ), sizeof( clgame.movevars.skyName ));
|
||||
|
||||
// water alpha is not allowed
|
||||
if( !FBitSet( world.flags, FWORLD_WATERALPHA ))
|
||||
clgame.movevars.wateralpha = 1.0f;
|
||||
|
||||
// update sky if changed
|
||||
if( Q_strcmp( clgame.oldmovevars.skyName, clgame.movevars.skyName ) && cl.video_prepped )
|
||||
R_SetupSky( clgame.movevars.skyName );
|
||||
|
||||
memcpy( &clgame.oldmovevars, &clgame.movevars, sizeof( movevars_t ));
|
||||
clgame.entities->curstate.scale = clgame.movevars.waveHeight;
|
||||
|
||||
// keep features an actual!
|
||||
clgame.oldmovevars.features = clgame.movevars.features = host.features;
|
||||
}
|
||||
|
||||
static void CL_ParseNewUserMsg( sizebuf_t *msg )
|
||||
{
|
||||
int svc_num, size;
|
||||
char s[16];
|
||||
|
||||
svc_num = MSG_ReadByte( msg );
|
||||
size = MSG_ReadByte( msg );
|
||||
MSG_ReadBytes( msg, s, sizeof( s ));
|
||||
|
||||
s[15] = 0;
|
||||
if( size == 255 )
|
||||
size = -1;
|
||||
|
||||
CL_LinkUserMessage( s, svc_num, size );
|
||||
}
|
||||
|
||||
typedef struct delta_header_t
|
||||
{
|
||||
qboolean remove : 1;
|
||||
qboolean custom : 1;
|
||||
qboolean instanced : 1;
|
||||
uint instanced_baseline_index : 6;
|
||||
uint offset : 6;
|
||||
} delta_header_t;
|
||||
|
||||
static int CL_ParseDeltaHeader( sizebuf_t *msg, qboolean delta, int oldnum, struct delta_header_t *hdr )
|
||||
{
|
||||
int entnum;
|
||||
|
||||
hdr->remove = hdr->custom = hdr->instanced = false;
|
||||
hdr->instanced_baseline_index = hdr->offset = 0;
|
||||
entnum = oldnum;
|
||||
|
||||
if( !delta )
|
||||
{
|
||||
// if we have one bit set, then it's a next entity in line
|
||||
// if we have next bit NON set, then it's a one of next 64 entities
|
||||
// if not, it's a new entity
|
||||
if( MSG_ReadOneBit( msg ))
|
||||
entnum++;
|
||||
else if( MSG_ReadOneBit( msg ) == 0 )
|
||||
entnum += MSG_ReadUBitLong( msg, 6 );
|
||||
else
|
||||
entnum += MSG_ReadUBitLong( msg, MAX_GOLDSRC_ENTITY_BITS );
|
||||
}
|
||||
else
|
||||
{
|
||||
// does this packet encode entity deletion?
|
||||
hdr->remove = MSG_ReadOneBit( msg );
|
||||
|
||||
// same logic as above
|
||||
if( MSG_ReadOneBit( msg ) == 0 )
|
||||
entnum += MSG_ReadUBitLong( msg, 6 );
|
||||
else entnum = MSG_ReadUBitLong( msg, MAX_GOLDSRC_ENTITY_BITS );
|
||||
}
|
||||
|
||||
// if we are not removing this entity
|
||||
if( !hdr->remove )
|
||||
{
|
||||
hdr->custom = MSG_ReadOneBit( msg );
|
||||
|
||||
hdr->instanced = false;
|
||||
hdr->instanced_baseline_index = 0;
|
||||
|
||||
// do we got instanced baselines in svc_spawnbaselines?
|
||||
if( cl.instanced_baseline_count )
|
||||
{
|
||||
hdr->instanced = MSG_ReadOneBit( msg );
|
||||
if( hdr->instanced )
|
||||
hdr->instanced_baseline_index = MSG_ReadUBitLong( msg, 6 );
|
||||
}
|
||||
|
||||
hdr->offset = 0;
|
||||
if( !delta && !hdr->instanced )
|
||||
{
|
||||
if( MSG_ReadOneBit( msg ))
|
||||
hdr->offset = MSG_ReadUBitLong( msg, 6 );
|
||||
}
|
||||
}
|
||||
|
||||
return entnum;
|
||||
}
|
||||
|
||||
static int CL_GetEntityDelta( const struct delta_header_t *hdr, int entnum )
|
||||
{
|
||||
if( hdr->custom )
|
||||
return DT_CUSTOM_ENTITY_STATE_T;
|
||||
|
||||
if( CL_IsPlayerIndex( entnum ))
|
||||
return DT_ENTITY_STATE_PLAYER_T;
|
||||
|
||||
return DT_ENTITY_STATE_T;
|
||||
}
|
||||
|
||||
static void CL_FlushEntityPacketGS( frame_t *frame, sizebuf_t *msg )
|
||||
{
|
||||
frame->valid = false;
|
||||
cl.validsequence = 0; // can't render a frame
|
||||
|
||||
// read it all but ignore it
|
||||
while( 1 )
|
||||
{
|
||||
int num = 0;
|
||||
entity_state_t from = { 0 }, to;
|
||||
delta_header_t hdr;
|
||||
|
||||
if( MSG_ReadWord( msg ) != 0 )
|
||||
{
|
||||
MSG_SeekToBit( msg, -16, SEEK_CUR );
|
||||
|
||||
num = CL_ParseDeltaHeader( msg, false, num, &hdr );
|
||||
}
|
||||
else break;
|
||||
|
||||
if( MSG_CheckOverflow( msg ))
|
||||
Host_Error( "%s: overflow\n", __func__ );
|
||||
|
||||
if( hdr.remove )
|
||||
continue;
|
||||
|
||||
Delta_ReadGSFields( msg, CL_GetEntityDelta( &hdr, num ), &from, &to, cl.mtime[0] );
|
||||
}
|
||||
|
||||
MSG_EndBitWriting( msg );
|
||||
}
|
||||
|
||||
static void CL_DeltaEntityGS( const delta_header_t *hdr, sizebuf_t *msg, frame_t *frame, int newnum, entity_state_t *from, qboolean has_update )
|
||||
{
|
||||
cl_entity_t *ent;
|
||||
entity_state_t *to;
|
||||
qboolean newent = from == NULL;
|
||||
int pack = frame->num_entities;
|
||||
|
||||
// alloc next slot to store update
|
||||
to = &cls.packet_entities[cls.next_client_entities % cls.num_client_entities];
|
||||
|
||||
if(( newnum < 0 ) || ( newnum >= clgame.maxEntities ))
|
||||
{
|
||||
Con_DPrintf( S_ERROR "CL_DeltaEntity: invalid newnum: %d\n", newnum );
|
||||
Host_Error( "%s: bad delta entity number: %i", __func__, newnum );
|
||||
return;
|
||||
}
|
||||
|
||||
ent = CL_EDICT_NUM( newnum );
|
||||
if( hdr->remove )
|
||||
{
|
||||
if( !newent )
|
||||
CL_KillDeadBeams( ent );
|
||||
return;
|
||||
}
|
||||
|
||||
ent->index = newnum; // enumerate entity index
|
||||
if( newent )
|
||||
{
|
||||
if( hdr->instanced )
|
||||
from = &cl.instanced_baseline[hdr->instanced_baseline_index];
|
||||
else if( hdr->offset != 0 )
|
||||
from = &cls.packet_entities[(cls.next_client_entities - hdr->offset) % cls.num_client_entities];
|
||||
else
|
||||
from = &ent->baseline;
|
||||
}
|
||||
|
||||
if( has_update )
|
||||
Delta_ReadGSFields( msg, CL_GetEntityDelta( hdr, newnum ), from, to, cl.mtime[0] );
|
||||
else memcpy( to, from, sizeof( entity_state_t ));
|
||||
|
||||
to->entityType = hdr->custom ? ENTITY_BEAM : ENTITY_NORMAL;
|
||||
to->number = newnum;
|
||||
|
||||
if( newent )
|
||||
{
|
||||
// interpolation must be reset
|
||||
SETVISBIT( frame->flags, pack );
|
||||
|
||||
// release beams from previous entity
|
||||
CL_KillDeadBeams( ent );
|
||||
}
|
||||
|
||||
// add entity to packet
|
||||
cls.next_client_entities++;
|
||||
frame->num_entities++;
|
||||
}
|
||||
|
||||
static void CL_CopyPacketEntity( frame_t *frame, int num, entity_state_t *from )
|
||||
{
|
||||
delta_header_t fakehdr =
|
||||
{
|
||||
.custom = FBitSet( from->entityType, ENTITY_BEAM ) == ENTITY_BEAM,
|
||||
};
|
||||
CL_DeltaEntityGS( &fakehdr, NULL, frame, num, from, false );
|
||||
}
|
||||
|
||||
static int CL_ParsePacketEntitiesGS( sizebuf_t *msg, qboolean delta )
|
||||
{
|
||||
frame_t *frame, *oldframe;
|
||||
int oldindex, newnum, oldnum, numbase = 0;
|
||||
entity_state_t *oldent;
|
||||
int count;
|
||||
int playerbytes = 0;
|
||||
|
||||
// save first uncompressed packet as timestamp
|
||||
if( cls.changelevel && !delta && cls.demorecording )
|
||||
CL_WriteDemoJumpTime();
|
||||
|
||||
count = MSG_ReadWord( msg );
|
||||
|
||||
frame = &cl.frames[cl.parsecountmod];
|
||||
memset( frame->flags, 0, sizeof( frame->flags ));
|
||||
frame->first_entity = cls.next_client_entities;
|
||||
frame->num_entities = 0;
|
||||
frame->valid = true;
|
||||
|
||||
MSG_StartBitWriting( msg );
|
||||
|
||||
if( delta )
|
||||
{
|
||||
uint oldpacket = MSG_ReadByte( msg );
|
||||
oldframe = &cl.frames[oldpacket & CL_UPDATE_MASK];
|
||||
|
||||
if( !CL_ValidateDeltaPacket( oldpacket, oldframe ))
|
||||
{
|
||||
CL_FlushEntityPacketGS( frame, msg );
|
||||
return playerbytes;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
oldframe = NULL;
|
||||
cl.send_reply = true;
|
||||
cls.demowaiting = false;
|
||||
}
|
||||
|
||||
cl.validsequence = cls.netchan.incoming_sequence;
|
||||
|
||||
oldent = NULL;
|
||||
oldindex = 0;
|
||||
oldnum = CL_UpdateOldEntNum( oldindex, oldframe, &oldent );
|
||||
|
||||
// read it all but ignore it
|
||||
while( 1 )
|
||||
{
|
||||
int bufstart;
|
||||
qboolean player;
|
||||
delta_header_t hdr;
|
||||
int val = MSG_ReadWord( msg );
|
||||
|
||||
if( val )
|
||||
{
|
||||
MSG_SeekToBit( msg, -16, SEEK_CUR );
|
||||
numbase = newnum = CL_ParseDeltaHeader( msg, delta, numbase, &hdr );
|
||||
}
|
||||
else break;
|
||||
|
||||
if( MSG_CheckOverflow( msg ))
|
||||
Host_Error( "%s: overflow\n", __func__ );
|
||||
|
||||
player = CL_IsPlayerIndex( newnum );
|
||||
|
||||
while( oldnum < newnum )
|
||||
{
|
||||
// one or more entities from the old packet are unchanged
|
||||
CL_CopyPacketEntity( frame, oldnum, oldent );
|
||||
oldnum = CL_UpdateOldEntNum( ++oldindex, oldframe, &oldent );
|
||||
}
|
||||
|
||||
bufstart = MSG_GetNumBytesRead( msg );
|
||||
|
||||
if( oldnum == newnum )
|
||||
{
|
||||
// from delta
|
||||
CL_DeltaEntityGS( &hdr, msg, frame, newnum, oldent, true );
|
||||
oldnum = CL_UpdateOldEntNum( ++oldindex, oldframe, &oldent );
|
||||
}
|
||||
else if( oldnum > newnum )
|
||||
{
|
||||
// from baseline
|
||||
CL_DeltaEntityGS( &hdr, msg, frame, newnum, NULL, true );
|
||||
}
|
||||
|
||||
if( player ) playerbytes += MSG_GetNumBytesRead( msg ) - bufstart;
|
||||
}
|
||||
|
||||
if( MSG_CheckOverflow( msg ))
|
||||
Host_Error( "%s: overflow\n", __func__ );
|
||||
|
||||
// any remaining entities in the old frame are copied over
|
||||
while( oldnum != MAX_ENTNUMBER )
|
||||
{
|
||||
// one or more entities from the old packet are unchanged
|
||||
CL_CopyPacketEntity( frame, oldnum, oldent );
|
||||
oldnum = CL_UpdateOldEntNum( ++oldindex, oldframe, &oldent );
|
||||
}
|
||||
|
||||
MSG_EndBitWriting( msg );
|
||||
|
||||
if( frame->num_entities != count )
|
||||
Con_Reportf( S_WARN "CL_Parse%sPacketEntitiesGS: (%i should be %i)\n", delta ? "Delta" : "", frame->num_entities, count );
|
||||
|
||||
if( !frame->valid )
|
||||
return playerbytes;
|
||||
|
||||
CL_ProcessPacket( frame );
|
||||
CL_SetSolidEntities();
|
||||
|
||||
// first update is the final signon stage where we actually receive an entity (i.e., the world at least)
|
||||
if( cls.signon == ( SIGNONS - 1 ))
|
||||
{
|
||||
// we are done with signon sequence.
|
||||
cls.signon = SIGNONS;
|
||||
|
||||
// Clear loading plaque.
|
||||
CL_SignonReply( PROTO_GOLDSRC );
|
||||
}
|
||||
|
||||
return playerbytes;
|
||||
}
|
||||
|
||||
static float MSG_ReadGSBitCoord( sizebuf_t *sb )
|
||||
{
|
||||
float value = 0;
|
||||
int ival, fval;
|
||||
|
||||
ival = MSG_ReadOneBit( sb );
|
||||
fval = MSG_ReadOneBit( sb );
|
||||
|
||||
if( ival || fval )
|
||||
{
|
||||
int sign = MSG_ReadOneBit( sb );
|
||||
|
||||
if( ival )
|
||||
ival = MSG_ReadUBitLong( sb, 12 );
|
||||
if( fval )
|
||||
fval = MSG_ReadUBitLong( sb, 3 );
|
||||
|
||||
value = (float)( fval / 8.0 + ival );
|
||||
if( sign )
|
||||
value = -value;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
static void MSG_ReadGSBitVec3Coord( sizebuf_t *sb, vec3_t fa )
|
||||
{
|
||||
qboolean x, y, z;
|
||||
|
||||
VectorClear( fa );
|
||||
|
||||
x = MSG_ReadOneBit( sb );
|
||||
y = MSG_ReadOneBit( sb );
|
||||
z = MSG_ReadOneBit( sb );
|
||||
if( x )
|
||||
fa[0] = MSG_ReadGSBitCoord( sb );
|
||||
if( y )
|
||||
fa[1] = MSG_ReadGSBitCoord( sb );
|
||||
if( z )
|
||||
fa[2] = MSG_ReadGSBitCoord( sb );
|
||||
}
|
||||
|
||||
static void CL_ParseSoundPacketGS( sizebuf_t *msg )
|
||||
{
|
||||
vec3_t pos;
|
||||
int chan, sound;
|
||||
float volume, attn;
|
||||
int flags, pitch, entnum;
|
||||
sound_t handle = 0;
|
||||
|
||||
MSG_StartBitWriting( msg );
|
||||
|
||||
flags = MSG_ReadUBitLong( msg, 9 );
|
||||
|
||||
if( FBitSet( flags, SND_VOLUME ))
|
||||
volume = (float)MSG_ReadByte( msg ) / 255.0f;
|
||||
else volume = VOL_NORM;
|
||||
|
||||
if( FBitSet( flags, SND_ATTENUATION ))
|
||||
attn = (float)MSG_ReadByte( msg ) / 64.0f;
|
||||
else attn = ATTN_NONE;
|
||||
|
||||
chan = MSG_ReadUBitLong( msg, 3 );
|
||||
entnum = MSG_ReadUBitLong( msg, MAX_GOLDSRC_ENTITY_BITS );
|
||||
sound = MSG_ReadUBitLong( msg, FBitSet( flags, SND_SEQUENCE ) ? 16 : 8 );
|
||||
MSG_ReadGSBitVec3Coord( msg, pos );
|
||||
|
||||
if( FBitSet( flags, SND_PITCH ))
|
||||
pitch = MSG_ReadByte( msg );
|
||||
else pitch = PITCH_NORM;
|
||||
|
||||
MSG_EndBitWriting( msg );
|
||||
|
||||
if( FBitSet( flags, SND_SENTENCE ))
|
||||
{
|
||||
char sentenceName[32];
|
||||
|
||||
if( FBitSet( flags, SND_SEQUENCE ))
|
||||
Q_snprintf( sentenceName, sizeof( sentenceName ), "!#%i", sound + MAX_SOUNDS_NONSENTENCE );
|
||||
else Q_snprintf( sentenceName, sizeof( sentenceName ), "!%i", sound );
|
||||
|
||||
handle = S_RegisterSound( sentenceName );
|
||||
}
|
||||
else handle = cl.sound_index[sound]; // see precached sound
|
||||
|
||||
if( !cl.audio_prepped )
|
||||
return; // too early
|
||||
|
||||
// g-cont. sound and ambient sound have only difference with channel
|
||||
if( chan == CHAN_STATIC )
|
||||
{
|
||||
S_AmbientSound( pos, entnum, handle, volume, attn, pitch, flags );
|
||||
}
|
||||
else
|
||||
{
|
||||
S_StartSound( pos, entnum, chan, handle, volume, attn, pitch, flags );
|
||||
}
|
||||
}
|
||||
|
||||
static void CL_ParseSpawnStaticSound( sizebuf_t *msg )
|
||||
{
|
||||
vec3_t pos;
|
||||
int handle, entnum, pitch, flags;
|
||||
float volume, attn;
|
||||
|
||||
MSG_ReadVec3Coord( msg, pos );
|
||||
handle = MSG_ReadShort( msg );
|
||||
volume = MSG_ReadByte( msg ) * ( 1.0f / 255.0f );
|
||||
attn = MSG_ReadByte( msg ) * ( 1.0f / 64.0f );
|
||||
entnum = MSG_ReadShort( msg );
|
||||
pitch = MSG_ReadByte( msg );
|
||||
flags = MSG_ReadByte( msg );
|
||||
|
||||
S_AmbientSound( pos, entnum, handle, volume, attn, pitch, flags );
|
||||
}
|
||||
|
||||
/*
|
||||
=====================================================================
|
||||
|
||||
ACTION MESSAGES
|
||||
|
||||
=====================================================================
|
||||
*/
|
||||
/*
|
||||
=====================
|
||||
CL_ParseGoldSrcServerMessage
|
||||
|
||||
dispatch messages
|
||||
=====================
|
||||
*/
|
||||
void CL_ParseGoldSrcServerMessage( sizebuf_t *msg )
|
||||
{
|
||||
size_t bufStart, playerbytes;
|
||||
int cmd, param1, param2;
|
||||
int old_background;
|
||||
const char *s;
|
||||
|
||||
// parse the message
|
||||
while( 1 )
|
||||
{
|
||||
if( MSG_CheckOverflow( msg ))
|
||||
{
|
||||
Host_Error( "CL_ParseServerMessage: overflow!\n" );
|
||||
return;
|
||||
}
|
||||
|
||||
// mark start position
|
||||
bufStart = MSG_GetNumBytesRead( msg );
|
||||
|
||||
// end of message (align bits)
|
||||
if( MSG_GetNumBitsLeft( msg ) < 8 )
|
||||
break;
|
||||
|
||||
cmd = MSG_ReadServerCmd( msg );
|
||||
|
||||
// record command for debugging spew on parse problem
|
||||
CL_Parse_RecordCommand( cmd, bufStart );
|
||||
|
||||
// other commands
|
||||
switch( cmd )
|
||||
{
|
||||
case svc_bad:
|
||||
Host_Error( "svc_bad\n" );
|
||||
break;
|
||||
case svc_nop:
|
||||
// this does nothing
|
||||
break;
|
||||
case svc_disconnect:
|
||||
CL_Drop ();
|
||||
Host_AbortCurrentFrame ();
|
||||
break;
|
||||
case svc_event:
|
||||
MSG_StartBitWriting( msg );
|
||||
CL_ParseEvent( msg, PROTO_GOLDSRC );
|
||||
MSG_EndBitWriting( msg );
|
||||
cl.frames[cl.parsecountmod].graphdata.event += MSG_GetNumBytesRead( msg ) - bufStart;
|
||||
break;
|
||||
case svc_setview:
|
||||
CL_ParseViewEntity( msg );
|
||||
break;
|
||||
case svc_sound:
|
||||
CL_ParseSoundPacketGS( msg );
|
||||
cl.frames[cl.parsecountmod].graphdata.sound += MSG_GetNumBytesRead( msg ) - bufStart;
|
||||
break;
|
||||
case svc_time:
|
||||
CL_ParseServerTime( msg );
|
||||
break;
|
||||
case svc_print:
|
||||
Con_Printf( "%s", MSG_ReadString( msg ));
|
||||
break;
|
||||
case svc_stufftext:
|
||||
s = MSG_ReadString( msg );
|
||||
#ifdef HACKS_RELATED_HLMODS
|
||||
// disable Cry Of Fear antisave protection
|
||||
if( !Q_strnicmp( s, "disconnect", 10 ) && cls.signon != SIGNONS )
|
||||
break; // too early
|
||||
#endif
|
||||
Cbuf_AddFilteredText( s );
|
||||
break;
|
||||
case svc_setangle:
|
||||
CL_ParseSetAngle( msg );
|
||||
break;
|
||||
case svc_goldsrc_serverinfo:
|
||||
Cbuf_Execute(); // make sure any stuffed commands are done
|
||||
CL_ParseServerData( msg, PROTO_GOLDSRC );
|
||||
Delta_InitMeta();
|
||||
break;
|
||||
case svc_lightstyle:
|
||||
CL_ParseLightStyle( msg, PROTO_GOLDSRC );
|
||||
break;
|
||||
case svc_updateuserinfo:
|
||||
CL_UpdateUserinfo( msg, PROTO_GOLDSRC );
|
||||
break;
|
||||
case svc_goldsrc_deltadescription:
|
||||
Delta_ParseTableField_GS( msg );
|
||||
break;
|
||||
case svc_clientdata:
|
||||
MSG_StartBitWriting( msg );
|
||||
CL_ParseClientData( msg, PROTO_GOLDSRC );
|
||||
MSG_EndBitWriting( msg );
|
||||
cl.frames[cl.parsecountmod].graphdata.client += MSG_GetNumBytesRead( msg ) - bufStart;
|
||||
break;
|
||||
case svc_pings:
|
||||
MSG_StartBitWriting( msg );
|
||||
CL_UpdateUserPings( msg );
|
||||
MSG_EndBitWriting( msg );
|
||||
break;
|
||||
case svc_particle:
|
||||
CL_ParseParticles( msg );
|
||||
break;
|
||||
case svc_spawnstatic:
|
||||
CL_ParseStaticEntity( msg );
|
||||
break;
|
||||
case svc_event_reliable:
|
||||
MSG_StartBitWriting( msg );
|
||||
CL_ParseReliableEvent( msg, PROTO_GOLDSRC );
|
||||
MSG_EndBitWriting( msg );
|
||||
cl.frames[cl.parsecountmod].graphdata.event += MSG_GetNumBytesRead( msg ) - bufStart;
|
||||
break;
|
||||
case svc_spawnbaseline:
|
||||
CL_ParseBaseline( msg, PROTO_GOLDSRC );
|
||||
break;
|
||||
case svc_temp_entity:
|
||||
CL_ParseTempEntity( msg, PROTO_GOLDSRC );
|
||||
cl.frames[cl.parsecountmod].graphdata.tentities += MSG_GetNumBytesRead( msg ) - bufStart;
|
||||
break;
|
||||
case svc_setpause:
|
||||
cl.paused = ( MSG_ReadOneBit( msg ) != 0 );
|
||||
break;
|
||||
case svc_signonnum:
|
||||
CL_ParseSignon( msg, PROTO_GOLDSRC );
|
||||
break;
|
||||
case svc_centerprint:
|
||||
CL_CenterPrint( MSG_ReadString( msg ), 0.25f );
|
||||
break;
|
||||
case svc_goldsrc_spawnstaticsound:
|
||||
CL_ParseSpawnStaticSound( msg );
|
||||
break;
|
||||
case svc_intermission:
|
||||
cl.intermission = 1;
|
||||
break;
|
||||
case svc_finale:
|
||||
CL_ParseFinaleCutscene( msg, 2 );
|
||||
break;
|
||||
case svc_cdtrack:
|
||||
param1 = MSG_ReadByte( msg );
|
||||
param1 = bound( 1, param1, MAX_CDTRACKS ); // tracknum
|
||||
param2 = MSG_ReadByte( msg );
|
||||
param2 = bound( 1, param2, MAX_CDTRACKS ); // loopnum
|
||||
S_StartBackgroundTrack( clgame.cdtracks[param1-1], clgame.cdtracks[param2-1], 0, false );
|
||||
break;
|
||||
case svc_restore:
|
||||
CL_ParseRestore( msg );
|
||||
break;
|
||||
case svc_cutscene:
|
||||
CL_ParseFinaleCutscene( msg, 3 );
|
||||
break;
|
||||
case svc_weaponanim:
|
||||
param1 = MSG_ReadByte( msg ); // iAnim
|
||||
param2 = MSG_ReadByte( msg ); // body
|
||||
CL_WeaponAnim( param1, param2 );
|
||||
break;
|
||||
case svc_roomtype:
|
||||
param1 = MSG_ReadShort( msg );
|
||||
Cvar_SetValue( "room_type", param1 );
|
||||
break;
|
||||
case svc_addangle:
|
||||
CL_ParseAddAngle( msg );
|
||||
break;
|
||||
case svc_goldsrc_newusermsg:
|
||||
CL_ParseNewUserMsg( msg );
|
||||
break;
|
||||
case svc_packetentities:
|
||||
playerbytes = CL_ParsePacketEntitiesGS( msg, false );
|
||||
cl.frames[cl.parsecountmod].graphdata.players += playerbytes;
|
||||
cl.frames[cl.parsecountmod].graphdata.entities += MSG_GetNumBytesRead( msg ) - bufStart - playerbytes;
|
||||
break;
|
||||
case svc_deltapacketentities:
|
||||
playerbytes = CL_ParsePacketEntitiesGS( msg, true );
|
||||
cl.frames[cl.parsecountmod].graphdata.players += playerbytes;
|
||||
cl.frames[cl.parsecountmod].graphdata.entities += MSG_GetNumBytesRead( msg ) - bufStart - playerbytes;
|
||||
break;
|
||||
case svc_choke:
|
||||
cl.frames[cls.netchan.incoming_sequence & CL_UPDATE_MASK].choked = true;
|
||||
cl.frames[cls.netchan.incoming_sequence & CL_UPDATE_MASK].receivedtime = -2.0;
|
||||
break;
|
||||
case svc_resourcelist:
|
||||
MSG_StartBitWriting( msg );
|
||||
CL_ParseResourceList( msg, PROTO_GOLDSRC );
|
||||
MSG_EndBitWriting( msg );
|
||||
break;
|
||||
case svc_goldsrc_newmovevars:
|
||||
CL_ParseNewMovevars( msg );
|
||||
break;
|
||||
case svc_resourcerequest:
|
||||
CL_ParseResourceRequest( msg );
|
||||
break;
|
||||
case svc_customization:
|
||||
CL_ParseCustomization( msg );
|
||||
break;
|
||||
case svc_crosshairangle:
|
||||
CL_ParseCrosshairAngle( msg );
|
||||
break;
|
||||
case svc_soundfade:
|
||||
CL_ParseSoundFade( msg );
|
||||
break;
|
||||
case svc_filetxferfailed:
|
||||
CL_ParseFileTransferFailed( msg );
|
||||
break;
|
||||
case svc_hltv:
|
||||
CL_ParseHLTV( msg );
|
||||
break;
|
||||
case svc_director:
|
||||
CL_ParseDirector( msg );
|
||||
break;
|
||||
case svc_voiceinit:
|
||||
CL_ParseVoiceInit( msg );
|
||||
break;
|
||||
case svc_voicedata:
|
||||
CL_ParseVoiceData( msg );
|
||||
cl.frames[cl.parsecountmod].graphdata.voicebytes += MSG_GetNumBytesRead( msg ) - bufStart;
|
||||
break;
|
||||
case svc_resourcelocation:
|
||||
CL_ParseResLocation( msg );
|
||||
break;
|
||||
case svc_goldsrc_sendextrainfo:
|
||||
CL_ParseExtraInfo( msg );
|
||||
break;
|
||||
case svc_querycvarvalue:
|
||||
CL_ParseCvarValue( msg, false, PROTO_GOLDSRC );
|
||||
break;
|
||||
case svc_querycvarvalue2:
|
||||
CL_ParseCvarValue( msg, true, PROTO_GOLDSRC );
|
||||
break;
|
||||
case svc_exec:
|
||||
CL_ParseExec( msg );
|
||||
break;
|
||||
default:
|
||||
CL_ParseUserMessage( msg, cmd );
|
||||
cl.frames[cl.parsecountmod].graphdata.usr += MSG_GetNumBytesRead( msg ) - bufStart;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -544,8 +544,8 @@ void GAME_EXPORT CL_SetSolidPlayers( int playernum )
|
||||
// some fields needs to be override from cls.predicted_players
|
||||
VectorCopy( player->origin, pe->origin );
|
||||
VectorCopy( player->angles, pe->angles );
|
||||
VectorCopy( clgame.pmove->player_mins[player->usehull], pe->mins );
|
||||
VectorCopy( clgame.pmove->player_maxs[player->usehull], pe->maxs );
|
||||
VectorCopy( host.player_mins[player->usehull], pe->mins );
|
||||
VectorCopy( host.player_maxs[player->usehull], pe->maxs );
|
||||
pe->movetype = player->movetype;
|
||||
pe->solid = player->solid;
|
||||
}
|
||||
|
||||
+23
-22
@@ -22,22 +22,24 @@ GNU General Public License for more details.
|
||||
#include "hltv.h"
|
||||
#include "input.h"
|
||||
|
||||
#define STAT_HEALTH 0
|
||||
#define STAT_FRAGS 1
|
||||
#define STAT_WEAPON 2
|
||||
#define STAT_AMMO 3
|
||||
#define STAT_ARMOR 4
|
||||
#define STAT_WEAPONFRAME 5
|
||||
#define STAT_SHELLS 6
|
||||
#define STAT_NAILS 7
|
||||
#define STAT_ROCKETS 8
|
||||
#define STAT_CELLS 9
|
||||
#define STAT_ACTIVEWEAPON 10
|
||||
#define STAT_TOTALSECRETS 11
|
||||
#define STAT_TOTALMONSTERS 12
|
||||
#define STAT_SECRETS 13 // bumped on client side by svc_foundsecret
|
||||
#define STAT_MONSTERS 14 // bumped by svc_killedmonster
|
||||
#define MAX_STATS 32
|
||||
enum {
|
||||
STAT_HEALTH = 0,
|
||||
STAT_FRAGS,
|
||||
STAT_WEAPON,
|
||||
STAT_AMMO,
|
||||
STAT_ARMOR,
|
||||
STAT_WEAPONFRAME,
|
||||
STAT_SHELLS,
|
||||
STAT_NAILS,
|
||||
STAT_ROCKETS,
|
||||
STAT_CELLS,
|
||||
STAT_ACTIVEWEAPON,
|
||||
STAT_TOTALSECRETS,
|
||||
STAT_TOTALMONSTERS,
|
||||
STAT_SECRETS, // bumped on client side by svc_foundsecret
|
||||
STAT_MONSTERS, // bumped by svc_killedmonster
|
||||
MAX_STATS = 32,
|
||||
};
|
||||
|
||||
static char cmd_buf[8192];
|
||||
static char msg_buf[8192];
|
||||
@@ -328,7 +330,7 @@ static void CL_ParseQuakeServerInfo( sizebuf_t *msg )
|
||||
clgame.movevars.gravity = 800.0f; // quake doesn't write gravity in demos
|
||||
clgame.movevars.maxvelocity = 2000.0f;
|
||||
|
||||
memcpy( &clgame.oldmovevars, &clgame.movevars, sizeof( movevars_t ));
|
||||
clgame.oldmovevars = clgame.movevars;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -429,7 +431,7 @@ static void CL_ParseQuakeEntityData( sizebuf_t *msg, int bits )
|
||||
cls.signon = SIGNONS;
|
||||
|
||||
// Clear loading plaque.
|
||||
CL_SignonReply ();
|
||||
CL_SignonReply( PROTO_QUAKE );
|
||||
}
|
||||
|
||||
// alloc next slot to store update
|
||||
@@ -624,7 +626,7 @@ CL_ParseStaticEntity
|
||||
|
||||
===================
|
||||
*/
|
||||
static void CL_ParseStaticEntity( sizebuf_t *msg )
|
||||
static void CL_ParseQuakeStaticEntity( sizebuf_t *msg )
|
||||
{
|
||||
entity_state_t state;
|
||||
cl_entity_t *ent;
|
||||
@@ -715,8 +717,7 @@ static void CL_ParseQuakeBaseline( sizebuf_t *msg )
|
||||
ent = CL_EDICT_NUM( newnum );
|
||||
ent->index = newnum;
|
||||
ent->player = CL_IsPlayerIndex( newnum );
|
||||
memcpy( &ent->baseline, &state, sizeof( entity_state_t ));
|
||||
memcpy( &ent->prevstate, &state, sizeof( entity_state_t ));
|
||||
ent->prevstate = ent->baseline = state;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1005,7 +1006,7 @@ void CL_ParseQuakeMessage( sizebuf_t *msg )
|
||||
CL_ParseQuakeDamage( msg );
|
||||
break;
|
||||
case svc_spawnstatic:
|
||||
CL_ParseStaticEntity( msg );
|
||||
CL_ParseQuakeStaticEntity( msg );
|
||||
break;
|
||||
case svc_spawnbinary:
|
||||
// never used in Quake
|
||||
|
||||
+393
-376
File diff suppressed because it is too large
Load Diff
@@ -35,7 +35,7 @@ static void V_CalcViewRect( void )
|
||||
int sb_lines;
|
||||
float size;
|
||||
|
||||
if( FBitSet( host.features, ENGINE_QUAKE_COMPATIBLE ))
|
||||
if( Host_IsQuakeCompatible( ))
|
||||
{
|
||||
// intermission is always full screen
|
||||
if( cl.intermission ) size = 120.0f;
|
||||
@@ -144,7 +144,9 @@ static void V_SetRefParams( ref_params_t *fd )
|
||||
VectorCopy( cl.viewangles, fd->cl_viewangles );
|
||||
fd->health = cl.local.health;
|
||||
VectorCopy( cl.crosshairangle, fd->crosshairangle );
|
||||
fd->viewsize = scr_viewsize.value;
|
||||
if( Host_IsQuakeCompatible( ))
|
||||
fd->viewsize = scr_viewsize.value;
|
||||
else fd->viewsize = 120.0f;
|
||||
|
||||
VectorCopy( cl.punchangle, fd->punchangle );
|
||||
fd->maxclients = cl.maxclients;
|
||||
|
||||
+30
-23
@@ -278,6 +278,8 @@ typedef struct
|
||||
int lostpackets; // count lost packets and show dialog in menu
|
||||
|
||||
double frametime_remainder;
|
||||
|
||||
uint worldmapCRC;
|
||||
} client_t;
|
||||
|
||||
/*
|
||||
@@ -309,14 +311,6 @@ typedef enum
|
||||
CL_CHANGELEVEL, // draw 'loading' during changelevel
|
||||
} scrstate_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
PROTO_CURRENT = 0, // Xash3D 49
|
||||
PROTO_LEGACY = 1, // Xash3D 48
|
||||
PROTO_QUAKE = 2, // Quake 15
|
||||
PROTO_GOLDSRC = 3, // GoldSrc 48
|
||||
} connprotocol_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char name[32];
|
||||
@@ -501,7 +495,6 @@ typedef struct
|
||||
|
||||
net_request_t net_requests[MAX_REQUESTS]; // no reason to keep more
|
||||
|
||||
efrag_t *free_efrags; // linked efrags
|
||||
cl_entity_t viewent; // viewmodel
|
||||
|
||||
qboolean client_dll_uses_sdl;
|
||||
@@ -518,8 +511,9 @@ typedef struct
|
||||
player_info_t playerinfo; // local playerinfo
|
||||
|
||||
gameui_draw_t ds; // draw2d stuff (menu images)
|
||||
GAMEINFO gameInfo; // current gameInfo
|
||||
GAMEINFO *modsInfo[MAX_MODS]; // simplified gameInfo for MainUI
|
||||
gameinfo2_t gameInfo; // current gameInfo
|
||||
gameinfo2_t *modsInfo; // simplified gameInfo for MainUI, allocated by demand
|
||||
GAMEINFO **oldModsInfo; // simplified gameInfo for older MainUI, allocated by demand
|
||||
|
||||
ui_globalvars_t *globals;
|
||||
|
||||
@@ -760,7 +754,7 @@ qboolean CL_PrecacheResources( void );
|
||||
void CL_SetupOverviewParams( void );
|
||||
void CL_UpdateFrameLerp( void );
|
||||
int CL_IsDevOverviewMode( void );
|
||||
void CL_SignonReply( void );
|
||||
void CL_SignonReply( connprotocol_t proto );
|
||||
void CL_ClearState( void );
|
||||
|
||||
//
|
||||
@@ -784,13 +778,14 @@ void CL_Demos_f( void );
|
||||
void CL_DeleteDemo_f( void );
|
||||
void CL_Record_f( void );
|
||||
void CL_Stop_f( void );
|
||||
void CL_ListDemo_f( void );
|
||||
int CL_GetDemoComment( const char *demoname, char *comment );
|
||||
|
||||
//
|
||||
// cl_events.c
|
||||
//
|
||||
void CL_ParseEvent( sizebuf_t *msg );
|
||||
void CL_ParseReliableEvent( sizebuf_t *msg );
|
||||
void CL_ParseEvent( sizebuf_t *msg, connprotocol_t proto );
|
||||
void CL_ParseReliableEvent( sizebuf_t *msg, connprotocol_t proto );
|
||||
void CL_SetEventIndex( const char *szEvName, int ev_index );
|
||||
void CL_PlaybackEvent( int flags, const edict_t *pInvoker, word eventindex, float delay, float *origin,
|
||||
float *angles, float fparam1, float fparam2, int iparam1, int iparam2, int bparam1, int bparam2 );
|
||||
@@ -867,20 +862,22 @@ _inline cl_entity_t *CL_EDICT_NUM( int n )
|
||||
// cl_parse.c
|
||||
//
|
||||
void CL_ParseSetAngle( sizebuf_t *msg );
|
||||
void CL_ParseServerData( sizebuf_t *msg, qboolean legacy );
|
||||
void CL_ParseLightStyle( sizebuf_t *msg );
|
||||
void CL_UpdateUserinfo( sizebuf_t *msg, qboolean legacy );
|
||||
void CL_ParseServerData( sizebuf_t *msg, connprotocol_t proto );
|
||||
void CL_ParseLightStyle( sizebuf_t *msg, connprotocol_t proto );
|
||||
void CL_UpdateUserinfo( sizebuf_t *msg, connprotocol_t proto );
|
||||
void CL_ParseResource( sizebuf_t *msg );
|
||||
void CL_ParseClientData( sizebuf_t *msg );
|
||||
void CL_ParseClientData( sizebuf_t *msg, connprotocol_t proto );
|
||||
void CL_UpdateUserPings( sizebuf_t *msg );
|
||||
void CL_ParseParticles( sizebuf_t *msg );
|
||||
void CL_ParseRestoreSoundPacket( sizebuf_t *msg );
|
||||
void CL_ParseBaseline( sizebuf_t *msg, qboolean legacy );
|
||||
void CL_ParseSignon( sizebuf_t *msg );
|
||||
void CL_ParseBaseline( sizebuf_t *msg, connprotocol_t proto );
|
||||
void CL_ParseSignon( sizebuf_t *msg, connprotocol_t proto );
|
||||
void CL_ParseRestore( sizebuf_t *msg );
|
||||
void CL_ParseStaticEntity( sizebuf_t *msg );
|
||||
void CL_ParseStaticDecal( sizebuf_t *msg );
|
||||
void CL_ParseAddAngle( sizebuf_t *msg );
|
||||
void CL_RegisterUserMessage( sizebuf_t *msg );
|
||||
void CL_ParseResourceList( sizebuf_t *msg, connprotocol_t proto );
|
||||
void CL_ParseMovevars( sizebuf_t *msg );
|
||||
void CL_ParseResourceRequest( sizebuf_t *msg );
|
||||
void CL_ParseCustomization( sizebuf_t *msg );
|
||||
@@ -889,18 +886,21 @@ void CL_ParseSoundFade( sizebuf_t *msg );
|
||||
void CL_ParseFileTransferFailed( sizebuf_t *msg );
|
||||
void CL_ParseHLTV( sizebuf_t *msg );
|
||||
void CL_ParseDirector( sizebuf_t *msg );
|
||||
void CL_ParseVoiceInit( sizebuf_t *msg );
|
||||
void CL_ParseVoiceData( sizebuf_t *msg );
|
||||
void CL_ParseResLocation( sizebuf_t *msg );
|
||||
void CL_ParseCvarValue( sizebuf_t *msg, const qboolean ext, const connprotocol_t proto );
|
||||
void CL_ParseServerMessage( sizebuf_t *msg );
|
||||
void CL_ParseTempEntity( sizebuf_t *msg );
|
||||
void CL_ParseTempEntity( sizebuf_t *msg, connprotocol_t proto );
|
||||
qboolean CL_DispatchUserMessage( const char *pszName, int iSize, void *pbuf );
|
||||
qboolean CL_RequestMissingResources( void );
|
||||
void CL_RegisterResources ( sizebuf_t *msg );
|
||||
void CL_RegisterResources( sizebuf_t *msg, connprotocol_t proto );
|
||||
void CL_ParseViewEntity( sizebuf_t *msg );
|
||||
void CL_ParseServerTime( sizebuf_t *msg );
|
||||
void CL_ParseUserMessage( sizebuf_t *msg, int svc_num );
|
||||
void CL_ParseFinaleCutscene( sizebuf_t *msg, int level );
|
||||
void CL_ParseTextMessage( sizebuf_t *msg );
|
||||
void CL_ParseExec( sizebuf_t *msg );
|
||||
void CL_BatchResourceRequest( qboolean initialize );
|
||||
int CL_EstimateNeededResources( void );
|
||||
|
||||
@@ -910,6 +910,11 @@ int CL_EstimateNeededResources( void );
|
||||
void CL_ParseLegacyServerMessage( sizebuf_t *msg );
|
||||
void CL_LegacyPrecache_f( void );
|
||||
|
||||
//
|
||||
// cl_parse_gs.c
|
||||
//
|
||||
void CL_ParseGoldSrcServerMessage( sizebuf_t *msg );
|
||||
|
||||
//
|
||||
// cl_scrn.c
|
||||
//
|
||||
@@ -974,7 +979,9 @@ void CL_ParseQuakeMessage( sizebuf_t *msg );
|
||||
//
|
||||
struct channel_s;
|
||||
struct rawchan_s;
|
||||
int CL_ParsePacketEntities( sizebuf_t *msg, qboolean delta );
|
||||
qboolean CL_ValidateDeltaPacket( uint oldpacket, frame_t *oldframe );
|
||||
int CL_UpdateOldEntNum( int oldindex, frame_t *oldframe, entity_state_t **oldent );
|
||||
int CL_ParsePacketEntities( sizebuf_t *msg, qboolean delta, connprotocol_t proto );
|
||||
qboolean CL_AddVisibleEntity( cl_entity_t *ent, int entityType );
|
||||
void CL_ResetLatchedVars( cl_entity_t *ent, qboolean full_reset );
|
||||
qboolean CL_GetEntitySpatialization( struct channel_s *ch );
|
||||
|
||||
@@ -1753,7 +1753,7 @@ static void Con_DrawNotify( void )
|
||||
|
||||
if( host.allow_console && ( !Cvar_VariableInteger( "cl_background" ) && !Cvar_VariableInteger( "sv_background" )))
|
||||
{
|
||||
for( i = CON_LINES_COUNT - con.num_times; i < CON_LINES_COUNT; i++ )
|
||||
for( i = Q_max( 0, CON_LINES_COUNT - con.num_times ); i < CON_LINES_COUNT; i++ )
|
||||
{
|
||||
con_lineinfo_t *l = &CON_LINES( i );
|
||||
|
||||
|
||||
+22
-12
@@ -142,7 +142,7 @@ static struct touch_s
|
||||
touchdefaultbutton_t g_DefaultButtons[256];
|
||||
int g_LastDefaultButton;
|
||||
|
||||
static CVAR_DEFINE_AUTO( touch_in_menu, "0", FCVAR_FILTERABLE, "draw touch in menu (for internal use only)" );
|
||||
static CVAR_DEFINE_AUTO( touch_in_menu, "0", FCVAR_PRIVILEGED, "draw touch in menu (for internal use only)" );
|
||||
static CVAR_DEFINE_AUTO( touch_forwardzone, "0.06", FCVAR_FILTERABLE, "forward touch zone" );
|
||||
static CVAR_DEFINE_AUTO( touch_sidezone, "0.06", FCVAR_FILTERABLE, "side touch zone" );
|
||||
static CVAR_DEFINE_AUTO( touch_pitch, "90", FCVAR_FILTERABLE, "touch pitch sensitivity" );
|
||||
@@ -163,8 +163,8 @@ static CVAR_DEFINE_AUTO( touch_dpad_radius, "1.0", FCVAR_FILTERABLE, "dpad radiu
|
||||
static CVAR_DEFINE_AUTO( touch_joy_radius, "1.0", FCVAR_FILTERABLE, "joy radius multiplier" );
|
||||
static CVAR_DEFINE_AUTO( touch_move_indicator, "0.0", FCVAR_FILTERABLE, "indicate move events (0 to disable)" );
|
||||
static CVAR_DEFINE_AUTO( touch_joy_texture, "touch_default/joy", FCVAR_FILTERABLE, "texture for move indicator");
|
||||
static CVAR_DEFINE_AUTO( touch_emulate, "0", FCVAR_ARCHIVE | FCVAR_PRIVILEGED, "emulate touch with mouse" );
|
||||
CVAR_DEFINE_AUTO( touch_enable, DEFAULT_TOUCH_ENABLE, FCVAR_ARCHIVE | FCVAR_FILTERABLE, "enable touch controls" );
|
||||
CVAR_DEFINE_AUTO( touch_emulate, "0", FCVAR_ARCHIVE | FCVAR_FILTERABLE, "emulate touch with mouse" );
|
||||
|
||||
// code looks smaller with it
|
||||
#define B(x) (button->x)
|
||||
@@ -767,14 +767,18 @@ static void Touch_ReloadConfig_f( void )
|
||||
touch.state = state_none;
|
||||
if( touch.edit )
|
||||
touch.edit->finger = -1;
|
||||
|
||||
if( touch.selection )
|
||||
touch.selection->finger = -1;
|
||||
|
||||
touch.edit = touch.selection = NULL;
|
||||
touch.resize_finger = touch.move_finger = touch.look_finger = touch.wheel_finger = -1;
|
||||
if( FS_FileExists( touch_config_file.string, true ) )
|
||||
{
|
||||
|
||||
if( touch_in_menu.value )
|
||||
Cvar_DirectSet( &touch_in_menu, "0" );
|
||||
|
||||
if( FS_FileExists( touch_config_file.string, true ))
|
||||
Cbuf_AddTextf( "exec \"%s\"\n", touch_config_file.string );
|
||||
}
|
||||
else
|
||||
{
|
||||
Touch_LoadDefaults_f();
|
||||
@@ -1010,7 +1014,7 @@ static void Touch_DisableEdit_f( void )
|
||||
{
|
||||
Cvar_Set( "touch_in_menu", "0" );
|
||||
}
|
||||
else if( cls.key_dest == key_game )
|
||||
else if( cls.key_dest == key_game )
|
||||
Touch_WriteConfig();
|
||||
}
|
||||
|
||||
@@ -1087,18 +1091,19 @@ void Touch_Init( void )
|
||||
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.680000, 0.000000, 0.760000, 0.151486, color, 2, 1, 16 );
|
||||
Touch_AddDefaultButton( "savequick", "touch_default/save", "savequick", 0.760000, 0.000000, 0.840000, 0.151486, color, 2, 1, 16 );
|
||||
Touch_AddDefaultButton( "messagemode", "touch_default/keyboard", "messagemode", 0.760000, 0.000000, 0.840000, 0.151486, color, 2, 1, 8 );
|
||||
Touch_AddDefaultButton( "loadquick", "touch_default/load", "loadquick", 0.760000, 0.000000, 0.840000, 0.142222, color, 2, 1, 16 );
|
||||
Touch_AddDefaultButton( "savequick", "touch_default/save", "savequick", 0.840000, 0.000000, 0.920000, 0.142222, color, 2, 1, 16 );
|
||||
Touch_AddDefaultButton( "messagemode", "touch_default/keyboard", "messagemode", 0.840000, 0.000000, 0.920000, 0.142222, 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.680000, 0.000000, 0.760000, 0.151486, color, 2, 1, 8 );
|
||||
Touch_AddDefaultButton( "scores", "touch_default/map", "+showscores", 0.760000, 0.000000, 0.840000, 0.142222, 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( "spray", "touch_default/spray", "impulse 201", 0.840000, 0.000000, 0.920000, 0.151486, color, 2, 1, 0 );
|
||||
Touch_AddDefaultButton( "spray", "touch_default/spray", "impulse 201", 0.680000, 0.000000, 0.760000, 0.142222, color, 2, 1, 8 );
|
||||
Touch_AddDefaultButton( "voicechat", "touch_default/microphone", "+voicerecord", 0.780000, 0.817778, 0.860000, 0.960000, color, 2, 1, 8 );
|
||||
|
||||
Cmd_AddCommand( "touch_addbutton", Touch_AddButton_f, "add native touch button" );
|
||||
Cmd_AddCommand( "touch_removebutton", IN_TouchRemoveButton_f, "remove native touch button" );
|
||||
@@ -2122,7 +2127,7 @@ void Touch_KeyEvent( int key, int down )
|
||||
float x, y;
|
||||
int finger, xi, yi;
|
||||
|
||||
if( !touch_emulate.value )
|
||||
if( !Touch_Emulated( ))
|
||||
{
|
||||
if( touch_enable.value )
|
||||
return;
|
||||
@@ -2176,6 +2181,11 @@ qboolean Touch_WantVisibleCursor( void )
|
||||
return ( touch_enable.value && touch_emulate.value ) || touch.clientonly;
|
||||
}
|
||||
|
||||
qboolean Touch_Emulated( void )
|
||||
{
|
||||
return touch_emulate.value || touch_in_menu.value;
|
||||
}
|
||||
|
||||
void Touch_Shutdown( void )
|
||||
{
|
||||
if( !touch.initialized )
|
||||
|
||||
+67
-51
@@ -47,6 +47,8 @@ static CVAR_DEFINE_AUTO( cl_forwardspeed, "400", FCVAR_ARCHIVE | FCVAR_CLIENTDLL
|
||||
static CVAR_DEFINE_AUTO( cl_backspeed, "400", FCVAR_ARCHIVE | FCVAR_CLIENTDLL | FCVAR_FILTERABLE, "Default back move speed" );
|
||||
static CVAR_DEFINE_AUTO( cl_sidespeed, "400", FCVAR_ARCHIVE | FCVAR_CLIENTDLL | FCVAR_FILTERABLE, "Default side move speed" );
|
||||
|
||||
static CVAR_DEFINE_AUTO( m_grab_debug, "0", FCVAR_PRIVILEGED, "show debug messages on mouse state change" );
|
||||
|
||||
/*
|
||||
================
|
||||
IN_CollectInputDevices
|
||||
@@ -116,6 +118,7 @@ static void IN_StartupMouse( void )
|
||||
Cvar_RegisterVariable( &m_yaw );
|
||||
Cvar_RegisterVariable( &look_filter );
|
||||
Cvar_RegisterVariable( &m_rawinput );
|
||||
Cvar_RegisterVariable( &m_grab_debug );
|
||||
|
||||
// You can use -nomouse argument to prevent using mouse from client
|
||||
// -noenginemouse will disable all mouse input
|
||||
@@ -202,68 +205,81 @@ void IN_ToggleClientMouse( int newstate, int oldstate )
|
||||
}
|
||||
}
|
||||
|
||||
static void IN_SetRelativeMouseMode( qboolean set, qboolean verbose )
|
||||
{
|
||||
static qboolean s_bRawInput;
|
||||
|
||||
if( set && !s_bRawInput )
|
||||
{
|
||||
#if XASH_SDL == 2
|
||||
SDL_GetRelativeMouseState( NULL, NULL );
|
||||
SDL_SetRelativeMouseMode( SDL_TRUE );
|
||||
#endif
|
||||
s_bRawInput = true;
|
||||
if( verbose )
|
||||
Con_Printf( "%s: true\n", __func__ );
|
||||
}
|
||||
else if( !set && s_bRawInput )
|
||||
{
|
||||
#if XASH_SDL == 2
|
||||
SDL_GetRelativeMouseState( NULL, NULL );
|
||||
SDL_SetRelativeMouseMode( SDL_FALSE );
|
||||
#endif
|
||||
s_bRawInput = false;
|
||||
if( verbose )
|
||||
Con_Printf( "%s: false\n", __func__ );
|
||||
}
|
||||
}
|
||||
|
||||
static void IN_SetMouseGrab( qboolean set, qboolean verbose )
|
||||
{
|
||||
static qboolean s_bMouseGrab;
|
||||
|
||||
if( set && !s_bMouseGrab )
|
||||
{
|
||||
#if XASH_SDL
|
||||
SDL_SetWindowGrab( host.hWnd, SDL_TRUE );
|
||||
#endif
|
||||
s_bMouseGrab = true;
|
||||
if( verbose )
|
||||
Con_Printf( "%s: true\n", __func__ );
|
||||
}
|
||||
else if( !set && s_bMouseGrab )
|
||||
{
|
||||
#if XASH_SDL
|
||||
SDL_SetWindowGrab( host.hWnd, SDL_FALSE );
|
||||
#endif
|
||||
|
||||
s_bMouseGrab = false;
|
||||
if( verbose )
|
||||
Con_Printf( "%s: false\n", __func__ );
|
||||
}
|
||||
}
|
||||
|
||||
static void IN_CheckMouseState( qboolean active )
|
||||
{
|
||||
static qboolean s_bRawInput, s_bMouseGrab;
|
||||
qboolean use_raw_input, verbose;
|
||||
|
||||
#if XASH_WIN32
|
||||
qboolean useRawInput = ( m_rawinput.value && clgame.client_dll_uses_sdl ) || clgame.dllFuncs.pfnLookEvent != NULL;
|
||||
use_raw_input = ( m_rawinput.value && clgame.client_dll_uses_sdl ) || clgame.dllFuncs.pfnLookEvent != NULL;
|
||||
#else
|
||||
qboolean useRawInput = true; // always use SDL code
|
||||
use_raw_input = true; // always use SDL code
|
||||
#endif
|
||||
|
||||
verbose = m_grab_debug.value ? true : false;
|
||||
|
||||
if( m_ignore.value )
|
||||
return;
|
||||
active = false;
|
||||
|
||||
if( active && useRawInput && !host.mouse_visible && cls.state == ca_active )
|
||||
{
|
||||
if( !s_bRawInput )
|
||||
{
|
||||
#if XASH_SDL == 2
|
||||
SDL_GetRelativeMouseState( NULL, NULL );
|
||||
SDL_SetRelativeMouseMode( SDL_TRUE );
|
||||
#endif
|
||||
|
||||
// Con_Printf( "Enable relative mode\n" );
|
||||
s_bRawInput = true;
|
||||
}
|
||||
}
|
||||
if( active && use_raw_input && !host.mouse_visible && cls.state == ca_active )
|
||||
IN_SetRelativeMouseMode( true, verbose );
|
||||
else
|
||||
{
|
||||
if( s_bRawInput )
|
||||
{
|
||||
#if XASH_SDL == 2
|
||||
SDL_GetRelativeMouseState( NULL, NULL );
|
||||
SDL_SetRelativeMouseMode( SDL_FALSE );
|
||||
#endif
|
||||
// Con_Printf( "Disable relative mode\n" );
|
||||
s_bRawInput = false;
|
||||
}
|
||||
}
|
||||
IN_SetRelativeMouseMode( false, verbose );
|
||||
|
||||
if( active && !host.mouse_visible && cls.state == ca_active )
|
||||
{
|
||||
if( !s_bMouseGrab )
|
||||
{
|
||||
#if XASH_SDL
|
||||
SDL_SetWindowGrab( host.hWnd, SDL_TRUE );
|
||||
#endif
|
||||
// Con_Printf( "Enable grab\n" );
|
||||
s_bMouseGrab = true;
|
||||
}
|
||||
}
|
||||
IN_SetMouseGrab( true, verbose );
|
||||
else
|
||||
{
|
||||
if( s_bMouseGrab )
|
||||
{
|
||||
#if XASH_SDL
|
||||
SDL_SetWindowGrab( host.hWnd, SDL_FALSE );
|
||||
#endif
|
||||
|
||||
// Con_Printf( "Disable grab\n" );
|
||||
s_bMouseGrab = false;
|
||||
}
|
||||
}
|
||||
IN_SetMouseGrab( false, verbose );
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -316,7 +332,7 @@ static void IN_MouseMove( void )
|
||||
if( !in_mouseinitialized )
|
||||
return;
|
||||
|
||||
if( touch_emulate.value )
|
||||
if( Touch_Emulated( ))
|
||||
{
|
||||
// touch emulation overrides all input
|
||||
Touch_KeyEvent( 0, 0 );
|
||||
@@ -347,7 +363,7 @@ void IN_MouseEvent( int key, int down )
|
||||
else ClearBits( in_mstate, BIT( key ));
|
||||
|
||||
// touch emulation overrides all input
|
||||
if( touch_emulate.value )
|
||||
if( Touch_Emulated( ))
|
||||
{
|
||||
Touch_KeyEvent( K_MOUSE1 + key, down );
|
||||
}
|
||||
|
||||
@@ -58,7 +58,6 @@ typedef enum
|
||||
} touchEventType;
|
||||
|
||||
extern convar_t touch_enable;
|
||||
extern convar_t touch_emulate;
|
||||
|
||||
void Touch_Draw( void );
|
||||
void Touch_SetClientOnly( byte state );
|
||||
@@ -74,6 +73,7 @@ void Touch_ResetDefaultButtons( void );
|
||||
int IN_TouchEvent( touchEventType type, int fingerID, float x, float y, float dx, float dy );
|
||||
void Touch_KeyEvent( int key, int down );
|
||||
qboolean Touch_WantVisibleCursor( void );
|
||||
qboolean Touch_Emulated( void );
|
||||
void Touch_NotifyResize( void );
|
||||
|
||||
//
|
||||
|
||||
+50
-37
@@ -10,7 +10,7 @@ ref_globals_t refState;
|
||||
|
||||
static const char* r_skyBoxSuffix[SKYBOX_MAX_SIDES] = { "rt", "bk", "lf", "ft", "up", "dn" };
|
||||
|
||||
CVAR_DEFINE_AUTO( gl_vsync, "0", FCVAR_ARCHIVE, "enable vertical syncronization" );
|
||||
CVAR_DEFINE_AUTO( gl_vsync, "1", FCVAR_ARCHIVE, "enable vertical syncronization" );
|
||||
CVAR_DEFINE_AUTO( r_showtextures, "0", FCVAR_CHEAT, "show all uploaded textures" );
|
||||
CVAR_DEFINE_AUTO( r_adjust_fov, "1", FCVAR_ARCHIVE, "making FOV adjustment for wide-screens" );
|
||||
CVAR_DEFINE_AUTO( r_decals, "4096", FCVAR_ARCHIVE, "sets the maximum number of decals" );
|
||||
@@ -171,6 +171,22 @@ static intptr_t pfnEngineGetParm( int parm, int arg )
|
||||
return CL_RenderGetParm( parm, arg, false ); // prevent recursion
|
||||
}
|
||||
|
||||
static cvar_t *pfnCvar_Get( const char *szName, const char *szValue, int flags, const char *description )
|
||||
{
|
||||
return (cvar_t *)Cvar_Get( szName, szValue, flags | FCVAR_REFDLL, description );
|
||||
}
|
||||
|
||||
static void pfnCvar_RegisterVariable( convar_t *var )
|
||||
{
|
||||
SetBits( var->flags, FCVAR_REFDLL );
|
||||
Cvar_RegisterVariable( var );
|
||||
}
|
||||
|
||||
static void pfnCvar_FullSet( const char *var_name, const char *value, int flags )
|
||||
{
|
||||
Cvar_FullSet( var_name, value, flags | FCVAR_REFDLL );
|
||||
}
|
||||
|
||||
static void pfnStudioEvent( const mstudioevent_t *event, const cl_entity_t *e )
|
||||
{
|
||||
clgame.dllFuncs.pfnStudioEvent( event, e );
|
||||
@@ -285,18 +301,18 @@ static qboolean R_Init_Video_( const int type )
|
||||
return R_Init_Video( type );
|
||||
}
|
||||
|
||||
static ref_api_t gEngfuncs =
|
||||
static const ref_api_t gEngfuncs =
|
||||
{
|
||||
pfnEngineGetParm,
|
||||
|
||||
(void*)Cvar_Get,
|
||||
pfnCvar_Get,
|
||||
(void*)Cvar_FindVarExt,
|
||||
Cvar_VariableValue,
|
||||
Cvar_VariableString,
|
||||
Cvar_SetValue,
|
||||
Cvar_Set,
|
||||
Cvar_RegisterVariable,
|
||||
Cvar_FullSet,
|
||||
pfnCvar_RegisterVariable,
|
||||
pfnCvar_FullSet,
|
||||
|
||||
Cmd_AddRefCommand,
|
||||
Cmd_RemoveCommand,
|
||||
@@ -431,7 +447,7 @@ static void R_UnloadProgs( void )
|
||||
|
||||
Cvar_FullSet( "host_refloaded", "0", FCVAR_READ_ONLY );
|
||||
|
||||
Cvar_Unlink( FCVAR_RENDERINFO | FCVAR_GLCONFIG );
|
||||
Cvar_Unlink( FCVAR_RENDERINFO | FCVAR_GLCONFIG | FCVAR_REFDLL );
|
||||
Cmd_Unlink( CMD_REFDLL );
|
||||
|
||||
COM_FreeLibrary( ref.hInstance );
|
||||
@@ -473,7 +489,7 @@ static qboolean R_LoadProgs( const char *name )
|
||||
if( ref.hInstance ) R_UnloadProgs();
|
||||
|
||||
FS_AllowDirectPaths( true );
|
||||
if( !(ref.hInstance = COM_LoadLibrary( name, false, true ) ))
|
||||
if( !( ref.hInstance = COM_LoadLibrary( name, false, true )))
|
||||
{
|
||||
FS_AllowDirectPaths( false );
|
||||
Con_Reportf( "%s: can't load renderer library %s: %s\n", __func__, name, COM_GetLibraryError() );
|
||||
@@ -482,32 +498,26 @@ static qboolean R_LoadProgs( const char *name )
|
||||
|
||||
FS_AllowDirectPaths( false );
|
||||
|
||||
if( !( GetRefAPI = (REFAPI)COM_GetProcAddress( ref.hInstance, GET_REF_API )) )
|
||||
if( !( GetRefAPI = (REFAPI)COM_GetProcAddress( ref.hInstance, GET_REF_API )))
|
||||
{
|
||||
COM_FreeLibrary( ref.hInstance );
|
||||
Con_Reportf( "%s: can't find GetRefAPI entry point in %s\n", __func__, name );
|
||||
ref.hInstance = NULL;
|
||||
return false;
|
||||
}
|
||||
|
||||
// make local copy of engfuncs to prevent overwrite it with user dll
|
||||
memcpy( &gpEngfuncs, &gEngfuncs, sizeof( gpEngfuncs ));
|
||||
gpEngfuncs = gEngfuncs;
|
||||
|
||||
if( GetRefAPI( REF_API_VERSION, &ref.dllFuncs, &gpEngfuncs, &refState ) != REF_API_VERSION )
|
||||
{
|
||||
COM_FreeLibrary( ref.hInstance );
|
||||
Con_Reportf( "%s: can't init renderer API: wrong version\n", __func__ );
|
||||
ref.hInstance = NULL;
|
||||
return false;
|
||||
}
|
||||
|
||||
refState.developer = host_developer.value;
|
||||
|
||||
if( !ref.dllFuncs.R_Init( ) )
|
||||
if( !ref.dllFuncs.R_Init( ))
|
||||
{
|
||||
COM_FreeLibrary( ref.hInstance );
|
||||
Con_Reportf( "%s: can't init renderer!\n", __func__ ); //, ref.dllFuncs.R_GetInitError() );
|
||||
ref.hInstance = NULL;
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -544,21 +554,19 @@ static void R_GetRendererName( char *dest, size_t size, const char *opt )
|
||||
{
|
||||
if( !Q_strstr( opt, "." OS_LIB_EXT ))
|
||||
{
|
||||
const char *format;
|
||||
|
||||
#ifdef XASH_INTERNAL_GAMELIBS
|
||||
if( !Q_strcmp( opt, "ref_" ))
|
||||
format = "%s";
|
||||
else
|
||||
format = "ref_%s";
|
||||
#define FMT1 "%s"
|
||||
#define FMT2 "ref_%s"
|
||||
#else
|
||||
if( !Q_strcmp( opt, "ref_" ))
|
||||
format = OS_LIB_PREFIX "%s." OS_LIB_EXT;
|
||||
else
|
||||
format = OS_LIB_PREFIX "ref_%s." OS_LIB_EXT;
|
||||
#define FMT1 OS_LIB_PREFIX "%s." OS_LIB_EXT
|
||||
#define FMT2 OS_LIB_PREFIX "ref_%s." OS_LIB_EXT
|
||||
#endif
|
||||
Q_snprintf( dest, size, format, opt );
|
||||
|
||||
if( !Q_strncmp( opt, "ref_", 4 ))
|
||||
Q_snprintf( dest, size, FMT1, opt );
|
||||
else
|
||||
Q_snprintf( dest, size, FMT2, opt );
|
||||
#undef FMT1
|
||||
#undef FMT2
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -670,7 +678,8 @@ static void R_CollectRendererNames( void )
|
||||
qboolean R_Init( void )
|
||||
{
|
||||
qboolean success = false;
|
||||
string requested;
|
||||
string requested_cmdline;
|
||||
string requested_cvar;
|
||||
|
||||
Cvar_RegisterVariable( &gl_vsync );
|
||||
Cvar_RegisterVariable( &r_showtextures );
|
||||
@@ -720,15 +729,16 @@ qboolean R_Init( void )
|
||||
// 1. Command line `-ref` argument.
|
||||
// 2. `ref_dll` cvar.
|
||||
// 3. Detected renderers in `DEFAULT_RENDERERS` order.
|
||||
requested[0] = 0;
|
||||
requested_cmdline[0] = 0;
|
||||
requested_cvar[0] = 0;
|
||||
|
||||
if( !success && Sys_GetParmFromCmdLine( "-ref", requested ))
|
||||
success = R_LoadRenderer( requested );
|
||||
if( Sys_GetParmFromCmdLine( "-ref", requested_cmdline ))
|
||||
success = R_LoadRenderer( requested_cmdline );
|
||||
|
||||
if( !success && COM_CheckString( r_refdll.string ))
|
||||
if( !success && COM_CheckString( r_refdll.string ) && Q_stricmp( requested_cmdline, r_refdll.string ))
|
||||
{
|
||||
Q_strncpy( requested, r_refdll.string, sizeof( requested ));
|
||||
success = R_LoadRenderer( requested );
|
||||
Q_strncpy( requested_cvar, r_refdll.string, sizeof( requested_cvar ));
|
||||
success = R_LoadRenderer( requested_cvar );
|
||||
}
|
||||
|
||||
if( !success )
|
||||
@@ -738,7 +748,10 @@ qboolean R_Init( void )
|
||||
for( i = 0; i < ref.numRenderers && !success; i++ )
|
||||
{
|
||||
// skip renderer that was requested but failed to load
|
||||
if( !Q_strcmp( requested, ref.shortNames[i] ))
|
||||
if( !Q_strcmp( requested_cmdline, ref.shortNames[i] ))
|
||||
continue;
|
||||
|
||||
if( !Q_strcmp( requested_cvar, ref.shortNames[i] ))
|
||||
continue;
|
||||
|
||||
success = R_LoadRenderer( ref.shortNames[i] );
|
||||
@@ -747,7 +760,7 @@ qboolean R_Init( void )
|
||||
|
||||
if( !success )
|
||||
{
|
||||
Host_Error( "Can't initialize any renderer. Check your video drivers!\n" );
|
||||
Sys_Error( "Can't initialize any renderer. Check your video drivers!\n" );
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -155,11 +155,11 @@ wavdata_t *S_LoadSound( sfx_t *sfx )
|
||||
if( !sc ) sc = S_CreateDefaultSound();
|
||||
|
||||
if( sc->rate < SOUND_11k ) // some bad sounds
|
||||
Sound_Process( &sc, SOUND_11k, sc->width, SOUND_RESAMPLE );
|
||||
Sound_Process( &sc, SOUND_11k, sc->width, sc->channels, SOUND_RESAMPLE );
|
||||
else if( sc->rate > SOUND_11k && sc->rate < SOUND_22k ) // some bad sounds
|
||||
Sound_Process( &sc, SOUND_22k, sc->width, SOUND_RESAMPLE );
|
||||
Sound_Process( &sc, SOUND_22k, sc->width, sc->channels, SOUND_RESAMPLE );
|
||||
else if( sc->rate > SOUND_22k && sc->rate < SOUND_44k ) // some bad sounds
|
||||
Sound_Process( &sc, SOUND_44k, sc->width, SOUND_RESAMPLE );
|
||||
Sound_Process( &sc, SOUND_44k, sc->width, sc->channels, SOUND_RESAMPLE );
|
||||
|
||||
sfx->cache = sc;
|
||||
|
||||
|
||||
@@ -524,8 +524,11 @@ static void SND_Spatialize( channel_t *ch )
|
||||
dist = VectorNormalizeLength( source_vec );
|
||||
dot = DotProduct( s_listener.right, source_vec );
|
||||
|
||||
// don't pan sounds with no attenuation
|
||||
if( ch->dist_mult <= 0.0f ) dot = 0.0f;
|
||||
if( !FBitSet( host.bugcomp, BUGCOMP_SPATIALIZE_SOUND_WITH_ATTN_NONE ))
|
||||
{
|
||||
// don't pan sounds with no attenuation
|
||||
if( ch->dist_mult <= 0.0f ) dot = 0.0f;
|
||||
}
|
||||
|
||||
// fill out channel volumes for single location
|
||||
S_SpatializeChannel( &ch->leftvol, &ch->rightvol, ch->master_vol, gain, dot, dist * ch->dist_mult );
|
||||
@@ -1092,7 +1095,7 @@ rawchan_t *S_FindRawChannel( int entnum, qboolean create )
|
||||
if( !raw_channels[best] )
|
||||
{
|
||||
raw_samples = MAX_RAW_SAMPLES;
|
||||
raw_channels[best] = Mem_Calloc( sndpool, sizeof( *ch ) + sizeof( portable_samplepair_t ) * ( raw_samples - 1 ));
|
||||
raw_channels[best] = Mem_Calloc( sndpool, sizeof( *ch ) + sizeof( portable_samplepair_t ) * raw_samples );
|
||||
}
|
||||
|
||||
ch = raw_channels[best];
|
||||
|
||||
@@ -923,7 +923,7 @@ static void S_MixUpsample( int sampleCount, int filtertype )
|
||||
static void MIX_MixRawSamplesBuffer( int end )
|
||||
{
|
||||
portable_samplepair_t *pbuf, *roombuf, *streambuf;
|
||||
uint i, j, stop;
|
||||
uint i, j, stop;
|
||||
|
||||
roombuf = MIX_GetPFrontFromIPaint( IROOMBUFFER );
|
||||
streambuf = MIX_GetPFrontFromIPaint( ISTREAMBUFFER );
|
||||
@@ -956,7 +956,11 @@ static void MIX_MixRawSamplesBuffer( int end )
|
||||
}
|
||||
|
||||
if( ch->entnum > 0 )
|
||||
SND_MoveMouthRaw( ch, &ch->rawsamples[paintedtime & ( ch->max_samples - 1 )], stop - paintedtime );
|
||||
{
|
||||
int pos = paintedtime & ( ch->max_samples - 1 );
|
||||
|
||||
SND_MoveMouthRaw( ch, &ch->rawsamples[pos], bound( 0, ch->max_samples - pos, stop - paintedtime ));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -96,7 +96,7 @@ static int S_TrimEnd( const wavdata_t *wav, int end )
|
||||
|
||||
if( width == 1 )
|
||||
{
|
||||
const int8_t *data = (const int8_t *)&wav->buffer[channels * width * end];
|
||||
const int8_t *data = (const int8_t *)&wav->buffer[channels * width * ( end - 1 )];
|
||||
|
||||
for( i = 0; i < TRIM_SCAN_MAX && end > 0; i++ )
|
||||
{
|
||||
@@ -109,7 +109,7 @@ static int S_TrimEnd( const wavdata_t *wav, int end )
|
||||
}
|
||||
else if( width == 2 )
|
||||
{
|
||||
const int16_t *data = (const int16_t *)&wav->buffer[channels * width * end];
|
||||
const int16_t *data = (const int16_t *)&wav->buffer[channels * width * ( end - 1 )];
|
||||
|
||||
for( i = 0; i < TRIM_SCAN_MAX && end > 0; i++ )
|
||||
{
|
||||
|
||||
@@ -116,7 +116,7 @@ typedef struct rawchan_s
|
||||
float oldtime; // catch time jumps
|
||||
wavdata_t sound_info; // advance play position
|
||||
size_t max_samples; // buffer length
|
||||
portable_samplepair_t rawsamples[1]; // variable sized
|
||||
portable_samplepair_t rawsamples[]; // variable sized
|
||||
} rawchan_t;
|
||||
|
||||
typedef struct channel_s
|
||||
|
||||
@@ -50,7 +50,9 @@ static CVAR_DEFINE_AUTO( vgui_utf8, "0", FCVAR_ARCHIVE, "enable utf-8 support fo
|
||||
static void GAME_EXPORT VGUI_DrawInit( void )
|
||||
{
|
||||
memset( vgui.textures, 0, sizeof( vgui.textures ));
|
||||
memset( vgui.color, 0, sizeof( vgui.color ));
|
||||
vgui.texture_id = vgui.bound_texture = 0;
|
||||
vgui.enable_texture = true;
|
||||
}
|
||||
|
||||
static void GAME_EXPORT VGUI_DrawShutdown( void )
|
||||
@@ -280,7 +282,7 @@ qboolean VGui_LoadProgs( HINSTANCE hInstance )
|
||||
void (*F)( vguiapi_t* );
|
||||
qboolean client = hInstance != NULL;
|
||||
|
||||
memcpy( &vgui.dllFuncs, &gEngfuncs, sizeof( vgui.dllFuncs ));
|
||||
vgui.dllFuncs = gEngfuncs;
|
||||
|
||||
// not loading interface from client.dll, load vgui_support.dll instead
|
||||
if( !client )
|
||||
@@ -371,7 +373,7 @@ void VGui_Shutdown( void )
|
||||
COM_FreeLibrary( vgui.hInstance );
|
||||
|
||||
// drop pointers to now unloaded vgui_support
|
||||
memcpy( &vgui.dllFuncs, &gEngfuncs, sizeof( vgui.dllFuncs ));
|
||||
vgui.dllFuncs = gEngfuncs;
|
||||
vgui.hInstance = NULL;
|
||||
}
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ static CVAR_DEFINE_AUTO( vid_scale, "1.0", FCVAR_RENDERINFO|FCVAR_VIDRESTART, "p
|
||||
|
||||
CVAR_DEFINE_AUTO( vid_highdpi, "1", FCVAR_RENDERINFO|FCVAR_VIDRESTART, "enable High-DPI mode" );
|
||||
CVAR_DEFINE_AUTO( vid_maximized, "0", FCVAR_RENDERINFO, "window maximized state, read-only" );
|
||||
CVAR_DEFINE( vid_fullscreen, "fullscreen", "0", FCVAR_RENDERINFO|FCVAR_VIDRESTART, "fullscreen state (0 windowed, 1 fullscreen, 2 borderless)" );
|
||||
CVAR_DEFINE( vid_fullscreen, "fullscreen", DEFAULT_FULLSCREEN, FCVAR_RENDERINFO|FCVAR_VIDRESTART, "fullscreen state (0 windowed, 1 fullscreen, 2 borderless)" );
|
||||
CVAR_DEFINE( window_width, "width", "0", FCVAR_RENDERINFO|FCVAR_VIDRESTART, "screen width" );
|
||||
CVAR_DEFINE( window_height, "height", "0", FCVAR_RENDERINFO|FCVAR_VIDRESTART, "screen height" );
|
||||
CVAR_DEFINE( window_xpos, "_window_xpos", "-1", FCVAR_RENDERINFO, "window position by horizontal" );
|
||||
|
||||
+29
-11
@@ -32,6 +32,11 @@ CVAR_DEFINE_AUTO( voice_inputfromfile, "0", FCVAR_PRIVILEGED, "input voice from
|
||||
|
||||
static void Voice_ApplyGainAdjust( int16_t *samples, int count, float scale );
|
||||
|
||||
// in case user enabled voice after connection
|
||||
// can't keep in `voice` struct because it gets zeroed on shutdown
|
||||
static string voice_codec_init;
|
||||
static int voice_quality_init;
|
||||
|
||||
/*
|
||||
===============================================================================
|
||||
|
||||
@@ -397,7 +402,7 @@ void Voice_RecordStart( void )
|
||||
|
||||
if( voice.input_file )
|
||||
{
|
||||
Sound_Process( &voice.input_file, voice.samplerate, voice.width, SOUND_RESAMPLE );
|
||||
Sound_Process( &voice.input_file, voice.samplerate, voice.width, VOICE_PCM_CHANNELS, SOUND_RESAMPLE );
|
||||
voice.input_file_pos = 0;
|
||||
|
||||
voice.start_time = Sys_DoubleTime();
|
||||
@@ -591,10 +596,17 @@ void Voice_Idle( double frametime )
|
||||
{
|
||||
int i;
|
||||
|
||||
if( FBitSet( voice_enable.flags, FCVAR_CHANGED ) && !voice_enable.value )
|
||||
if( FBitSet( voice_enable.flags, FCVAR_CHANGED ))
|
||||
{
|
||||
Voice_Shutdown();
|
||||
return;
|
||||
ClearBits( voice_enable.flags, FCVAR_CHANGED );
|
||||
|
||||
if( voice_enable.value )
|
||||
{
|
||||
if( cls.state == ca_active && COM_CheckString( voice_codec_init ) && voice_quality_init != 0 )
|
||||
Voice_Init( voice_codec_init, voice_quality_init, false );
|
||||
}
|
||||
else
|
||||
Voice_Shutdown();
|
||||
}
|
||||
|
||||
// update local player status first
|
||||
@@ -613,6 +625,19 @@ Initialize the voice subsystem
|
||||
*/
|
||||
qboolean Voice_Init( const char *pszCodecName, int quality, qboolean preinit )
|
||||
{
|
||||
if( Q_strcmp( pszCodecName, VOICE_OPUS_CUSTOM_CODEC ))
|
||||
{
|
||||
Con_Printf( S_ERROR "Server requested unsupported codec: %s\n", pszCodecName );
|
||||
|
||||
// reset saved codec name, we won't enable voice for this connection
|
||||
voice_codec_init[0] = 0;
|
||||
voice_quality_init = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
Q_strncpy( voice_codec_init, pszCodecName, sizeof( voice_codec_init ));
|
||||
voice_quality_init = quality;
|
||||
|
||||
if( !voice_enable.value )
|
||||
return false;
|
||||
|
||||
@@ -620,13 +645,6 @@ qboolean Voice_Init( const char *pszCodecName, int quality, qboolean preinit )
|
||||
if( Q_strcmp( pszCodecName, voice.codec ) || voice.quality != quality )
|
||||
{
|
||||
Voice_Shutdown();
|
||||
|
||||
if( Q_strcmp( pszCodecName, VOICE_OPUS_CUSTOM_CODEC ))
|
||||
{
|
||||
Con_Printf( S_ERROR "Server requested unsupported codec: %s\n", pszCodecName );
|
||||
return false;
|
||||
}
|
||||
|
||||
voice.autogain.block_size = 128;
|
||||
|
||||
if( !Voice_InitCustomMode( ))
|
||||
|
||||
+1
-1
@@ -387,7 +387,7 @@ static void Cmd_Echo_f( void )
|
||||
int i;
|
||||
|
||||
for( i = 1; i < Cmd_Argc(); i++ )
|
||||
Con_Printf( "%s", Cmd_Argv( i ));
|
||||
Con_Printf( "%s ", Cmd_Argv( i ));
|
||||
Con_Printf( "\n" );
|
||||
}
|
||||
|
||||
|
||||
@@ -52,12 +52,18 @@ GNU General Public License for more details.
|
||||
|
||||
#define DEFAULT_EXTERNAL_PALETTE "gfx/palette.pal"
|
||||
|
||||
// path to folders where placed all sounds
|
||||
// path to sound files
|
||||
#define DEFAULT_SOUNDPATH "sound/"
|
||||
|
||||
// path store saved games
|
||||
// path to saved games
|
||||
#define DEFAULT_SAVE_DIRECTORY "save/"
|
||||
|
||||
// path to download games
|
||||
#define DEFAULT_DOWNLOADED_DIRECTORY "downloaded/"
|
||||
|
||||
// path to user mod directory
|
||||
#define DEFAULT_CUSTOM_DIRECTORY "custom/"
|
||||
|
||||
// fallback to this skybox
|
||||
#define DEFAULT_SKYBOX_NAME "desert"
|
||||
|
||||
@@ -72,7 +78,7 @@ GNU General Public License for more details.
|
||||
|
||||
#define XASH_ENGINE_NAME "Xash3D FWGS"
|
||||
#define XASH_DEDICATED_SERVER_NAME "XashDS"
|
||||
#define XASH_VERSION "0.20" // engine current version
|
||||
#define XASH_VERSION "0.21" // engine current version
|
||||
#define XASH_COMPAT_VERSION "0.99" // version we are based on
|
||||
|
||||
#endif//COM_STRINGS_H
|
||||
|
||||
+85
-34
@@ -112,6 +112,9 @@ typedef enum
|
||||
#include "con_nprint.h"
|
||||
#include "crclib.h"
|
||||
#include "ref_api.h"
|
||||
#define FSCALLBACK_OVERRIDE_OPEN
|
||||
#define FSCALLBACK_OVERRIDE_LOADFILE
|
||||
#define FSCALLBACK_OVERRIDE_MALLOC_LIKE
|
||||
#include "fscallback.h"
|
||||
|
||||
// PERFORMANCE INFO
|
||||
@@ -273,6 +276,9 @@ typedef enum bugcomp_e
|
||||
// rewrites mod's attempts to write GoldSrc-specific messages into Xash protocol
|
||||
// (new wrappers are added by request)
|
||||
BUGCOMP_MESSAGE_REWRITE_FACILITY_FLAG = BIT( 1 ),
|
||||
|
||||
// makes sound with no attenuation spatialized, like in GoldSrc
|
||||
BUGCOMP_SPATIALIZE_SOUND_WITH_ATTN_NONE = BIT( 2 ),
|
||||
} bugcomp_t;
|
||||
|
||||
typedef struct host_parm_s
|
||||
@@ -314,6 +320,11 @@ typedef struct host_parm_s
|
||||
vec3_t player_mins[MAX_MAP_HULLS]; // 4 hulls allowed
|
||||
vec3_t player_maxs[MAX_MAP_HULLS]; // 4 hulls allowed
|
||||
|
||||
// for CL_{Push,Pop}TraceBounds
|
||||
vec3_t player_mins_backup[MAX_MAP_HULLS];
|
||||
vec3_t player_maxs_backup[MAX_MAP_HULLS];
|
||||
qboolean trace_bounds_pushed;
|
||||
|
||||
qboolean allow_console; // allow console in dev-mode or multiplayer game
|
||||
qboolean allow_console_init; // initial value to allow the console
|
||||
qboolean key_overstrike; // key overstrike mode
|
||||
@@ -354,12 +365,49 @@ extern host_parm_t host;
|
||||
|
||||
typedef void (*xcommand_t)( void );
|
||||
|
||||
//
|
||||
// zone.c
|
||||
//
|
||||
void Memory_Init( void );
|
||||
void _Mem_Free( void *data, const char *filename, int fileline );
|
||||
void *_Mem_Realloc( poolhandle_t poolptr, void *memptr, size_t size, qboolean clear, const char *filename, int fileline )
|
||||
ALLOC_CHECK( 3 ) WARN_UNUSED_RESULT;
|
||||
void *_Mem_Alloc( poolhandle_t poolptr, size_t size, qboolean clear, const char *filename, int fileline )
|
||||
ALLOC_CHECK( 2 ) MALLOC_LIKE( _Mem_Free, 1 ) WARN_UNUSED_RESULT;
|
||||
poolhandle_t _Mem_AllocPool( const char *name, const char *filename, int fileline )
|
||||
WARN_UNUSED_RESULT;
|
||||
void _Mem_FreePool( poolhandle_t *poolptr, const char *filename, int fileline );
|
||||
void _Mem_EmptyPool( poolhandle_t poolptr, const char *filename, int fileline );
|
||||
void _Mem_Check( const char *filename, int fileline );
|
||||
qboolean Mem_IsAllocatedExt( poolhandle_t poolptr, void *data );
|
||||
void Mem_PrintList( size_t minallocationsize );
|
||||
void Mem_PrintStats( void );
|
||||
|
||||
#define Mem_Malloc( pool, size ) _Mem_Alloc( pool, size, false, __FILE__, __LINE__ )
|
||||
#define Mem_Calloc( pool, size ) _Mem_Alloc( pool, size, true, __FILE__, __LINE__ )
|
||||
#define Mem_Realloc( pool, ptr, size ) _Mem_Realloc( pool, ptr, size, true, __FILE__, __LINE__ )
|
||||
#define Mem_Free( mem ) _Mem_Free( mem, __FILE__, __LINE__ )
|
||||
#define Mem_AllocPool( name ) _Mem_AllocPool( name, __FILE__, __LINE__ )
|
||||
#define Mem_FreePool( pool ) _Mem_FreePool( pool, __FILE__, __LINE__ )
|
||||
#define Mem_EmptyPool( pool ) _Mem_EmptyPool( pool, __FILE__, __LINE__ )
|
||||
#define Mem_IsAllocated( mem ) Mem_IsAllocatedExt( NULL, mem )
|
||||
#define Mem_Check() _Mem_Check( __FILE__, __LINE__ )
|
||||
|
||||
//
|
||||
// filesystem_engine.c
|
||||
//
|
||||
void FS_Init( const char *basedir );
|
||||
void FS_Shutdown( void );
|
||||
void *FS_GetNativeObject( const char *obj );
|
||||
int FS_Close( file_t *file );
|
||||
search_t *FS_Search( const char *pattern, int caseinsensitive, int gamedironly )
|
||||
MALLOC_LIKE( _Mem_Free, 1 ) WARN_UNUSED_RESULT;
|
||||
file_t *FS_Open( const char *filepath, const char *mode, qboolean gamedironly )
|
||||
MALLOC_LIKE( FS_Close, 1 ) WARN_UNUSED_RESULT;
|
||||
byte *FS_LoadFile( const char *path, fs_offset_t *filesizeptr, qboolean gamedironly )
|
||||
MALLOC_LIKE( _Mem_Free, 1 ) WARN_UNUSED_RESULT;
|
||||
byte *FS_LoadDirectFile( const char *path, fs_offset_t *filesizeptr )
|
||||
MALLOC_LIKE( _Mem_Free, 1 ) WARN_UNUSED_RESULT;
|
||||
|
||||
//
|
||||
// cmd.c
|
||||
@@ -392,30 +440,6 @@ void Cmd_ExecuteString( const char *text );
|
||||
void Cmd_ForwardToServer( void );
|
||||
void Cmd_Escape( char *newCommand, const char *oldCommand, int len );
|
||||
|
||||
//
|
||||
// zone.c
|
||||
//
|
||||
void Memory_Init( void );
|
||||
void *_Mem_Realloc( poolhandle_t poolptr, void *memptr, size_t size, qboolean clear, const char *filename, int fileline ) ALLOC_CHECK( 3 );
|
||||
void *_Mem_Alloc( poolhandle_t poolptr, size_t size, qboolean clear, const char *filename, int fileline ) ALLOC_CHECK( 2 );
|
||||
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_EmptyPool( poolhandle_t poolptr, const char *filename, int fileline );
|
||||
void _Mem_Free( void *data, const char *filename, int fileline );
|
||||
void _Mem_Check( const char *filename, int fileline );
|
||||
qboolean Mem_IsAllocatedExt( poolhandle_t poolptr, void *data );
|
||||
void Mem_PrintList( size_t minallocationsize );
|
||||
void Mem_PrintStats( void );
|
||||
|
||||
#define Mem_Malloc( pool, size ) _Mem_Alloc( pool, size, false, __FILE__, __LINE__ )
|
||||
#define Mem_Calloc( pool, size ) _Mem_Alloc( pool, size, true, __FILE__, __LINE__ )
|
||||
#define Mem_Realloc( pool, ptr, size ) _Mem_Realloc( pool, ptr, size, true, __FILE__, __LINE__ )
|
||||
#define Mem_Free( mem ) _Mem_Free( mem, __FILE__, __LINE__ )
|
||||
#define Mem_AllocPool( name ) _Mem_AllocPool( name, __FILE__, __LINE__ )
|
||||
#define Mem_FreePool( pool ) _Mem_FreePool( pool, __FILE__, __LINE__ )
|
||||
#define Mem_EmptyPool( pool ) _Mem_EmptyPool( pool, __FILE__, __LINE__ )
|
||||
#define Mem_IsAllocated( mem ) Mem_IsAllocatedExt( NULL, mem )
|
||||
#define Mem_Check() _Mem_Check( __FILE__, __LINE__ )
|
||||
|
||||
//
|
||||
// imagelib
|
||||
@@ -426,10 +450,10 @@ void Image_Setup( void );
|
||||
void Image_Init( void );
|
||||
void Image_Shutdown( void );
|
||||
void Image_AddCmdFlags( uint flags );
|
||||
rgbdata_t *FS_LoadImage( const char *filename, const byte *buffer, size_t size );
|
||||
qboolean FS_SaveImage( const char *filename, rgbdata_t *pix );
|
||||
rgbdata_t *FS_CopyImage( rgbdata_t *in );
|
||||
void FS_FreeImage( rgbdata_t *pack );
|
||||
rgbdata_t *FS_LoadImage( const char *filename, const byte *buffer, size_t size ) MALLOC_LIKE( FS_FreeImage, 1 ) WARN_UNUSED_RESULT;
|
||||
qboolean FS_SaveImage( const char *filename, rgbdata_t *pix );
|
||||
rgbdata_t *FS_CopyImage( rgbdata_t *in ) MALLOC_LIKE( FS_FreeImage, 1 ) WARN_UNUSED_RESULT;
|
||||
extern const bpc_desc_t PFDesc[]; // image get pixelformat
|
||||
qboolean Image_Process( rgbdata_t **pix, int width, int height, uint flags, float reserved );
|
||||
void Image_PaletteHueReplace( byte *palSrc, int newHue, int start, int end, int pal_size );
|
||||
@@ -484,15 +508,15 @@ typedef struct
|
||||
//
|
||||
void Sound_Init( void );
|
||||
void Sound_Shutdown( void );
|
||||
wavdata_t *FS_LoadSound( const char *filename, const byte *buffer, size_t size );
|
||||
void FS_FreeSound( wavdata_t *pack );
|
||||
stream_t *FS_OpenStream( const char *filename );
|
||||
void FS_FreeStream( stream_t *stream );
|
||||
wavdata_t *FS_LoadSound( const char *filename, const byte *buffer, size_t size ) MALLOC_LIKE( FS_FreeSound, 1 ) WARN_UNUSED_RESULT;
|
||||
stream_t *FS_OpenStream( const char *filename ) MALLOC_LIKE( FS_FreeStream, 1 ) WARN_UNUSED_RESULT;
|
||||
wavdata_t *FS_StreamInfo( stream_t *stream );
|
||||
int FS_ReadStream( stream_t *stream, int bytes, void *buffer );
|
||||
int FS_SetStreamPos( stream_t *stream, int newpos );
|
||||
int FS_GetStreamPos( stream_t *stream );
|
||||
void FS_FreeStream( stream_t *stream );
|
||||
qboolean Sound_Process( wavdata_t **wav, int rate, int width, uint flags );
|
||||
qboolean Sound_Process( wavdata_t **wav, int rate, int width, int channels, uint flags );
|
||||
uint Sound_GetApproxWavePlayLen( const char *filepath );
|
||||
qboolean Sound_SupportedFileFormat( const char *fileext );
|
||||
|
||||
@@ -556,7 +580,7 @@ qboolean SV_Active( void );
|
||||
char *COM_MemFgets( byte *pMemFile, int fileSize, int *filePos, char *pBuffer, int bufferSize );
|
||||
void COM_HexConvert( const char *pszInput, int nInputLength, byte *pOutput );
|
||||
int COM_SaveFile( const char *filename, const void *data, int len );
|
||||
byte* COM_LoadFileForMe( const char *filename, int *pLength );
|
||||
byte *COM_LoadFileForMe( const char *filename, int *pLength ) MALLOC_LIKE( free, 1 );
|
||||
qboolean COM_IsSafeFileToDownload( const char *filename );
|
||||
cvar_t *pfnCVarGetPointer( const char *szVarName );
|
||||
int pfnDrawConsoleString( int x, int y, char *string );
|
||||
@@ -646,6 +670,15 @@ void HPAK_FlushHostQueue( void );
|
||||
#define INPUT_DEVICE_JOYSTICK (1<<2)
|
||||
#define INPUT_DEVICE_VR (1<<3)
|
||||
|
||||
|
||||
typedef enum connprotocol_e
|
||||
{
|
||||
PROTO_CURRENT = 0, // Xash3D 49
|
||||
PROTO_LEGACY, // Xash3D 48
|
||||
PROTO_QUAKE, // Quake 15
|
||||
PROTO_GOLDSRC, // GoldSrc 48
|
||||
} connprotocol_t;
|
||||
|
||||
// shared calls
|
||||
struct physent_s;
|
||||
struct sv_client_s;
|
||||
@@ -656,10 +689,9 @@ qboolean CL_IsThirdPerson( void );
|
||||
qboolean CL_IsIntermission( void );
|
||||
qboolean CL_Initialized( void );
|
||||
char *CL_Userinfo( void );
|
||||
void CL_LegacyUpdateInfo( void );
|
||||
void CL_CharEvent( int key );
|
||||
qboolean CL_DisableVisibility( void );
|
||||
byte *COM_LoadFile( const char *filename, int usehunk, int *pLength );
|
||||
byte *COM_LoadFile( const char *filename, int usehunk, int *pLength ) MALLOC_LIKE( free, 1 );
|
||||
struct cmd_s *Cmd_GetFirstFunctionHandle( void );
|
||||
struct cmd_s *Cmd_GetNextFunctionHandle( struct cmd_s *cmd );
|
||||
struct cmdalias_s *Cmd_AliasGetList( void );
|
||||
@@ -744,6 +776,15 @@ int COM_CompareFileTime( const char *filename1, const char *filename2, int *iCom
|
||||
char *va( const char *format, ... ) _format( 1 );
|
||||
qboolean CRC32_MapFile( dword *crcvalue, const char *filename, qboolean multiplayer );
|
||||
|
||||
#if !XASH_DEDICATED
|
||||
connprotocol_t CL_Protocol( void );
|
||||
#else
|
||||
static inline connprotocol_t CL_Protocol( void )
|
||||
{
|
||||
return PROTO_CURRENT;
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline qboolean Host_IsLocalGame( void )
|
||||
{
|
||||
if( SV_Active( ))
|
||||
@@ -793,6 +834,16 @@ void NET_MasterClear( void );
|
||||
void NET_MasterShutdown( void );
|
||||
qboolean NET_GetMaster( netadr_t from, uint *challenge, double *last_heartbeat );
|
||||
|
||||
//
|
||||
// munge.c
|
||||
//
|
||||
void COM_Munge( byte *data, size_t len, int seq );
|
||||
void COM_UnMunge( byte *data, size_t len, int seq );
|
||||
void COM_Munge2( byte *data, size_t len, int seq );
|
||||
void COM_UnMunge2( byte *data, size_t len, int seq );
|
||||
void COM_Munge3( byte *data, size_t len, int seq );
|
||||
void COM_UnMunge3( byte *data, size_t len, int seq );
|
||||
|
||||
//
|
||||
// sounds.c
|
||||
//
|
||||
|
||||
@@ -1019,6 +1019,7 @@ autocomplete_list_t cmd_list[] =
|
||||
{ "changelevel", 1, Cmd_GetMapList },
|
||||
{ "playdemo", 1, Cmd_GetDemoList, },
|
||||
{ "timedemo", 1, Cmd_GetDemoList, },
|
||||
{ "listdemo", 1, Cmd_GetDemoList, },
|
||||
{ "playvol", 1, Cmd_GetSoundList },
|
||||
{ "hpkval", 1, Cmd_GetCustomList },
|
||||
{ "hpklist", 1, Cmd_GetCustomList },
|
||||
@@ -1201,7 +1202,7 @@ void Con_CompleteCommand( field_t *field )
|
||||
|
||||
if( !con.matchCount ) return; // no matches
|
||||
|
||||
memcpy( &temp, con.completionField, sizeof( field_t ) );
|
||||
temp = *con.completionField;
|
||||
|
||||
// autocomplete second arg
|
||||
if( (Cmd_Argc() >= 2) || ((Cmd_Argc() == 1) && nextcmd) )
|
||||
|
||||
@@ -92,7 +92,7 @@ static void Sys_StackTrace( PEXCEPTION_POINTERS pInfo )
|
||||
STACKFRAME64 stackframe;
|
||||
DWORD image;
|
||||
|
||||
memcpy( &context, pInfo->ContextRecord, sizeof( CONTEXT ));
|
||||
context = *pInfo->ContextRecord;
|
||||
|
||||
options = SymGetOptions();
|
||||
options |= SYMOPT_DEBUG;
|
||||
|
||||
+120
-22
@@ -70,15 +70,14 @@ find the specified variable by name
|
||||
*/
|
||||
convar_t *Cvar_FindVarExt( const char *var_name, int ignore_group )
|
||||
{
|
||||
// TODO: ignore group for cvar
|
||||
#if defined(XASH_HASHED_VARS)
|
||||
return (convar_t *)BaseCmd_Find( HM_CVAR, var_name );
|
||||
#else
|
||||
convar_t *var;
|
||||
convar_t *var;
|
||||
|
||||
if( !var_name )
|
||||
return NULL;
|
||||
|
||||
#if defined(XASH_HASHED_VARS) // TODO: ignore_group
|
||||
var = BaseCmd_Find( HM_CVAR, var_name );
|
||||
#else
|
||||
for( var = cvar_vars; var; var = var->next )
|
||||
{
|
||||
if( ignore_group && FBitSet( ignore_group, var->flags ))
|
||||
@@ -87,9 +86,13 @@ convar_t *Cvar_FindVarExt( const char *var_name, int ignore_group )
|
||||
if( !Q_stricmp( var_name, var->name ))
|
||||
return var;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
#endif
|
||||
|
||||
// HACKHACK: HL25 compatibility
|
||||
if( !var && !Q_stricmp( var_name, "gl_widescreen_yfov" ))
|
||||
var = Cvar_FindVarExt( "r_adjust_fov", ignore_group );
|
||||
|
||||
return var;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -230,7 +233,7 @@ static const char *Cvar_ValidateString( convar_t *var, const char *value )
|
||||
if( !COM_CheckStringEmpty( szNew ) ) Q_strncpy( szNew, "empty", sizeof( szNew ));
|
||||
}
|
||||
|
||||
if( FBitSet( var->flags, FCVAR_NOEXTRAWHITEPACE ))
|
||||
if( FBitSet( var->flags, FCVAR_NOEXTRAWHITESPACE ))
|
||||
{
|
||||
char *szVal = szNew;
|
||||
int len = 0;
|
||||
@@ -272,6 +275,15 @@ static qboolean Cvar_ValidateVarName( const char *s, qboolean isvalue )
|
||||
return true;
|
||||
}
|
||||
|
||||
static void Cvar_Free( convar_t *var )
|
||||
{
|
||||
freestring( var->name );
|
||||
freestring( var->string );
|
||||
freestring( var->def_string );
|
||||
freestring( var->desc );
|
||||
Mem_Free( var );
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
Cvar_UnlinkVar
|
||||
@@ -311,17 +323,13 @@ static int Cvar_UnlinkVar( const char *var_name, int group )
|
||||
#endif
|
||||
|
||||
// unlink variable from list
|
||||
freestring( var->string );
|
||||
*prev = var->next;
|
||||
|
||||
// only allocated cvars can throw these fields
|
||||
if( FBitSet( var->flags, FCVAR_ALLOCATED ))
|
||||
{
|
||||
freestring( var->name );
|
||||
freestring( var->def_string );
|
||||
freestring( var->desc );
|
||||
Mem_Free( var );
|
||||
}
|
||||
Cvar_Free( var );
|
||||
else
|
||||
freestring( var->string );
|
||||
count++;
|
||||
}
|
||||
|
||||
@@ -1217,6 +1225,20 @@ static void Cvar_List_f( void )
|
||||
Con_Printf( "\n%i cvars\n", count );
|
||||
}
|
||||
|
||||
static qboolean Cvar_ValidateUnlinkGroup( int group )
|
||||
{
|
||||
if( FBitSet( group, FCVAR_EXTDLL ) && !Cvar_VariableInteger( "host_gameloaded" ))
|
||||
return false;
|
||||
|
||||
if( FBitSet( group, FCVAR_CLIENTDLL ) && !Cvar_VariableInteger( "host_clientloaded" ))
|
||||
return false;
|
||||
|
||||
if( FBitSet( group, FCVAR_GAMEUIDLL ) && !Cvar_VariableInteger( "host_gameuiloaded" ))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
Cvar_Unlink
|
||||
@@ -1228,19 +1250,95 @@ void Cvar_Unlink( int group )
|
||||
{
|
||||
int count;
|
||||
|
||||
if( Cvar_VariableInteger( "host_gameloaded" ) && FBitSet( group, FCVAR_EXTDLL ))
|
||||
return;
|
||||
|
||||
if( Cvar_VariableInteger( "host_clientloaded" ) && FBitSet( group, FCVAR_CLIENTDLL ))
|
||||
return;
|
||||
|
||||
if( Cvar_VariableInteger( "host_gameuiloaded" ) && FBitSet( group, FCVAR_GAMEUIDLL ))
|
||||
if( !Cvar_ValidateUnlinkGroup( group ))
|
||||
return;
|
||||
|
||||
count = Cvar_UnlinkVar( NULL, group );
|
||||
Con_Reportf( "unlink %i cvars\n", count );
|
||||
}
|
||||
|
||||
pending_cvar_t *Cvar_PrepareToUnlink( int group )
|
||||
{
|
||||
pending_cvar_t *list = NULL;
|
||||
pending_cvar_t *tail = NULL;
|
||||
convar_t *cv;
|
||||
|
||||
for( cv = cvar_vars; cv != NULL; cv = cv->next )
|
||||
{
|
||||
size_t namelen;
|
||||
pending_cvar_t *p;
|
||||
|
||||
if( !FBitSet( cv->flags, group ))
|
||||
continue;
|
||||
|
||||
namelen = Q_strlen( cv->name ) + 1;
|
||||
p = Mem_Malloc( host.mempool, sizeof( *list ) + namelen );
|
||||
p->next = NULL;
|
||||
p->cv_cur = cv;
|
||||
p->cv_next = cv->next;
|
||||
p->cv_allocated = FBitSet( cv->flags, FCVAR_ALLOCATED ) ? true : false;
|
||||
Q_strncpy( p->cv_name, cv->name, namelen );
|
||||
|
||||
if( list == NULL )
|
||||
list = p;
|
||||
else
|
||||
tail->next = p;
|
||||
|
||||
tail = p;
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
void Cvar_UnlinkPendingCvars( pending_cvar_t *list )
|
||||
{
|
||||
int count = 0;
|
||||
|
||||
while( list != NULL )
|
||||
{
|
||||
pending_cvar_t *next = list->next;
|
||||
convar_t *cv_prev, *cv;
|
||||
|
||||
for( cv_prev = NULL, cv = cvar_vars; cv != NULL; cv_prev = cv, cv = cv->next )
|
||||
{
|
||||
if( cv == list->cv_cur )
|
||||
break;
|
||||
}
|
||||
|
||||
if( cv == NULL )
|
||||
{
|
||||
Con_Reportf( "%s: can't find %s in variable list\n", __func__, list->cv_name );
|
||||
Mem_Free( list );
|
||||
list = next;
|
||||
continue;
|
||||
}
|
||||
|
||||
// unlink cvar from list
|
||||
BaseCmd_Remove( HM_CVAR, list->cv_name );
|
||||
if( cv_prev != NULL )
|
||||
cv_prev->next = list->cv_next;
|
||||
else cvar_vars = list->cv_next;
|
||||
|
||||
if( list->cv_allocated )
|
||||
Cvar_Free( list->cv_cur );
|
||||
else
|
||||
{
|
||||
// TODO: can't free cvar string here because
|
||||
// it's not safe to access cv_cur and
|
||||
// can't save string pointer because it could've been changed
|
||||
// and pointer to it is already lost
|
||||
// freestring( list->cv_string );
|
||||
}
|
||||
|
||||
// now free pending cvar
|
||||
Mem_Free( list );
|
||||
list = next;
|
||||
count++;
|
||||
}
|
||||
|
||||
Con_Reportf( "unlink %i cvars\n", count );
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
Cvar_Init
|
||||
|
||||
+12
-37
@@ -18,45 +18,18 @@ GNU General Public License for more details.
|
||||
|
||||
#include "cvardef.h"
|
||||
|
||||
#ifdef XASH_64BIT
|
||||
#define CVAR_SENTINEL 0xDEADBEEFDEADBEEF
|
||||
#else
|
||||
#define CVAR_SENTINEL 0xDEADBEEF
|
||||
#endif
|
||||
#define CVAR_CHECK_SENTINEL( cv ) ((uintptr_t)(cv)->next == CVAR_SENTINEL)
|
||||
|
||||
// NOTE: if this is changed, it must be changed in cvardef.h too
|
||||
typedef struct convar_s
|
||||
// As some mods dynamically allocate cvars and free them without notifying the engine
|
||||
// let's construct a list of cvars that must be removed
|
||||
typedef struct pending_cvar_s
|
||||
{
|
||||
// this part shared with cvar_t
|
||||
char *name;
|
||||
char *string;
|
||||
int flags;
|
||||
float value;
|
||||
struct convar_s *next;
|
||||
struct pending_cvar_s *next;
|
||||
|
||||
// this part unique for convar_t
|
||||
char *desc; // variable descrition info
|
||||
char *def_string; // keep pointer to initial value
|
||||
} convar_t;
|
||||
convar_t *cv_cur; // preserve the data that might get freed
|
||||
convar_t *cv_next;
|
||||
qboolean cv_allocated; // if it's allocated by us, it's safe to access cv_cur
|
||||
char cv_name[];
|
||||
} pending_cvar_t;
|
||||
|
||||
// cvar internal flags
|
||||
#define FCVAR_RENDERINFO (1<<16) // save to a seperate config called video.cfg
|
||||
#define FCVAR_READ_ONLY (1<<17) // cannot be set by user at all, and can't be requested by CvarGetPointer from game dlls
|
||||
#define FCVAR_EXTENDED (1<<18) // this is convar_t (sets on registration)
|
||||
#define FCVAR_ALLOCATED (1<<19) // this convar_t is fully dynamic allocated (include description)
|
||||
#define FCVAR_VIDRESTART (1<<20) // recreate the window is cvar with this flag was changed
|
||||
#define FCVAR_TEMPORARY (1<<21) // these cvars holds their values and can be unlink in any time
|
||||
#define FCVAR_MOVEVARS (1<<22) // this cvar is a part of movevars_t struct that shared between client and server
|
||||
#define FCVAR_USER_CREATED (1<<23) // created by a set command (dll's used)
|
||||
|
||||
#define CVAR_DEFINE( cv, cvname, cvstr, cvflags, cvdesc ) \
|
||||
convar_t cv = { (char*)cvname, (char*)cvstr, cvflags, 0.0f, (void *)CVAR_SENTINEL, (char*)cvdesc, NULL }
|
||||
|
||||
#define CVAR_DEFINE_AUTO( cv, cvstr, cvflags, cvdesc ) \
|
||||
CVAR_DEFINE( cv, #cv, cvstr, cvflags, cvdesc )
|
||||
|
||||
#ifndef REF_DLL
|
||||
cvar_t *Cvar_GetList( void );
|
||||
#define Cvar_FindVar( name ) Cvar_FindVarExt( name, 0 )
|
||||
convar_t *Cvar_FindVarExt( const char *var_name, int ignore_group );
|
||||
@@ -81,6 +54,8 @@ qboolean Cvar_CommandWithPrivilegeCheck( convar_t *v, qboolean isPrivileged );
|
||||
void Cvar_Init( void );
|
||||
void Cvar_PostFSInit( void );
|
||||
void Cvar_Unlink( int group );
|
||||
#endif // REF_DLL
|
||||
|
||||
pending_cvar_t *Cvar_PrepareToUnlink( int group );
|
||||
void Cvar_UnlinkPendingCvars( pending_cvar_t *pending_cvars );
|
||||
|
||||
#endif//CVAR_H
|
||||
|
||||
@@ -134,11 +134,6 @@ void GAME_EXPORT S_StopSound(int entnum, int channel, const char *soundname)
|
||||
|
||||
}
|
||||
|
||||
int S_GetCurrentStaticSounds( soundlist_t *pout, int size )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int GAME_EXPORT CL_GetMaxClients( void )
|
||||
{
|
||||
return 0;
|
||||
|
||||
@@ -27,6 +27,31 @@ fs_globals_t *FI;
|
||||
static pfnCreateInterface_t fs_pfnCreateInterface;
|
||||
static HINSTANCE fs_hInstance;
|
||||
|
||||
search_t *FS_Search( const char *pattern, int caseinsensitive, int gamedironly )
|
||||
{
|
||||
return g_fsapi.Search( pattern, caseinsensitive, gamedironly );
|
||||
}
|
||||
|
||||
int FS_Close( file_t *file )
|
||||
{
|
||||
return g_fsapi.Close( file );
|
||||
}
|
||||
|
||||
file_t *FS_Open( const char *filepath, const char *mode, qboolean gamedironly )
|
||||
{
|
||||
return g_fsapi.Open( filepath, mode, gamedironly );
|
||||
}
|
||||
|
||||
byte *FS_LoadFile( const char *path, fs_offset_t *filesizeptr, qboolean gamedironly )
|
||||
{
|
||||
return g_fsapi.LoadFile( path, filesizeptr, gamedironly );
|
||||
}
|
||||
|
||||
byte *FS_LoadDirectFile( const char *path, fs_offset_t *filesizeptr )
|
||||
{
|
||||
return g_fsapi.LoadDirectFile( path, filesizeptr );
|
||||
}
|
||||
|
||||
static void COM_StripDirectorySlash( char *pname )
|
||||
{
|
||||
size_t len;
|
||||
@@ -59,7 +84,7 @@ static void FS_Path_f_( void )
|
||||
FS_Path_f();
|
||||
}
|
||||
|
||||
static fs_interface_t fs_memfuncs =
|
||||
static const fs_interface_t fs_memfuncs =
|
||||
{
|
||||
Con_Printf,
|
||||
Con_DPrintf,
|
||||
@@ -221,7 +246,13 @@ void FS_Init( const char *basedir )
|
||||
COM_StripDirectorySlash( rodir );
|
||||
|
||||
if( !Sys_GetParmFromCmdLine( "-game", gamedir ))
|
||||
Q_strncpy( gamedir, basedir, sizeof( gamedir )); // gamedir == basedir
|
||||
{
|
||||
char *env = getenv( "XASH3D_GAME" );
|
||||
if( env )
|
||||
Q_strncpy( gamedir, env, sizeof( gamedir ));
|
||||
else
|
||||
Q_strncpy( gamedir, basedir, sizeof( gamedir )); // gamedir == basedir
|
||||
}
|
||||
|
||||
FS_LoadProgs();
|
||||
|
||||
|
||||
+13
-3
@@ -73,6 +73,7 @@ static feature_message_t bugcomp_features[] =
|
||||
{
|
||||
{ BUGCOMP_PENTITYOFENTINDEX_FLAG, "pfnPEntityOfEntIndex bugfix revert", "peoei" },
|
||||
{ BUGCOMP_MESSAGE_REWRITE_FACILITY_FLAG, "GoldSrc Message Rewrite Facility", "gsmrf" },
|
||||
{ BUGCOMP_SPATIALIZE_SOUND_WITH_ATTN_NONE, "spatialize sounds with zero attenuation", "sp_attn_none" },
|
||||
};
|
||||
|
||||
static feature_message_t engine_features[] =
|
||||
@@ -1028,8 +1029,8 @@ static void Host_InitCommon( int argc, char **argv, const char *progname, qboole
|
||||
}
|
||||
#endif
|
||||
|
||||
// always enable console for Quake
|
||||
if( !host.allow_console && ( Sys_CheckParm( "-console" ) || !Q_strnicmp( exename, "quake", 5 )))
|
||||
// always enable console for Quake and dedicated
|
||||
if( !host.allow_console && ( Host_IsDedicated() || Sys_CheckParm( "-console" ) || !Q_strnicmp( exename, "quake", 5 )))
|
||||
host.allow_console = true;
|
||||
|
||||
// member console allowing
|
||||
@@ -1078,7 +1079,16 @@ static void Host_InitCommon( int argc, char **argv, const char *progname, qboole
|
||||
|
||||
// print current developer level to simplify processing users feedback
|
||||
if( developer > 0 )
|
||||
Con_Printf( "Developer level: ^3%i\n", developer );
|
||||
{
|
||||
int i;
|
||||
|
||||
Con_Printf( "Program args: " S_YELLOW );
|
||||
for( i = 0; i < host.argc; i++ )
|
||||
Con_Printf( "%s ", host.argv[i] );
|
||||
Con_Printf( S_DEFAULT "\n" );
|
||||
|
||||
Con_Printf( "Developer level: " S_YELLOW "%i" S_DEFAULT "\n", developer );
|
||||
}
|
||||
|
||||
host.bugcomp = Host_CheckBugcomp();
|
||||
|
||||
|
||||
@@ -67,7 +67,7 @@ typedef struct dresource_s
|
||||
} dresource_t;
|
||||
#pragma pack( pop )
|
||||
|
||||
STATIC_ASSERT( sizeof( dresource_t ) == 136, "invalid dresource_t size, HPAKs won't be compatible (no custom logo in multiplayer!)" );
|
||||
STATIC_CHECK_SIZEOF( dresource_t, 136, 136 );
|
||||
|
||||
typedef struct
|
||||
{
|
||||
@@ -76,6 +76,8 @@ typedef struct
|
||||
int infotableofs;
|
||||
} hpak_header_t;
|
||||
|
||||
STATIC_CHECK_SIZEOF( hpak_header_t, 12, 12 );
|
||||
|
||||
typedef struct
|
||||
{
|
||||
dresource_t resource;
|
||||
@@ -83,6 +85,8 @@ typedef struct
|
||||
int disksize;
|
||||
} hpak_lump_t;
|
||||
|
||||
STATIC_CHECK_SIZEOF( hpak_lump_t, 144, 144 );
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int count;
|
||||
|
||||
@@ -108,12 +108,13 @@ typedef struct imglib_s
|
||||
|
||||
enum
|
||||
{
|
||||
LUMP_NORMAL = 0, // no alpha
|
||||
LUMP_MASKED, // 1-bit alpha channel masked texture
|
||||
LUMP_GRADIENT, // gradient image (decals)
|
||||
LUMP_EXTENDED, // bmp images have extened palette with alpha-channel
|
||||
LUMP_HALFLIFE, // get predefined half-life palette
|
||||
LUMP_QUAKE1 // get predefined quake palette
|
||||
LUMP_NORMAL = 0, // no alpha
|
||||
LUMP_MASKED, // 1-bit alpha channel masked texture
|
||||
LUMP_GRADIENT, // gradient image (decals)
|
||||
LUMP_EXTENDED, // bmp images have extened palette with alpha-channel
|
||||
LUMP_HALFLIFE, // get predefined half-life palette
|
||||
LUMP_QUAKE1, // get predefined quake palette
|
||||
LUMP_TEXGAMMA, // apply texgamma on top of palette, for half-life mips
|
||||
};
|
||||
|
||||
enum
|
||||
|
||||
@@ -110,7 +110,7 @@ void Image_Reset( void )
|
||||
image.size = 0;
|
||||
}
|
||||
|
||||
static rgbdata_t *ImagePack( void )
|
||||
static MALLOC_LIKE( FS_FreeImage, 1 ) rgbdata_t *ImagePack( void )
|
||||
{
|
||||
rgbdata_t *pack;
|
||||
|
||||
@@ -547,7 +547,7 @@ static void Test_CheckImage( const char *name, rgbdata_t *rgb )
|
||||
TASSERT( load->size == rgb->size )
|
||||
TASSERT( memcmp(load->buffer, rgb->buffer, rgb->size ) == 0 )
|
||||
|
||||
Mem_Free( load );
|
||||
FS_FreeImage( load );
|
||||
}
|
||||
|
||||
void Test_RunImagelib( void )
|
||||
|
||||
@@ -174,8 +174,8 @@ byte *Image_Copy( size_t size )
|
||||
{
|
||||
byte *out;
|
||||
|
||||
out = Mem_Malloc( host.imagepool, size );
|
||||
memcpy( out, image.tempbuffer, size );
|
||||
out = Mem_Realloc( host.imagepool, image.tempbuffer, size );
|
||||
image.tempbuffer = NULL;
|
||||
|
||||
return out;
|
||||
}
|
||||
@@ -293,9 +293,18 @@ static void Image_SetPalette( const byte *pal, uint *d_table )
|
||||
case LUMP_NORMAL:
|
||||
for( i = 0; i < 256; i++ )
|
||||
{
|
||||
rgba[0] = TextureToGamma( pal[i*3+0] );
|
||||
rgba[1] = TextureToGamma( pal[i*3+1] );
|
||||
rgba[2] = TextureToGamma( pal[i*3+2] );
|
||||
memcpy( rgba, &pal[i * 3], 3 );
|
||||
rgba[3] = 0xFF;
|
||||
memcpy( &uirgba, rgba, sizeof( uirgba ));
|
||||
d_table[i] = uirgba;
|
||||
}
|
||||
break;
|
||||
case LUMP_TEXGAMMA:
|
||||
for( i = 0; i < 256; i++ )
|
||||
{
|
||||
rgba[0] = TextureToGamma( pal[i * 3 + 0] );
|
||||
rgba[1] = TextureToGamma( pal[i * 3 + 1] );
|
||||
rgba[2] = TextureToGamma( pal[i * 3 + 2] );
|
||||
rgba[3] = 0xFF;
|
||||
memcpy( &uirgba, rgba, sizeof( uirgba ));
|
||||
d_table[i] = uirgba;
|
||||
@@ -1374,20 +1383,20 @@ static qboolean Image_RemapInternal( rgbdata_t *pic, int topColor, int bottomCol
|
||||
return true;
|
||||
}
|
||||
|
||||
qboolean Image_Process(rgbdata_t **pix, int width, int height, uint flags, float reserved )
|
||||
qboolean Image_Process( rgbdata_t **pix, int width, int height, uint flags, float reserved )
|
||||
{
|
||||
rgbdata_t *pic = *pix;
|
||||
qboolean result = true;
|
||||
byte *out;
|
||||
|
||||
// check for buffers
|
||||
if( !pic || !pic->buffer )
|
||||
if( unlikely( !pic || !pic->buffer ))
|
||||
{
|
||||
image.force_flags = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
if( !flags )
|
||||
if( unlikely( !flags ))
|
||||
{
|
||||
// clear any force flags
|
||||
image.force_flags = 0;
|
||||
@@ -1432,7 +1441,7 @@ qboolean Image_Process(rgbdata_t **pix, int width, int height, uint flags, float
|
||||
pic->width = w, pic->height = h;
|
||||
pic->size = w * h * PFDesc[pic->type].bpp;
|
||||
Mem_Free( pic->buffer ); // free original image buffer
|
||||
pic->buffer = Image_Copy( pic->size ); // unzone buffer (don't touch image.tempbuffer)
|
||||
pic->buffer = Image_Copy( pic->size ); // unzone buffer
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -427,8 +427,18 @@ qboolean Image_LoadMIP( const char *name, const byte *buffer, fs_offset_t filesi
|
||||
}
|
||||
|
||||
if( pal_type == PAL_QUAKE1 )
|
||||
{
|
||||
SetBits( image.flags, IMAGE_QUAKEPAL );
|
||||
rendermode = LUMP_NORMAL;
|
||||
|
||||
// if texture was converted from quake to half-life with no palette changes
|
||||
// then applying texgamma might make it too dark or even outright broken
|
||||
rendermode = LUMP_NORMAL;
|
||||
}
|
||||
else
|
||||
{
|
||||
// half-life mips need texgamma applied
|
||||
rendermode = LUMP_TEXGAMMA;
|
||||
}
|
||||
}
|
||||
|
||||
Image_GetPaletteLMP( pal, rendermode );
|
||||
|
||||
@@ -23,9 +23,8 @@ GNU General Public License for more details.
|
||||
#include "build.h"
|
||||
#include "common.h"
|
||||
|
||||
#define E_GAME "XASH3D_GAME" // default env dir to start from
|
||||
#ifndef XASH_GAMEDIR
|
||||
#define XASH_GAMEDIR "valve"
|
||||
#define XASH_GAMEDIR "valve" // !!! Replace with your default (base) game directory !!!
|
||||
#endif
|
||||
|
||||
#if XASH_WIN32
|
||||
@@ -47,12 +46,7 @@ static void Sys_ChangeGame( const char *progname )
|
||||
|
||||
static int Sys_Start( void )
|
||||
{
|
||||
const char *game = getenv( E_GAME );
|
||||
|
||||
if( !game )
|
||||
game = XASH_GAMEDIR;
|
||||
|
||||
Q_strncpy( szGameDir, game, sizeof( szGameDir ));
|
||||
Q_strncpy( szGameDir, XASH_GAMEDIR, sizeof( szGameDir ));
|
||||
|
||||
#if XASH_EMSCRIPTEN
|
||||
#ifdef EMSCRIPTEN_LIB_FS
|
||||
@@ -73,7 +67,7 @@ static int Sys_Start( void )
|
||||
IOS_LaunchDialog();
|
||||
#endif
|
||||
|
||||
return Host_Main( szArgc, szArgv, game, 0, Sys_ChangeGame );
|
||||
return Host_Main( szArgc, szArgv, szGameDir, 0, Sys_ChangeGame );
|
||||
}
|
||||
|
||||
int main( int argc, char **argv )
|
||||
|
||||
+22
-16
@@ -21,6 +21,7 @@ typedef struct master_s
|
||||
struct master_s *next;
|
||||
qboolean sent; // TODO: get rid of this internal state
|
||||
qboolean save;
|
||||
qboolean v6only;
|
||||
string address;
|
||||
netadr_t adr; // temporary, rewritten after each send
|
||||
|
||||
@@ -45,7 +46,7 @@ NET_GetMasterHostByName
|
||||
*/
|
||||
static net_gai_state_t NET_GetMasterHostByName( master_t *m )
|
||||
{
|
||||
net_gai_state_t res = NET_StringToAdrNB( m->address, &m->adr );
|
||||
net_gai_state_t res = NET_StringToAdrNB( m->address, &m->adr, m->v6only );
|
||||
|
||||
if( res == NET_EAI_OK )
|
||||
return res;
|
||||
@@ -251,7 +252,7 @@ NET_AddMaster
|
||||
Add master to the list
|
||||
========================
|
||||
*/
|
||||
static void NET_AddMaster( const char *addr, qboolean save )
|
||||
static void NET_AddMaster( const char *addr, qboolean save, qboolean v6only )
|
||||
{
|
||||
master_t *master, *last;
|
||||
|
||||
@@ -261,10 +262,11 @@ static void NET_AddMaster( const char *addr, qboolean save )
|
||||
return;
|
||||
}
|
||||
|
||||
master = Mem_Malloc( host.mempool, sizeof( master_t ) );
|
||||
master = Mem_Malloc( host.mempool, sizeof( *master ) );
|
||||
Q_strncpy( master->address, addr, sizeof( master->address ));
|
||||
master->sent = false;
|
||||
master->save = save;
|
||||
master->v6only = v6only;
|
||||
master->next = NULL;
|
||||
master->adr.type = 0;
|
||||
|
||||
@@ -283,7 +285,7 @@ static void NET_AddMaster_f( void )
|
||||
return;
|
||||
}
|
||||
|
||||
NET_AddMaster( Cmd_Argv( 1 ), true ); // save them into config
|
||||
NET_AddMaster( Cmd_Argv( 1 ), true, false ); // save them into config
|
||||
ml.modified = true; // save config
|
||||
}
|
||||
|
||||
@@ -316,15 +318,14 @@ static void NET_ListMasters_f( void )
|
||||
master_t *list;
|
||||
int i;
|
||||
|
||||
Msg( "Master servers\n=============\n" );
|
||||
|
||||
Con_Printf( "Master servers:\n" );
|
||||
|
||||
for( i = 1, list = ml.list; list; i++, list = list->next )
|
||||
{
|
||||
Msg( "%d\t%s", i, list->address );
|
||||
Con_Printf( "%d\t%s", i, list->address );
|
||||
if( list->adr.type != 0 )
|
||||
Msg( "\t%s\n", NET_AdrToString( list->adr ));
|
||||
else Msg( "\n" );
|
||||
Con_Printf( "\t%s\n", NET_AdrToString( list->adr ));
|
||||
else Con_Printf( "\n" );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -354,11 +355,15 @@ static void NET_LoadMasters( void )
|
||||
// format: master <addr>\n
|
||||
while( ( pfile = COM_ParseFile( pfile, token, sizeof( token ) ) ) )
|
||||
{
|
||||
if( !Q_strcmp( token, "master" ) ) // load addr
|
||||
if( !Q_strcmp( token, "master" )) // load addr
|
||||
{
|
||||
pfile = COM_ParseFile( pfile, token, sizeof( token ) );
|
||||
|
||||
NET_AddMaster( token, true );
|
||||
NET_AddMaster( token, true, false );
|
||||
}
|
||||
else if( !Q_strcmp( token, "master6" ))
|
||||
{
|
||||
pfile = COM_ParseFile( pfile, token, sizeof( token ) );
|
||||
NET_AddMaster( token, true, true );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -396,7 +401,7 @@ void NET_SaveMasters( void )
|
||||
for( m = ml.list; m; m = m->next )
|
||||
{
|
||||
if( m->save )
|
||||
FS_Printf( f, "master %s\n", m->address );
|
||||
FS_Printf( f, "%s %s\n", m->v6only ? "master6" : "master", m->address );
|
||||
}
|
||||
|
||||
FS_Close( f );
|
||||
@@ -418,9 +423,10 @@ void NET_InitMasters( void )
|
||||
Cvar_RegisterVariable( &sv_verbose_heartbeats );
|
||||
|
||||
// keep main master always there
|
||||
NET_AddMaster( MASTERSERVER_ADR, false );
|
||||
NET_AddMaster( "aaaa.mentality.rip:27010", false ); // IPv6-only
|
||||
NET_AddMaster( "mentality.rip:27011", false );
|
||||
NET_AddMaster( MASTERSERVER_ADR, false, false );
|
||||
NET_AddMaster( "aaaa.mentality.rip:27010", false, true ); // IPv6-only
|
||||
NET_AddMaster( "mentality.rip:27011", false, false ); // testing server, might be offline
|
||||
NET_AddMaster( "aaaa.mentality.rip:27011", false, true ); // IPv6-only, testing server, might be offline
|
||||
|
||||
NET_LoadMasters( );
|
||||
}
|
||||
|
||||
@@ -0,0 +1,241 @@
|
||||
/*
|
||||
mod_alias.c - alias model loading
|
||||
Copyright (C) 2010 Uncle Mike
|
||||
Copyright (C) 2024 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 "common.h"
|
||||
#include "alias.h"
|
||||
#if !XASH_DEDICATED
|
||||
#include "ref_common.h"
|
||||
#endif // XASH_DEDICATED
|
||||
#include "mod_local.h"
|
||||
#include "xash3d_mathlib.h"
|
||||
|
||||
static int g_posenum = 0;
|
||||
static const trivertex_t *g_poseverts[MAXALIASFRAMES];
|
||||
|
||||
static const void *Mod_LoadAliasFrame( const daliasframe_t *pdaliasframe, maliasframedesc_t *frame, const aliashdr_t *aliashdr )
|
||||
{
|
||||
const trivertex_t *pinframe;
|
||||
int i;
|
||||
|
||||
Q_strncpy( frame->name, pdaliasframe->name, sizeof( frame->name ));
|
||||
frame->firstpose = g_posenum;
|
||||
frame->numposes = 1;
|
||||
|
||||
for( i = 0; i < 3; i++ )
|
||||
{
|
||||
frame->bboxmin.v[i] = pdaliasframe->bboxmin.v[i];
|
||||
frame->bboxmax.v[i] = pdaliasframe->bboxmax.v[i];
|
||||
}
|
||||
|
||||
pinframe = (const trivertex_t *)(pdaliasframe + 1);
|
||||
|
||||
g_poseverts[g_posenum] = pinframe;
|
||||
g_posenum++;
|
||||
|
||||
pinframe += aliashdr->numverts;
|
||||
|
||||
return (void *)pinframe;
|
||||
}
|
||||
|
||||
static const void *Mod_LoadAliasGroup( const daliasgroup_t *pingroup, maliasframedesc_t *frame, const aliashdr_t *aliashdr )
|
||||
{
|
||||
const daliasinterval_t *pin_intervals;
|
||||
const void *ptemp;
|
||||
int i, numframes;
|
||||
|
||||
frame->firstpose = g_posenum;
|
||||
frame->numposes = numframes = pingroup->numframes;
|
||||
|
||||
for( i = 0; i < 3; i++ )
|
||||
{
|
||||
frame->bboxmin.v[i] = pingroup->bboxmin.v[i];
|
||||
frame->bboxmax.v[i] = pingroup->bboxmax.v[i];
|
||||
}
|
||||
|
||||
pin_intervals = (const daliasinterval_t *)(pingroup + 1);
|
||||
|
||||
// all the intervals are always equal 0.1 so we don't care about them
|
||||
frame->interval = pin_intervals->interval;
|
||||
pin_intervals += numframes;
|
||||
ptemp = (void *)pin_intervals;
|
||||
|
||||
for( i = 0; i < numframes; i++ )
|
||||
{
|
||||
g_poseverts[g_posenum] = (const trivertex_t *)((const daliasframe_t *)ptemp + 1);
|
||||
ptemp = g_poseverts[g_posenum] + aliashdr->numverts;
|
||||
g_posenum++;
|
||||
}
|
||||
|
||||
return ptemp;
|
||||
}
|
||||
|
||||
static void Mod_CalcAliasBounds( model_t *mod, const aliashdr_t *aliashdr )
|
||||
{
|
||||
int i, j, k;
|
||||
float radius;
|
||||
float dist;
|
||||
vec3_t v;
|
||||
|
||||
ClearBounds( mod->mins, mod->maxs );
|
||||
radius = 0.0f;
|
||||
|
||||
// process verts
|
||||
for( i = 0; i < aliashdr->numposes; i++ )
|
||||
{
|
||||
for( j = 0; j < aliashdr->numverts; j++ )
|
||||
{
|
||||
for( k = 0; k < 3; k++ )
|
||||
v[k] = g_poseverts[i][j].v[k] * aliashdr->scale[k] + aliashdr->scale_origin[k];
|
||||
|
||||
AddPointToBounds( v, mod->mins, mod->maxs );
|
||||
dist = DotProduct( v, v );
|
||||
|
||||
if( radius < dist )
|
||||
radius = dist;
|
||||
}
|
||||
}
|
||||
|
||||
mod->radius = sqrt( radius );
|
||||
}
|
||||
|
||||
static const void *Mod_LoadAllSkins( model_t *mod, int numskins, const daliasskintype_t *pskintype, const aliashdr_t *aliashdr )
|
||||
{
|
||||
int i, size;
|
||||
|
||||
if(( numskins < 1 ) || ( numskins > MAX_SKINS ))
|
||||
Host_Error( "%s: Invalid # of skins: %d\n", __func__, numskins );
|
||||
|
||||
size = aliashdr->skinwidth * aliashdr->skinheight;
|
||||
|
||||
// just skipping textures, renderer will take care of them later
|
||||
for( i = 0; i < numskins; i++ )
|
||||
{
|
||||
if( pskintype->type == ALIAS_SKIN_SINGLE )
|
||||
{
|
||||
const byte *ptexture = (const byte *)&pskintype[1];
|
||||
|
||||
pskintype = (const daliasskintype_t *)( ptexture + size );
|
||||
}
|
||||
else
|
||||
{
|
||||
const daliasskingroup_t *pinskingroup = (const daliasskingroup_t *)&pskintype[1];
|
||||
const daliasskininterval_t *pinskinintervals = (const daliasskininterval_t *)&pinskingroup[1];
|
||||
const byte *ptexture = (const byte *)&pinskinintervals[pinskingroup->numskins];
|
||||
|
||||
pskintype = (const daliasskintype_t *)( ptexture + size );
|
||||
}
|
||||
}
|
||||
|
||||
return pskintype;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
====================
|
||||
Mod_LoadAliasModel
|
||||
|
||||
load alias model
|
||||
====================
|
||||
*/
|
||||
void Mod_LoadAliasModel( model_t *mod, const void *buffer, qboolean *loaded )
|
||||
{
|
||||
const daliasframetype_t *pframetype;
|
||||
const daliasskintype_t *pskintype;
|
||||
const dtriangle_t *pintriangles;
|
||||
const daliashdr_t *pinmodel;
|
||||
const stvert_t *pinstverts;
|
||||
aliashdr_t *m_pAliasHeader;
|
||||
size_t size;
|
||||
char poolname[MAX_VA_STRING];
|
||||
int i;
|
||||
|
||||
if( loaded ) *loaded = false;
|
||||
pinmodel = (const daliashdr_t *)buffer;
|
||||
i = pinmodel->version;
|
||||
|
||||
if( i != ALIAS_VERSION )
|
||||
{
|
||||
Con_DPrintf( S_ERROR "%s has wrong version number (%i should be %i)\n", mod->name, i, ALIAS_VERSION );
|
||||
return;
|
||||
}
|
||||
|
||||
if( pinmodel->numverts <= 0 || pinmodel->numtris <= 0 || pinmodel->numframes <= 0 )
|
||||
return; // how is it possible to make that?
|
||||
|
||||
Q_snprintf( poolname, sizeof( poolname ), "^2%s^7", mod->name );
|
||||
mod->mempool = Mem_AllocPool( poolname );
|
||||
|
||||
size = sizeof( aliashdr_t ) + (pinmodel->numframes - 1) * sizeof( maliasframedesc_t );
|
||||
mod->cache.data = m_pAliasHeader = Mem_Calloc( mod->mempool, size );
|
||||
|
||||
// endian-adjust and copy the data, starting with the alias model header
|
||||
m_pAliasHeader->numverts = pinmodel->numverts;
|
||||
|
||||
if( m_pAliasHeader->numverts > MAXALIASVERTS )
|
||||
{
|
||||
Con_DPrintf( S_ERROR "model %s has too many vertices\n", mod->name );
|
||||
return;
|
||||
}
|
||||
|
||||
mod->flags = pinmodel->flags; // share effects flags
|
||||
m_pAliasHeader->boundingradius = pinmodel->boundingradius;
|
||||
m_pAliasHeader->numskins = pinmodel->numskins;
|
||||
m_pAliasHeader->skinwidth = pinmodel->skinwidth;
|
||||
m_pAliasHeader->skinheight = pinmodel->skinheight;
|
||||
m_pAliasHeader->numtris = pinmodel->numtris;
|
||||
mod->numframes = m_pAliasHeader->numframes = pinmodel->numframes;
|
||||
m_pAliasHeader->size = pinmodel->size;
|
||||
|
||||
for( i = 0; i < 3; i++ )
|
||||
{
|
||||
m_pAliasHeader->scale[i] = pinmodel->scale[i];
|
||||
m_pAliasHeader->scale_origin[i] = pinmodel->scale_origin[i];
|
||||
m_pAliasHeader->eyeposition[i] = pinmodel->eyeposition[i];
|
||||
}
|
||||
|
||||
// load the skins
|
||||
pskintype = (const daliasskintype_t *)&pinmodel[1];
|
||||
pskintype = Mod_LoadAllSkins( mod, m_pAliasHeader->numskins, pskintype, m_pAliasHeader );
|
||||
// will be done at renderer side...
|
||||
|
||||
// load base s and t vertices
|
||||
pinstverts = (const stvert_t *)pskintype;
|
||||
// will be done at renderer side...
|
||||
|
||||
// load triangle lists
|
||||
pintriangles = (const dtriangle_t *)&pinstverts[m_pAliasHeader->numverts];
|
||||
// will be done at renderer side
|
||||
|
||||
// load the frames
|
||||
pframetype = (const daliasframetype_t *)&pintriangles[m_pAliasHeader->numtris];
|
||||
m_pAliasHeader->pposeverts = g_poseverts; // store the pointer to be accessed by renderer
|
||||
g_posenum = 0;
|
||||
|
||||
for( i = 0; i < m_pAliasHeader->numframes; i++ )
|
||||
{
|
||||
aliasframetype_t frametype = pframetype->type;
|
||||
|
||||
if( frametype == ALIAS_SINGLE )
|
||||
pframetype = (const daliasframetype_t *)Mod_LoadAliasFrame((const daliasframe_t *)&pframetype[1], &m_pAliasHeader->frames[i], m_pAliasHeader );
|
||||
else pframetype = (const daliasframetype_t *)Mod_LoadAliasGroup(( const daliasgroup_t *)&pframetype[1], &m_pAliasHeader->frames[i], m_pAliasHeader );
|
||||
}
|
||||
|
||||
m_pAliasHeader->numposes = g_posenum;
|
||||
Mod_CalcAliasBounds( mod, m_pAliasHeader );
|
||||
mod->type = mod_alias;
|
||||
|
||||
if( loaded ) *loaded = true; // done
|
||||
}
|
||||
+34
-35
@@ -30,13 +30,6 @@ GNU General Public License for more details.
|
||||
|
||||
#define MIPTEX_CUSTOM_PALETTE_SIZE_BYTES ( sizeof( int16_t ) + 768 )
|
||||
|
||||
typedef struct wadlist_s
|
||||
{
|
||||
char wadnames[MAX_MAP_WADS][32];
|
||||
int wadusage[MAX_MAP_WADS];
|
||||
int count;
|
||||
} wadlist_t;
|
||||
|
||||
typedef struct leaflist_s
|
||||
{
|
||||
int count;
|
||||
@@ -136,7 +129,6 @@ typedef struct
|
||||
dclipnode32_t *clipnodes_out; // temporary 32-bit array to hold clipnodes
|
||||
|
||||
// misc stuff
|
||||
wadlist_t wadlist;
|
||||
int lightmap_samples; // samples per lightmap (1 or 3)
|
||||
int version; // model version
|
||||
qboolean isworld;
|
||||
@@ -1835,7 +1827,7 @@ static void Mod_LoadEntities( model_t *mod, dbspmodel_t *bmod )
|
||||
world.generator[0] = '\0';
|
||||
world.compiler[0] = '\0';
|
||||
world.message[0] = '\0';
|
||||
bmod->wadlist.count = 0;
|
||||
world.wadlist.count = 0;
|
||||
|
||||
// parse all the wads for loading textures in right ordering
|
||||
while(( pfile = COM_ParseFile( pfile, token, sizeof( token ))) != NULL )
|
||||
@@ -1878,12 +1870,12 @@ static void Mod_LoadEntities( model_t *mod, dbspmodel_t *bmod )
|
||||
// make sure that wad is really exist
|
||||
if( FS_FileExists( va( "%s.wad", token ), false ))
|
||||
{
|
||||
int num = bmod->wadlist.count++;
|
||||
Q_strncpy( bmod->wadlist.wadnames[num], token, sizeof( bmod->wadlist.wadnames[0] ));
|
||||
bmod->wadlist.wadusage[num] = 0;
|
||||
int num = world.wadlist.count++;
|
||||
Q_strncpy( world.wadlist.wadnames[num], token, sizeof( world.wadlist.wadnames[0] ));
|
||||
world.wadlist.wadusage[num] = 0;
|
||||
}
|
||||
|
||||
if( bmod->wadlist.count >= MAX_MAP_WADS )
|
||||
if( world.wadlist.count >= MAX_MAP_WADS )
|
||||
break; // too many wads...
|
||||
}
|
||||
}
|
||||
@@ -2030,24 +2022,35 @@ static void Mod_LoadMarkSurfaces( model_t *mod, dbspmodel_t *bmod )
|
||||
|
||||
if( bmod->version == QBSP2_VERSION )
|
||||
{
|
||||
dmarkface32_t *in = bmod->markfaces32;
|
||||
const dmarkface32_t *in = bmod->markfaces32;
|
||||
|
||||
for( i = 0; i < bmod->nummarkfaces; i++, in++ )
|
||||
for( i = 0; i < bmod->nummarkfaces; i++ )
|
||||
{
|
||||
if( *in < 0 || *in >= mod->numsurfaces )
|
||||
Host_Error( "%s: bad surface number in '%s'\n", __func__, mod->name );
|
||||
out[i] = mod->surfaces + *in;
|
||||
if( in[i] < 0 || in[i] >= mod->numsurfaces )
|
||||
Host_Error( "%s: bad surface number %i at %i (max %i) in '%s'\n", __func__, in[i], i, mod->numsurfaces, mod->name );
|
||||
out[i] = mod->surfaces + in[i];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
dmarkface_t *in = bmod->markfaces;
|
||||
const dmarkface_t *in = bmod->markfaces;
|
||||
|
||||
for( i = 0; i < bmod->nummarkfaces; i++, in++ )
|
||||
for( i = 0; i < bmod->nummarkfaces; i++ )
|
||||
{
|
||||
if( *in < 0 || *in >= mod->numsurfaces )
|
||||
Host_Error( "%s: bad surface number in '%s'\n", __func__, mod->name );
|
||||
out[i] = mod->surfaces + *in;
|
||||
// NOTE: some of the buggy compilers have written a broken BSP file
|
||||
// with marksurface pointing at negative surface, for example darkf6.bsp
|
||||
// and darkf26.bsp in darkfuture mod. GoldSrc straight up writes
|
||||
// invalid pointer to a surface. Try to fix up these cases...
|
||||
if( mod->numsurfaces <= INT16_MAX && (int16_t)in[i] < 0 )
|
||||
{
|
||||
Con_Printf( S_WARN "%s: fixing up bad surface number %i at %i (max %i) in '%s'\n", __func__, in[i], i, mod->numsurfaces, mod->name );
|
||||
out[i] = mod->surfaces;
|
||||
continue;
|
||||
}
|
||||
|
||||
if( in[i] < 0 || in[i] >= mod->numsurfaces )
|
||||
Host_Error( "%s: bad surface number %i at %i (max %i) in '%s'\n", __func__, in[i], i, mod->numsurfaces, mod->name );
|
||||
out[i] = mod->surfaces + in[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2309,9 +2312,9 @@ static void Mod_LoadTextureData( model_t *mod, dbspmodel_t *bmod, int textureInd
|
||||
}
|
||||
|
||||
// Try WAD texture (force while r_wadtextures is 1)
|
||||
if( !texture->gl_texturenum && (( r_wadtextures.value && bmod->wadlist.count > 0 ) || mipTex->offsets[0] <= 0 ))
|
||||
if( !texture->gl_texturenum && (( r_wadtextures.value && world.wadlist.count > 0 ) || mipTex->offsets[0] <= 0 ))
|
||||
{
|
||||
int wadIndex = Mod_FindTextureInWadList( &bmod->wadlist, mipTex->name, texpath, sizeof( texpath ));
|
||||
int wadIndex = Mod_FindTextureInWadList( &world.wadlist, mipTex->name, texpath, sizeof( texpath ));
|
||||
|
||||
if( wadIndex >= 0 )
|
||||
{
|
||||
@@ -2319,7 +2322,7 @@ static void Mod_LoadTextureData( model_t *mod, dbspmodel_t *bmod, int textureInd
|
||||
if( !Host_IsDedicated( ))
|
||||
texture->gl_texturenum = ref.dllFuncs.GL_LoadTexture( texpath, NULL, 0, txFlags );
|
||||
#endif // !XASH_DEDICATED
|
||||
bmod->wadlist.wadusage[wadIndex]++;
|
||||
world.wadlist.wadusage[wadIndex]++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2377,12 +2380,12 @@ static void Mod_LoadTextureData( model_t *mod, dbspmodel_t *bmod, int textureInd
|
||||
// doesn't exist there. The original texture is already loaded, but cannot be modified.
|
||||
// Instead, load the original texture again and convert it to luma.
|
||||
|
||||
wadIndex = Mod_FindTextureInWadList( &bmod->wadlist, texture->name, texpath, sizeof( texpath ));
|
||||
wadIndex = Mod_FindTextureInWadList( &world.wadlist, texture->name, texpath, sizeof( texpath ));
|
||||
|
||||
if( wadIndex >= 0 )
|
||||
{
|
||||
src = FS_LoadFile( texpath, &srcSize, false );
|
||||
bmod->wadlist.wadusage[wadIndex]++;
|
||||
world.wadlist.wadusage[wadIndex]++;
|
||||
}
|
||||
|
||||
// OK, loading it from wad or hi-res version
|
||||
@@ -3415,18 +3418,14 @@ static qboolean Mod_LoadBmodelLumps( model_t *mod, const byte *mod_base, qboolea
|
||||
Mod_CalcPHS( mod );
|
||||
}
|
||||
|
||||
for( i = 0; i < bmod->wadlist.count; i++ )
|
||||
for( i = 0; i < world.wadlist.count; i++ )
|
||||
{
|
||||
string wadname;
|
||||
|
||||
if( !bmod->wadlist.wadusage[i] )
|
||||
if( !world.wadlist.wadusage[i] )
|
||||
continue;
|
||||
|
||||
Q_snprintf( wadname, sizeof( wadname ), "%s.wad", bmod->wadlist.wadnames[i] );
|
||||
|
||||
// a1ba: automatically precache used wad files so client will download it
|
||||
if( SV_Active( ))
|
||||
SV_GenericIndex( wadname );
|
||||
Q_snprintf( wadname, sizeof( wadname ), "%s.wad", world.wadlist.wadnames[i] );
|
||||
|
||||
if( !wadlist_warn )
|
||||
{
|
||||
|
||||
@@ -74,7 +74,7 @@ typedef struct winding_s
|
||||
struct winding_s *pair;
|
||||
hullnode_t chain;
|
||||
int numpoints;
|
||||
vec3_t p[4]; // variable sized
|
||||
vec3_t p[]; // variable sized
|
||||
} winding_t;
|
||||
|
||||
typedef struct
|
||||
@@ -83,6 +83,12 @@ typedef struct
|
||||
uint num_polys;
|
||||
} hull_model_t;
|
||||
|
||||
typedef struct wadlist_s
|
||||
{
|
||||
char wadnames[MAX_MAP_WADS][32];
|
||||
int wadusage[MAX_MAP_WADS];
|
||||
int count;
|
||||
} wadlist_t;
|
||||
|
||||
typedef struct world_static_s
|
||||
{
|
||||
@@ -119,6 +125,8 @@ typedef struct world_static_s
|
||||
// Potentially Hearable Set
|
||||
byte *compressed_phs;
|
||||
size_t *phsofs;
|
||||
|
||||
wadlist_t wadlist;
|
||||
} world_static_t;
|
||||
|
||||
#ifndef REF_DLL
|
||||
@@ -149,6 +157,11 @@ qboolean Mod_ValidateCRC( const char *name, CRC32_t crc );
|
||||
void Mod_NeedCRC( const char *name, qboolean needCRC );
|
||||
void Mod_FreeUnused( void );
|
||||
|
||||
//
|
||||
// mod_alias.c
|
||||
//
|
||||
void Mod_LoadAliasModel( model_t *mod, const void *buffer, qboolean *loaded );
|
||||
|
||||
//
|
||||
// mod_bmodel.c
|
||||
//
|
||||
@@ -194,7 +207,7 @@ void Mod_ClearStudioCache( void );
|
||||
//
|
||||
// mod_sprite.c
|
||||
//
|
||||
void Mod_LoadSpriteModel( model_t *mod, const void *buffer, qboolean *loaded, uint texFlags );
|
||||
void Mod_LoadSpriteModel( model_t *mod, const void *buffer, qboolean *loaded );
|
||||
#endif
|
||||
|
||||
#endif//MOD_LOCAL_H
|
||||
|
||||
@@ -30,7 +30,7 @@ Mod_LoadSpriteModel
|
||||
load sprite model
|
||||
====================
|
||||
*/
|
||||
void Mod_LoadSpriteModel( model_t *mod, const void *buffer, qboolean *loaded, uint texFlags )
|
||||
void Mod_LoadSpriteModel( model_t *mod, const void *buffer, qboolean *loaded )
|
||||
{
|
||||
dsprite_q1_t *pinq1;
|
||||
dsprite_hl_t *pinhl;
|
||||
|
||||
+10
-4
@@ -300,17 +300,15 @@ model_t *Mod_LoadModel( model_t *mod, qboolean crash )
|
||||
Mod_LoadStudioModel( mod, buf, &loaded );
|
||||
break;
|
||||
case IDSPRITEHEADER:
|
||||
Mod_LoadSpriteModel( mod, buf, &loaded, 0 );
|
||||
Mod_LoadSpriteModel( mod, buf, &loaded );
|
||||
break;
|
||||
case IDALIASHEADER:
|
||||
// REFTODO: move server-related code here
|
||||
loaded = true;
|
||||
Mod_LoadAliasModel( mod, buf, &loaded );
|
||||
break;
|
||||
case Q1BSP_VERSION:
|
||||
case HLBSP_VERSION:
|
||||
case QBSP2_VERSION:
|
||||
Mod_LoadBrushModel( mod, buf, &loaded );
|
||||
// ref.dllFuncs.Mod_LoadModel( mod_brush, mod, buf, &loaded, 0 );
|
||||
break;
|
||||
default:
|
||||
Mem_Free( buf );
|
||||
@@ -318,6 +316,7 @@ model_t *Mod_LoadModel( model_t *mod, qboolean crash )
|
||||
else Con_Printf( S_ERROR "%s has unknown format\n", tempname );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if( loaded )
|
||||
{
|
||||
if( world.loading )
|
||||
@@ -339,6 +338,13 @@ model_t *Mod_LoadModel( model_t *mod, qboolean crash )
|
||||
#endif
|
||||
}
|
||||
|
||||
if( mod->type == mod_alias )
|
||||
{
|
||||
aliashdr_t *hdr = mod->cache.data;
|
||||
if( hdr ) // clean up temporary pointer after passing the alias model to the renderer
|
||||
hdr->pposeverts = NULL;
|
||||
}
|
||||
|
||||
if( !loaded )
|
||||
{
|
||||
Mod_FreeModel( mod );
|
||||
|
||||
@@ -0,0 +1,161 @@
|
||||
/*
|
||||
munge.c - protocol mangling for GoldSrc
|
||||
Copyright (C) ReHLDS developers
|
||||
Copyright (C) 2023 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 "common.h"
|
||||
|
||||
static const byte mungify_table[] =
|
||||
{
|
||||
0x7A, 0x64, 0x05, 0xF1, 0x1B, 0x9B, 0xA0, 0xB5,
|
||||
0xCA, 0xED, 0x61, 0x0D, 0x4A, 0xDF, 0x8E, 0xC7,
|
||||
};
|
||||
|
||||
static const byte mungify_table2[] =
|
||||
{
|
||||
0x05, 0x61, 0x7A, 0xED, 0x1B, 0xCA, 0x0D, 0x9B,
|
||||
0x4A, 0xF1, 0x64, 0xC7, 0xB5, 0x8E, 0xDF, 0xA0,
|
||||
};
|
||||
|
||||
static const byte mungify_table3[] =
|
||||
{
|
||||
0x20, 0x07, 0x13, 0x61, 0x03, 0x45, 0x17, 0x72,
|
||||
0x0A, 0x2D, 0x48, 0x0C, 0x4A, 0x12, 0xA9, 0xB5,
|
||||
};
|
||||
|
||||
static int COM_SwapLong( int c )
|
||||
{
|
||||
return ((( c >> 0 ) & 0xFF) << 24 ) +
|
||||
((( c >> 8 ) & 0xFF) << 16 ) +
|
||||
((( c >> 16 ) & 0xFF) << 8 ) +
|
||||
((( c >> 24 ) & 0xFF) << 0 );
|
||||
}
|
||||
|
||||
static void COM_GenericMunge( byte *data, const size_t len, const int seq, const byte *table, const qboolean reverse )
|
||||
{
|
||||
const size_t mungelen = len / 4;
|
||||
int i;
|
||||
|
||||
for( i = 0; i < mungelen; i++ )
|
||||
{
|
||||
uint *pc, c;
|
||||
byte *p;
|
||||
int j;
|
||||
|
||||
pc = (uint *)&data[i * 4];
|
||||
c = *pc;
|
||||
c ^= seq;
|
||||
if( !reverse )
|
||||
c = COM_SwapLong( c );
|
||||
|
||||
p = (byte *)&c;
|
||||
for( j = 0; j < 4; j++ )
|
||||
*p++ ^= (0xa5 | (j << j) | j | table[(i + j) & 0x0f]);
|
||||
|
||||
if( reverse )
|
||||
c = COM_SwapLong( c );
|
||||
c ^= ~seq;
|
||||
*pc = c;
|
||||
}
|
||||
}
|
||||
|
||||
// Anti-proxy/aimbot obfuscation code
|
||||
// COM_UnMunge should reversably fixup the data
|
||||
void COM_Munge( byte *data, size_t len, int seq )
|
||||
{
|
||||
COM_GenericMunge( data, len, seq, mungify_table, false );
|
||||
}
|
||||
|
||||
void COM_UnMunge( byte *data, size_t len, int seq )
|
||||
{
|
||||
COM_GenericMunge( data, len, seq, mungify_table, true );
|
||||
}
|
||||
|
||||
void COM_Munge2( byte *data, size_t len, int seq )
|
||||
{
|
||||
COM_GenericMunge( data, len, seq, mungify_table2, false );
|
||||
}
|
||||
|
||||
void COM_UnMunge2( byte *data, size_t len, int seq )
|
||||
{
|
||||
COM_GenericMunge( data, len, seq, mungify_table2, true );
|
||||
}
|
||||
|
||||
void COM_Munge3( byte *data, size_t len, int seq )
|
||||
{
|
||||
COM_GenericMunge( data, len, seq, mungify_table3, false );
|
||||
}
|
||||
|
||||
void COM_UnMunge3( byte *data, size_t len, int seq )
|
||||
{
|
||||
COM_GenericMunge( data, len, seq, mungify_table3, true );
|
||||
}
|
||||
|
||||
#if XASH_ENGINE_TESTS
|
||||
#include "tests.h"
|
||||
|
||||
void Test_RunMunge( void )
|
||||
{
|
||||
const char *msg = "0123456789qwertyuiopasdfghjklzxcvbnmaa";
|
||||
const char *expected[][3] =
|
||||
{
|
||||
{
|
||||
"\x33\x2a\x61\x30\x2d\x6e\x35\x74\x2d\x79\x79\x78\x73\x34\x32\x25\x30\x2f\x39\x35\x26\x3c\x33\x61\x31\x22\x78\x67\x29\x68\x6a\x6c\x7d\x7e\x72\x36\x61\x61",
|
||||
"\x69\x2a\x31\x30\x2d\x36\x25\x74\x77\x61\x79\x38\x6b\x34\x62\x25\x30\x7f\x39\x35\x76\x34\x33\x61\x39\x2a\x78\x67\x23\x68\x7a\x6c\x7d\x66\x72\x76\x61\x61",
|
||||
"\x69\x6a\x71\x30\x6f\x7e\x25\x74\x3f\x69\x69\x38\x63\x2c\x62\x25\x28\x77\x29\x75\x7c\x2c\x73\x21\x23\x62\x38\x27\x6b\x28\x2a\x6c\x3d\x3e\x72\x36\x61\x61",
|
||||
}, {
|
||||
"\x32\x2a\x61\x31\x2c\x6e\x35\x75\x2c\x79\x79\x79\x72\x34\x32\x24\x31\x2f\x39\x34\x27\x3c\x33\x60\x30\x22\x78\x66\x28\x68\x6a\x6d\x7c\x7e\x72\x37\x61\x61",
|
||||
"\x68\x2a\x31\x31\x2c\x36\x25\x75\x76\x61\x79\x39\x6a\x34\x62\x24\x31\x7f\x39\x34\x77\x34\x33\x60\x38\x2a\x78\x66\x22\x68\x7a\x6d\x7c\x66\x72\x77\x61\x61",
|
||||
"\x68\x6a\x71\x31\x6e\x7e\x25\x75\x3e\x69\x69\x39\x62\x2c\x62\x24\x29\x77\x29\x74\x7d\x2c\x73\x20\x22\x62\x38\x26\x6a\x28\x2a\x6d\x3c\x3e\x72\x37\x61\x61",
|
||||
}
|
||||
};
|
||||
string buf;
|
||||
size_t msglen = Q_strlen( msg ) + 1;
|
||||
int i;
|
||||
|
||||
Q_strncpy( buf, msg, msglen );
|
||||
|
||||
for( i = 0; i < 0xFF; i++ )
|
||||
{
|
||||
COM_Munge( buf, msglen, i );
|
||||
if( i < sizeof( expected ) / sizeof( expected[0] ))
|
||||
{
|
||||
//for( int j = 0; j < msglen; j++ )
|
||||
// printf( "\\x%02x", buf[j] );
|
||||
//printf( "\n" );
|
||||
TASSERT( !memcmp( buf, expected[i][0], msglen ));
|
||||
}
|
||||
COM_UnMunge( buf, msglen, i );
|
||||
|
||||
TASSERT( !Q_strcmp( buf, msg ));
|
||||
|
||||
COM_Munge2( buf, msglen, i );
|
||||
if( i < sizeof( expected ) / sizeof( expected[0] ))
|
||||
{
|
||||
TASSERT( !memcmp( buf, expected[i][1], msglen ));
|
||||
}
|
||||
COM_UnMunge2( buf, msglen, i );
|
||||
|
||||
TASSERT( !Q_strcmp( buf, msg ));
|
||||
|
||||
COM_Munge3( buf, msglen, i );
|
||||
if( i < sizeof( expected ) / sizeof( expected[0] ))
|
||||
{
|
||||
TASSERT( !memcmp( buf, expected[i][2], msglen ));
|
||||
}
|
||||
COM_UnMunge3( buf, msglen, i );
|
||||
|
||||
TASSERT( !Q_strcmp( buf, msg ));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
+223
-38
@@ -81,7 +81,7 @@ const char *svc_strings[svc_lastmsg+1] =
|
||||
"svc_director",
|
||||
"svc_voiceinit",
|
||||
"svc_voicedata",
|
||||
"svc_deltapacketbones",
|
||||
"svc_unused54",
|
||||
"svc_unused55",
|
||||
"svc_resourcelocation",
|
||||
"svc_querycvarvalue",
|
||||
@@ -160,17 +160,6 @@ void MSG_InitMasks( void )
|
||||
ExtraMasks[maskBit] = (uint)BIT( maskBit ) - 1;
|
||||
}
|
||||
|
||||
void MSG_WriteOneBit( sizebuf_t *sb, int nValue )
|
||||
{
|
||||
if( !MSG_Overflow( sb, 1 ))
|
||||
{
|
||||
if( nValue ) sb->pData[sb->iCurBit>>3] |= BIT( sb->iCurBit & 7 );
|
||||
else sb->pData[sb->iCurBit>>3] &= ~BIT( sb->iCurBit & 7 );
|
||||
|
||||
sb->iCurBit++;
|
||||
}
|
||||
}
|
||||
|
||||
void MSG_WriteUBitLong( sizebuf_t *sb, uint curData, int numbits )
|
||||
{
|
||||
Assert( numbits >= 0 && numbits <= 32 );
|
||||
@@ -224,17 +213,25 @@ void MSG_WriteSBitLong( sizebuf_t *sb, int data, int numbits )
|
||||
// do we have a valid # of bits to encode with?
|
||||
Assert( numbits >= 1 && numbits <= 32 );
|
||||
|
||||
// NOTE: it does this wierdness here so it's bit-compatible with regular integer data in the buffer.
|
||||
// (Some old code writes direct integers right into the buffer).
|
||||
if( data < 0 )
|
||||
{
|
||||
if( sb->iAlternateSign )
|
||||
MSG_WriteOneBit( sb, 1 );
|
||||
|
||||
MSG_WriteUBitLong( sb, (uint)( 0x80000000 + data ), numbits - 1 );
|
||||
MSG_WriteOneBit( sb, 1 );
|
||||
|
||||
if( !sb->iAlternateSign )
|
||||
MSG_WriteOneBit( sb, 1 );
|
||||
}
|
||||
else
|
||||
{
|
||||
if( sb->iAlternateSign )
|
||||
MSG_WriteOneBit( sb, 0 );
|
||||
|
||||
MSG_WriteUBitLong( sb, (uint)data, numbits - 1 );
|
||||
MSG_WriteOneBit( sb, 0 );
|
||||
|
||||
if( !sb->iAlternateSign )
|
||||
MSG_WriteOneBit( sb, 0 );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -395,15 +392,11 @@ qboolean MSG_WriteBytes( sizebuf_t *sb, const void *pBuf, int nBytes )
|
||||
|
||||
qboolean MSG_WriteString( sizebuf_t *sb, const char *pStr )
|
||||
{
|
||||
if( pStr )
|
||||
{
|
||||
do
|
||||
{
|
||||
MSG_WriteChar( sb, (signed char)*pStr );
|
||||
pStr++;
|
||||
} while( *( pStr - 1 ));
|
||||
}
|
||||
else MSG_WriteChar( sb, 0 );
|
||||
int len = Q_strlen( pStr );
|
||||
|
||||
if( len )
|
||||
MSG_WriteBytes( sb, pStr, len + 1 );
|
||||
else MSG_WriteByte( sb, 0 );
|
||||
|
||||
return !sb->bOverflow;
|
||||
}
|
||||
@@ -411,13 +404,22 @@ qboolean MSG_WriteString( sizebuf_t *sb, const char *pStr )
|
||||
qboolean MSG_WriteStringf( sizebuf_t *sb, const char *format, ... )
|
||||
{
|
||||
va_list va;
|
||||
int len;
|
||||
char buf[MAX_VA_STRING];
|
||||
|
||||
va_start( va, format );
|
||||
Q_vsnprintf( buf, sizeof( buf ), format, va );
|
||||
len = Q_vsnprintf( buf, sizeof( buf ), format, va );
|
||||
va_end( va );
|
||||
|
||||
return MSG_WriteString( sb, buf );
|
||||
if( len < 0 )
|
||||
{
|
||||
Host_Error( "%s: snprintf overflow!\n", __func__ );
|
||||
return false;
|
||||
}
|
||||
|
||||
MSG_WriteBytes( sb, buf, len + 1 );
|
||||
|
||||
return !sb->bOverflow;
|
||||
}
|
||||
|
||||
int MSG_ReadOneBit( sizebuf_t *sb )
|
||||
@@ -539,12 +541,22 @@ int MSG_ReadSBitLong( sizebuf_t *sb, int numbits )
|
||||
{
|
||||
int r, sign;
|
||||
|
||||
r = MSG_ReadUBitLong( sb, numbits - 1 );
|
||||
if( sb->iAlternateSign )
|
||||
{
|
||||
sign = MSG_ReadOneBit( sb );
|
||||
r = MSG_ReadUBitLong( sb, numbits - 1 );
|
||||
|
||||
// NOTE: it does this wierdness here so it's bit-compatible with regular integer data in the buffer.
|
||||
// (Some old code writes direct integers right into the buffer).
|
||||
sign = MSG_ReadOneBit( sb );
|
||||
if( sign ) r = -( BIT( numbits - 1 ) - r );
|
||||
if( sign )
|
||||
r = -r;
|
||||
}
|
||||
else
|
||||
{
|
||||
r = MSG_ReadUBitLong( sb, numbits - 1 );
|
||||
sign = MSG_ReadOneBit( sb );
|
||||
|
||||
if( sign )
|
||||
r = -( BIT( numbits - 1 ) - r );
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
@@ -575,7 +587,13 @@ int MSG_ReadCmd( sizebuf_t *sb, netsrc_t type )
|
||||
|
||||
int MSG_ReadChar( sizebuf_t *sb )
|
||||
{
|
||||
return MSG_ReadSBitLong( sb, sizeof( int8_t ) << 3 );
|
||||
int alt = sb->iAlternateSign, ret;
|
||||
|
||||
sb->iAlternateSign = 0;
|
||||
ret = MSG_ReadSBitLong( sb, sizeof( int8_t ) << 3 );
|
||||
sb->iAlternateSign = alt;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int MSG_ReadByte( sizebuf_t *sb )
|
||||
@@ -585,7 +603,13 @@ int MSG_ReadByte( sizebuf_t *sb )
|
||||
|
||||
int MSG_ReadShort( sizebuf_t *sb )
|
||||
{
|
||||
return MSG_ReadSBitLong( sb, sizeof( int16_t ) << 3 );
|
||||
int alt = sb->iAlternateSign, ret;
|
||||
|
||||
sb->iAlternateSign = 0;
|
||||
ret = MSG_ReadSBitLong( sb, sizeof( int16_t ) << 3 );
|
||||
sb->iAlternateSign = alt;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int MSG_ReadWord( sizebuf_t *sb )
|
||||
@@ -617,7 +641,13 @@ void MSG_ReadVec3Angles( sizebuf_t *sb, vec3_t fa )
|
||||
|
||||
int MSG_ReadLong( sizebuf_t *sb )
|
||||
{
|
||||
return MSG_ReadSBitLong( sb, sizeof( int32_t ) << 3 );
|
||||
int alt = sb->iAlternateSign, ret;
|
||||
|
||||
sb->iAlternateSign = 0;
|
||||
ret = MSG_ReadSBitLong( sb, sizeof( int32_t ) << 3 );
|
||||
sb->iAlternateSign = alt;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint MSG_ReadDword( sizebuf_t *sb )
|
||||
@@ -629,9 +659,7 @@ float MSG_ReadFloat( sizebuf_t *sb )
|
||||
{
|
||||
float ret;
|
||||
|
||||
Assert( sizeof( ret ) == 4 );
|
||||
|
||||
MSG_ReadBits( sb, &ret, 32 );
|
||||
MSG_ReadBits( sb, &ret, sizeof( ret ) << 3 );
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -694,3 +722,160 @@ void MSG_ExciseBits( sizebuf_t *sb, int startbit, int bitstoremove )
|
||||
MSG_SeekToBit( sb, startbit, SEEK_SET );
|
||||
sb->nDataBits -= bitstoremove;
|
||||
}
|
||||
|
||||
#ifdef XASH_ENGINE_TESTS
|
||||
#include "tests.h"
|
||||
|
||||
static const void *g_testbuf = "asdf\xba\xa1\xba\xa1\xed\xc8\x15\x7a";
|
||||
static const size_t g_testbuf_bits = (( 4 + 4 + 2 + 1 ) << 3 ) + 4;
|
||||
|
||||
static void Test_Buffer_BitByte( void )
|
||||
{
|
||||
TASSERT_EQi( BitByte( 0 ), 0 );
|
||||
TASSERT_EQi( BitByte( 1 ), 1 );
|
||||
TASSERT_EQi( BitByte( 8 ), 1 );
|
||||
TASSERT_EQi( BitByte( 9 ), 2 );
|
||||
}
|
||||
|
||||
static void Test_Buffer_Write( void )
|
||||
{
|
||||
sizebuf_t sb;
|
||||
char testdata[0x100] = { 0 };
|
||||
|
||||
MSG_Init( &sb, __func__, testdata, sizeof( testdata ));
|
||||
TASSERT_EQi( sb.iCurBit, 0 );
|
||||
TASSERT_EQi( sb.nDataBits, sizeof( testdata ) << 3 );
|
||||
TASSERT_EQi( sb.pData, testdata );
|
||||
TASSERT_EQi( sb.bOverflow, false );
|
||||
|
||||
MSG_WriteBytes( &sb, "asdf", 4 );
|
||||
TASSERT_EQi( sb.bOverflow, false );
|
||||
TASSERT_EQi( sb.iCurBit, 32 );
|
||||
|
||||
MSG_WriteDword( &sb, 0xa1baa1ba );
|
||||
TASSERT_EQi( sb.bOverflow, false );
|
||||
TASSERT_EQi( sb.iCurBit, 64 );
|
||||
|
||||
MSG_WriteShort( &sb, -0x3713 );
|
||||
TASSERT_EQi( sb.bOverflow, false );
|
||||
TASSERT_EQi( sb.iCurBit, 80 );
|
||||
|
||||
MSG_WriteOneBit( &sb, 1 );
|
||||
TASSERT_EQi( sb.bOverflow, false );
|
||||
TASSERT_EQi( sb.iCurBit, 81 );
|
||||
|
||||
MSG_WriteOneBit( &sb, 0 );
|
||||
TASSERT_EQi( sb.bOverflow, false );
|
||||
TASSERT_EQi( sb.iCurBit, 82 );
|
||||
|
||||
MSG_WriteOneBit( &sb, 1 );
|
||||
TASSERT_EQi( sb.bOverflow, false );
|
||||
TASSERT_EQi( sb.iCurBit, 83 );
|
||||
|
||||
MSG_WriteOneBit( &sb, 0 );
|
||||
TASSERT_EQi( sb.bOverflow, false );
|
||||
TASSERT_EQi( sb.iCurBit, 84 );
|
||||
|
||||
MSG_WriteByte( &sb, 0xa1 );
|
||||
TASSERT_EQi( sb.bOverflow, false );
|
||||
TASSERT_EQi( sb.iCurBit, 92 );
|
||||
|
||||
TASSERT_EQi( MSG_GetNumBitsWritten( &sb ), g_testbuf_bits );
|
||||
TASSERT_EQi( MSG_GetNumBytesWritten( &sb ), BitByte( g_testbuf_bits ));
|
||||
TASSERT_EQi( MSG_GetRealBytesWritten( &sb ), g_testbuf_bits >> 3 );
|
||||
|
||||
// if tests fails here on big endian, it's possible due to endian issues
|
||||
TASSERT( !memcmp( sb.pData, g_testbuf, g_testbuf_bits >> 3 ));
|
||||
|
||||
// must check last 4 bits separately because we never care about uninitialized bits
|
||||
MSG_SeekToBit( &sb, g_testbuf_bits & ~7, SEEK_SET );
|
||||
TASSERT_EQi( sb.iCurBit, 88 );
|
||||
TASSERT_EQi( MSG_ReadUBitLong( &sb, 4 ), 0xa );
|
||||
}
|
||||
|
||||
static void Test_Buffer_Read( void )
|
||||
{
|
||||
sizebuf_t sb;
|
||||
char buf[4];
|
||||
|
||||
MSG_StartReading( &sb, (void *)g_testbuf, -1, 0, g_testbuf_bits );
|
||||
TASSERT_EQi( sb.iCurBit, 0 );
|
||||
TASSERT_EQi( sb.nDataBits, g_testbuf_bits );
|
||||
TASSERT_EQi( sb.pData, g_testbuf );
|
||||
TASSERT_EQi( sb.bOverflow, false );
|
||||
|
||||
MSG_ReadBytes( &sb, buf, 4 );
|
||||
TASSERT( !memcmp( buf, "asdf", 4 ));
|
||||
TASSERT_EQi( sb.iCurBit, 32 );
|
||||
TASSERT_EQi( sb.bOverflow, false );
|
||||
|
||||
TASSERT_EQi( MSG_ReadWord( &sb ), 0xa1ba );
|
||||
TASSERT_EQi( sb.iCurBit, 48 );
|
||||
TASSERT_EQi( sb.bOverflow, false );
|
||||
|
||||
TASSERT_EQi( MSG_ReadDword( &sb ), 0xc8eda1baU );
|
||||
TASSERT_EQi( sb.iCurBit, 80 );
|
||||
TASSERT_EQi( sb.bOverflow, false );
|
||||
|
||||
TASSERT_EQi( MSG_ReadOneBit( &sb ), 1 );
|
||||
TASSERT_EQi( sb.iCurBit, 81 );
|
||||
TASSERT_EQi( sb.bOverflow, false );
|
||||
|
||||
TASSERT_EQi( MSG_ReadOneBit( &sb ), 0 );
|
||||
TASSERT_EQi( sb.iCurBit, 82 );
|
||||
TASSERT_EQi( sb.bOverflow, false );
|
||||
|
||||
TASSERT_EQi( MSG_ReadOneBit( &sb ), 1 );
|
||||
TASSERT_EQi( sb.iCurBit, 83 );
|
||||
TASSERT_EQi( sb.bOverflow, false );
|
||||
|
||||
TASSERT_EQi( MSG_ReadOneBit( &sb ), 0 );
|
||||
TASSERT_EQi( sb.iCurBit, 84 );
|
||||
TASSERT_EQi( sb.bOverflow, false );
|
||||
|
||||
TASSERT_EQi( MSG_ReadByte( &sb ), 0xa1 );
|
||||
TASSERT_EQi( sb.iCurBit, 92 );
|
||||
TASSERT_EQi( sb.bOverflow, false );
|
||||
|
||||
TASSERT_EQi( MSG_Overflow( &sb, 1 ), true );
|
||||
TASSERT_EQi( sb.bOverflow, true );
|
||||
}
|
||||
|
||||
static void Test_Buffer_ExciseBits( void )
|
||||
{
|
||||
sizebuf_t sb;
|
||||
char testdata[0x100];
|
||||
|
||||
memcpy( testdata, g_testbuf, BitByte( g_testbuf_bits ));
|
||||
|
||||
MSG_StartWriting( &sb, testdata, 0, 0, g_testbuf_bits );
|
||||
MSG_ExciseBits( &sb, 8, 28 );
|
||||
|
||||
TASSERT_EQi( MSG_CheckOverflow( &sb ), false );
|
||||
TASSERT_EQi( MSG_GetMaxBits( &sb ), 64 );
|
||||
TASSERT( !memcmp( MSG_GetData( &sb ), "a\x1b\xaa\x1b\xda\x8e\x5c\xa1", 8 ));
|
||||
|
||||
memcpy( testdata, g_testbuf, BitByte( g_testbuf_bits ));
|
||||
|
||||
MSG_StartWriting( &sb, testdata, 0, 0, g_testbuf_bits );
|
||||
MSG_ExciseBits( &sb, 16, 32 );
|
||||
|
||||
TASSERT_EQi( MSG_CheckOverflow( &sb ), false );
|
||||
TASSERT_EQi( MSG_GetMaxBits( &sb ), g_testbuf_bits - 32 );
|
||||
TASSERT( !memcmp( MSG_GetData( &sb ), "as\xba\xa1\xed\xc8\x15", 7 ));
|
||||
|
||||
MSG_SeekToBit( &sb, 7 << 3, SEEK_SET );
|
||||
TASSERT_EQi( MSG_ReadUBitLong( &sb, 4 ), 0xa );
|
||||
}
|
||||
|
||||
void Test_RunBuffer( void )
|
||||
{
|
||||
MSG_InitMasks();
|
||||
|
||||
TRUN( Test_Buffer_BitByte( ));
|
||||
TRUN( Test_Buffer_Write( ));
|
||||
TRUN( Test_Buffer_Read( ));
|
||||
TRUN( Test_Buffer_ExciseBits( ));
|
||||
}
|
||||
|
||||
#endif // XASH_ENGINE_TESTS
|
||||
|
||||
@@ -42,6 +42,9 @@ struct sizebuf_s
|
||||
int iCurBit;
|
||||
int nDataBits;
|
||||
const char *pDebugName; // buffer name (pointer to const name)
|
||||
|
||||
// to support GoldSrc broken signed integers
|
||||
int iAlternateSign;
|
||||
};
|
||||
|
||||
#define MSG_StartReading MSG_StartWriting
|
||||
@@ -71,6 +74,7 @@ static inline void MSG_InitExt( sizebuf_t *sb, const char *pDebugName, void *pDa
|
||||
sb->nDataBits = nBits;
|
||||
|
||||
sb->pDebugName = pDebugName;
|
||||
sb->iAlternateSign = 0;
|
||||
}
|
||||
|
||||
static inline void MSG_StartWriting( sizebuf_t *sb, void *pData, int nBytes, int iStartBit, int nBits )
|
||||
@@ -169,11 +173,40 @@ static inline qboolean MSG_Overflow( sizebuf_t *sb, int nBits )
|
||||
return sb->bOverflow;
|
||||
}
|
||||
|
||||
static inline void MSG_EndBitWriting( sizebuf_t *sb )
|
||||
{
|
||||
sb->iAlternateSign--;
|
||||
|
||||
if( sb->iAlternateSign < 0 )
|
||||
{
|
||||
Con_Printf( "%s: non-even MSG_Start/EndBitWriting\n", __func__ );
|
||||
sb->iAlternateSign = 0;
|
||||
}
|
||||
|
||||
// we have native bit ops here, just pad to closest byte
|
||||
MSG_SeekToBit( sb, MSG_GetNumBytesWritten( sb ) << 3, SEEK_SET );
|
||||
}
|
||||
|
||||
static inline void MSG_StartBitWriting( sizebuf_t *sb )
|
||||
{
|
||||
sb->iAlternateSign++;
|
||||
}
|
||||
|
||||
void MSG_InitMasks( void ); // called once at startup engine
|
||||
void MSG_ExciseBits( sizebuf_t *sb, int startbit, int bitstoremove );
|
||||
|
||||
// Bit-write functions
|
||||
void MSG_WriteOneBit( sizebuf_t *sb, int nValue );
|
||||
static inline void MSG_WriteOneBit( sizebuf_t *sb, int nValue )
|
||||
{
|
||||
if( !MSG_Overflow( sb, 1 ))
|
||||
{
|
||||
if( nValue ) sb->pData[sb->iCurBit>>3] |= BIT( sb->iCurBit & 7 );
|
||||
else sb->pData[sb->iCurBit>>3] &= ~BIT( sb->iCurBit & 7 );
|
||||
|
||||
sb->iCurBit++;
|
||||
}
|
||||
}
|
||||
|
||||
NO_ASAN void MSG_WriteUBitLong( sizebuf_t *sb, uint curData, int numbits );
|
||||
void MSG_WriteSBitLong( sizebuf_t *sb, int data, int numbits );
|
||||
void MSG_WriteBitLong( sizebuf_t *sb, uint data, int numbits, qboolean bSigned );
|
||||
|
||||
+116
-36
@@ -18,6 +18,9 @@ GNU General Public License for more details.
|
||||
#include "xash3d_mathlib.h"
|
||||
#include "net_encode.h"
|
||||
#include "protocol.h"
|
||||
#if !XASH_DEDICATED
|
||||
#include <bzlib.h>
|
||||
#endif // !XASH_DEDICATED
|
||||
|
||||
#define MAKE_FRAGID( id, count ) ((( id & 0xffff ) << 16 ) | ( count & 0xffff ))
|
||||
#define FRAG_GETID( fragid ) (( fragid >> 16 ) & 0xffff )
|
||||
@@ -265,7 +268,7 @@ Netchan_Setup
|
||||
called to open a channel to a remote system
|
||||
==============
|
||||
*/
|
||||
void Netchan_Setup( netsrc_t sock, netchan_t *chan, netadr_t adr, int qport, void *client, int (*pfnBlockSize)(void *, fragsize_t mode ))
|
||||
void Netchan_Setup( netsrc_t sock, netchan_t *chan, netadr_t adr, int qport, void *client, int (*pfnBlockSize)(void *, fragsize_t mode ), uint flags )
|
||||
{
|
||||
Netchan_Clear( chan );
|
||||
|
||||
@@ -281,6 +284,10 @@ void Netchan_Setup( netsrc_t sock, netchan_t *chan, netadr_t adr, int qport, voi
|
||||
chan->qport = qport;
|
||||
chan->client = client;
|
||||
chan->pfnBlockSize = pfnBlockSize;
|
||||
chan->split = FBitSet( flags, NETCHAN_USE_LEGACY_SPLIT ) ? true : false;
|
||||
chan->use_munge = FBitSet( flags, NETCHAN_USE_MUNGE ) ? true : false;
|
||||
chan->use_bz2 = FBitSet( flags, NETCHAN_USE_BZIP2 ) ? true : false;
|
||||
chan->gs_netchan = FBitSet( flags, NETCHAN_GOLDSRC ) ? true : false;
|
||||
|
||||
MSG_Init( &chan->message, "NetData", chan->message_buf, sizeof( chan->message_buf ));
|
||||
}
|
||||
@@ -379,7 +386,6 @@ static void Netchan_ClearFragbufs( fragbuf_t **ppbuf )
|
||||
while( buf )
|
||||
{
|
||||
n = buf->next;
|
||||
Mem_Free( buf->frag_message_buf );
|
||||
Mem_Free( buf );
|
||||
buf = n;
|
||||
}
|
||||
@@ -458,22 +464,21 @@ Netchan_OutOfBand
|
||||
Sends an out-of-band datagram
|
||||
================
|
||||
*/
|
||||
void Netchan_OutOfBand( int net_socket, netadr_t adr, int length, byte *data )
|
||||
void Netchan_OutOfBand( int net_socket, netadr_t adr, int len, byte *data )
|
||||
{
|
||||
byte send_buf[MAX_PRINT_MSG];
|
||||
sizebuf_t send;
|
||||
byte buf[MAX_PRINT_MSG + 4] = { 0xff, 0xff, 0xff, 0xff };
|
||||
|
||||
// write the packet header
|
||||
MSG_Init( &send, "SequencePacket", send_buf, sizeof( send_buf ));
|
||||
if( CL_IsPlaybackDemo( ))
|
||||
return;
|
||||
|
||||
MSG_WriteLong( &send, NET_HEADER_OUTOFBANDPACKET ); // -1 sequence means out of band
|
||||
MSG_WriteBytes( &send, data, length );
|
||||
|
||||
if( !CL_IsPlaybackDemo( ))
|
||||
if( len > sizeof( buf ) - 4 )
|
||||
{
|
||||
// send the datagram
|
||||
NET_SendPacket( net_socket, MSG_GetNumBytesWritten( &send ), MSG_GetData( &send ), adr );
|
||||
Host_Error( "%s: overflow!\n", __func__ );
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy( &buf[4], data, len );
|
||||
NET_SendPacket( net_socket, len + 4, buf, adr );
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -483,16 +488,26 @@ Netchan_OutOfBandPrint
|
||||
Sends a text message in an out-of-band datagram
|
||||
================
|
||||
*/
|
||||
void Netchan_OutOfBandPrint( int net_socket, netadr_t adr, const char *format, ... )
|
||||
void Netchan_OutOfBandPrint( int net_socket, netadr_t adr, const char *fmt, ... )
|
||||
{
|
||||
char string[MAX_PRINT_MSG];
|
||||
va_list argptr;
|
||||
va_list va;
|
||||
byte buf[MAX_PRINT_MSG + 4] = { 0xff, 0xff, 0xff, 0xff };
|
||||
int len;
|
||||
|
||||
va_start( argptr, format );
|
||||
Q_vsnprintf( string, sizeof( string ) - 1, format, argptr );
|
||||
va_end( argptr );
|
||||
if( CL_IsPlaybackDemo( ))
|
||||
return;
|
||||
|
||||
Netchan_OutOfBand( net_socket, adr, Q_strlen( string ), (byte *)string );
|
||||
va_start( va, fmt );
|
||||
len = Q_vsnprintf( &buf[4], sizeof( buf ) - 4, fmt, va );
|
||||
va_end( va );
|
||||
|
||||
if( len < 0 )
|
||||
{
|
||||
Host_Error( "%s: snprintf overflow!\n", __func__ );
|
||||
return;
|
||||
}
|
||||
|
||||
NET_SendPacket( net_socket, len + 4, buf, adr );
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -505,8 +520,7 @@ static fragbuf_t *Netchan_AllocFragbuf( int fragment_size )
|
||||
{
|
||||
fragbuf_t *buf;
|
||||
|
||||
buf = (fragbuf_t *)Mem_Calloc( net_mempool, sizeof( fragbuf_t ));
|
||||
buf->frag_message_buf = (byte *)Mem_Calloc( net_mempool, fragment_size );
|
||||
buf = (fragbuf_t *)Mem_Calloc( net_mempool, sizeof( fragbuf_t ) + fragment_size );
|
||||
MSG_Init( &buf->frag_message, "Frag Message", buf->frag_message_buf, fragment_size );
|
||||
|
||||
return buf;
|
||||
@@ -520,7 +534,7 @@ Netchan_AddFragbufToTail
|
||||
*/
|
||||
static void Netchan_AddFragbufToTail( fragbufwaiting_t *wait, fragbuf_t *buf )
|
||||
{
|
||||
fragbuf_t *p;
|
||||
fragbuf_t *p;
|
||||
|
||||
buf->next = NULL;
|
||||
wait->fragbufcount++;
|
||||
@@ -680,7 +694,19 @@ static void Netchan_CreateFragments_( netchan_t *chan, sizebuf_t *msg )
|
||||
|
||||
wait = (fragbufwaiting_t *)Mem_Calloc( net_mempool, sizeof( fragbufwaiting_t ));
|
||||
|
||||
if( !LZSS_IsCompressed( MSG_GetData( msg )))
|
||||
if( chan->use_bz2 && memcmp( MSG_GetData( msg ), "BZ2", 4 ))
|
||||
{
|
||||
byte pbOut[0x10000];
|
||||
uint uCompressedSize = MSG_GetNumBytesWritten( msg ) - 4;
|
||||
if( !BZ2_bzBuffToBuffCompress( pbOut, &uCompressedSize, MSG_GetData( msg ), MSG_GetNumBytesWritten( msg ), 9, 0, 30 ))
|
||||
{
|
||||
Con_Reportf( "Compressing split packet with BZip2 (%d -> %d bytes)\n", MSG_GetNumBytesWritten( msg ), uCompressedSize );
|
||||
memcpy( msg->pData, "BZ2", 4 );
|
||||
memcpy( msg->pData + 4, pbOut, uCompressedSize );
|
||||
MSG_SeekToBit( msg, uCompressedSize << 3, SEEK_SET );
|
||||
}
|
||||
}
|
||||
else if( !chan->use_bz2 && !LZSS_IsCompressed( MSG_GetData( msg )))
|
||||
{
|
||||
uint uCompressedSize = 0;
|
||||
uint uSourceSize = MSG_GetNumBytesWritten( msg );
|
||||
@@ -688,7 +714,7 @@ static void Netchan_CreateFragments_( netchan_t *chan, sizebuf_t *msg )
|
||||
|
||||
if( pbOut && uCompressedSize > 0 && uCompressedSize < uSourceSize )
|
||||
{
|
||||
Con_Reportf( "Compressing split packet (%d -> %d bytes)\n", uSourceSize, uCompressedSize );
|
||||
Con_Reportf( "Compressing split packet with LZSS (%d -> %d bytes)\n", uSourceSize, uCompressedSize );
|
||||
memcpy( msg->pData, pbOut, uCompressedSize );
|
||||
MSG_SeekToBit( msg, uCompressedSize << 3, SEEK_SET );
|
||||
}
|
||||
@@ -1091,7 +1117,16 @@ qboolean Netchan_CopyNormalFragments( netchan_t *chan, sizebuf_t *msg, size_t *l
|
||||
p = n;
|
||||
}
|
||||
|
||||
if( LZSS_IsCompressed( MSG_GetData( msg )))
|
||||
if( chan->use_bz2 && !memcmp( MSG_GetData( msg ), "BZ2", 4 ) )
|
||||
{
|
||||
byte buf[0x10000];
|
||||
uint uDecompressedLen = sizeof( buf );
|
||||
|
||||
BZ2_bzBuffToBuffDecompress( buf, &uDecompressedLen, MSG_GetData( msg ) + 4, MSG_GetNumBytesWritten( msg ) - 4, 1, 0 );
|
||||
memcpy( msg->pData, buf, uDecompressedLen );
|
||||
size = uDecompressedLen;
|
||||
}
|
||||
else if( !chan->use_bz2 && LZSS_IsCompressed( MSG_GetData( msg )))
|
||||
{
|
||||
uint uDecompressedLen = LZSS_GetActualSize( MSG_GetData( msg ));
|
||||
byte buf[NET_MAX_MESSAGE];
|
||||
@@ -1128,7 +1163,8 @@ Netchan_CopyFileFragments
|
||||
*/
|
||||
qboolean Netchan_CopyFileFragments( netchan_t *chan, sizebuf_t *msg )
|
||||
{
|
||||
char filename[MAX_OSPATH];
|
||||
char filename[MAX_OSPATH], compressor[32];
|
||||
uint uncompressedSize;
|
||||
int nsize, pos;
|
||||
byte *buffer;
|
||||
fragbuf_t *p, *n;
|
||||
@@ -1151,6 +1187,12 @@ qboolean Netchan_CopyFileFragments( netchan_t *chan, sizebuf_t *msg )
|
||||
MSG_Clear( msg );
|
||||
|
||||
Q_strncpy( filename, MSG_ReadString( msg ), sizeof( filename ));
|
||||
compressor[0] = 0;
|
||||
if( chan->gs_netchan )
|
||||
{
|
||||
Q_strncpy( compressor, MSG_ReadString( msg ), sizeof( compressor ));
|
||||
uncompressedSize = MSG_ReadLong( msg );
|
||||
}
|
||||
|
||||
if( !COM_CheckString( filename ))
|
||||
{
|
||||
@@ -1168,7 +1210,7 @@ qboolean Netchan_CopyFileFragments( netchan_t *chan, sizebuf_t *msg )
|
||||
if( filename[0] != '!' )
|
||||
{
|
||||
string temp_filename;
|
||||
Q_snprintf( temp_filename, sizeof( temp_filename ), "downloaded/%s", filename );
|
||||
Q_snprintf( temp_filename, sizeof( temp_filename ), DEFAULT_DOWNLOADED_DIRECTORY "%s", filename );
|
||||
Q_strncpy( filename, temp_filename, sizeof( filename ));
|
||||
}
|
||||
|
||||
@@ -1221,10 +1263,25 @@ qboolean Netchan_CopyFileFragments( netchan_t *chan, sizebuf_t *msg )
|
||||
p = n;
|
||||
}
|
||||
|
||||
if( LZSS_IsCompressed( buffer ))
|
||||
if( chan->gs_netchan && chan->use_bz2 )
|
||||
{
|
||||
uint uncompressedSize = LZSS_GetActualSize( buffer ) + 1;
|
||||
byte *uncompressedBuffer = Mem_Calloc( net_mempool, uncompressedSize );
|
||||
if( !Q_stricmp( compressor, "bz2" ))
|
||||
{
|
||||
byte *uncompressedBuffer = Mem_Calloc( net_mempool, uncompressedSize );
|
||||
|
||||
Con_DPrintf( "Decompressing file %s (%d -> %d bytes)\n", filename, nsize, uncompressedSize );
|
||||
BZ2_bzBuffToBuffDecompress( uncompressedBuffer, &uncompressedSize, buffer, nsize, 1, 0 );
|
||||
Mem_Free( buffer );
|
||||
nsize = uncompressedSize;
|
||||
buffer = uncompressedBuffer;
|
||||
}
|
||||
}
|
||||
else if( LZSS_IsCompressed( buffer ))
|
||||
{
|
||||
byte *uncompressedBuffer;
|
||||
|
||||
uncompressedSize = LZSS_GetActualSize( buffer ) + 1;
|
||||
uncompressedBuffer = Mem_Calloc( net_mempool, uncompressedSize );
|
||||
|
||||
nsize = LZSS_Decompress( buffer, uncompressedBuffer );
|
||||
Mem_Free( buffer );
|
||||
@@ -1586,7 +1643,7 @@ void Netchan_TransmitBits( netchan_t *chan, int length, byte *data )
|
||||
MSG_WriteLong( &send, w2 );
|
||||
|
||||
// send the qport if we are a client
|
||||
if( chan->sock == NS_CLIENT )
|
||||
if( chan->sock == NS_CLIENT && !chan->gs_netchan )
|
||||
{
|
||||
MSG_WriteWord( &send, (int)net_qport.value );
|
||||
}
|
||||
@@ -1599,8 +1656,16 @@ void Netchan_TransmitBits( netchan_t *chan, int length, byte *data )
|
||||
{
|
||||
MSG_WriteByte( &send, 1 );
|
||||
MSG_WriteLong( &send, chan->reliable_fragid[i] );
|
||||
MSG_WriteLong( &send, chan->frag_startpos[i] );
|
||||
MSG_WriteLong( &send, chan->frag_length[i] );
|
||||
if( chan->gs_netchan )
|
||||
{
|
||||
MSG_WriteShort( &send, chan->frag_startpos[i] >> 3 );
|
||||
MSG_WriteShort( &send, chan->frag_length[i] >> 3 );
|
||||
}
|
||||
else
|
||||
{
|
||||
MSG_WriteLong( &send, chan->frag_startpos[i] );
|
||||
MSG_WriteLong( &send, chan->frag_length[i] );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1657,6 +1722,10 @@ void Netchan_TransmitBits( netchan_t *chan, int length, byte *data )
|
||||
int splitsize = 0;
|
||||
if( chan->pfnBlockSize )
|
||||
splitsize = chan->pfnBlockSize( chan->client, FRAGSIZE_SPLIT );
|
||||
|
||||
if( chan->use_munge )
|
||||
COM_Munge2( send.pData + 8, MSG_GetNumBytesWritten( &send ) - 8, (byte)( chan->outgoing_sequence - 1 ));
|
||||
|
||||
NET_SendPacketEx( chan->sock, MSG_GetNumBytesWritten( &send ), MSG_GetData( &send ), chan->remote_address, splitsize );
|
||||
}
|
||||
|
||||
@@ -1705,6 +1774,9 @@ qboolean Netchan_Process( netchan_t *chan, sizebuf_t *msg )
|
||||
sequence = MSG_ReadLong( msg );
|
||||
sequence_ack = MSG_ReadLong( msg );
|
||||
|
||||
if( chan->use_munge )
|
||||
COM_UnMunge2( msg->pData + 8, ( msg->nDataBits >> 3 ) - 8, sequence & 0xFF );
|
||||
|
||||
// read the qport if we are a server
|
||||
if( chan->sock == NS_SERVER )
|
||||
qport = MSG_ReadShort( msg );
|
||||
@@ -1722,8 +1794,16 @@ qboolean Netchan_Process( netchan_t *chan, sizebuf_t *msg )
|
||||
{
|
||||
frag_message[i] = true;
|
||||
fragid[i] = MSG_ReadLong( msg );
|
||||
frag_offset[i] = MSG_ReadLong( msg );
|
||||
frag_length[i] = MSG_ReadLong( msg );
|
||||
if( chan->gs_netchan )
|
||||
{
|
||||
frag_offset[i] = MSG_ReadShort( msg ) << 3;
|
||||
frag_length[i] = MSG_ReadShort( msg ) << 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
frag_offset[i] = MSG_ReadLong( msg );
|
||||
frag_length[i] = MSG_ReadLong( msg );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+190
-53
@@ -37,6 +37,7 @@ GNU General Public License for more details.
|
||||
#define DT_TIMEWINDOW_BIG BIT( 6 ) // and re-encoded on the client relative to the client's clock
|
||||
#define DT_STRING BIT( 7 ) // A null terminated string, sent as 8 byte chars
|
||||
#define DT_SIGNED BIT( 8 ) // sign modificator
|
||||
#define DT_SIGNED_GS BIT( 31 ) // GoldSrc-specific sign modificator
|
||||
|
||||
#define NUM_FIELDS( x ) ((sizeof( x ) / sizeof( x[0] )) - 1)
|
||||
|
||||
@@ -47,6 +48,7 @@ GNU General Public License for more details.
|
||||
#define PHYS_DEF( x ) #x, offsetof( movevars_t, x ), sizeof( ((movevars_t *)0)->x )
|
||||
#define CLDT_DEF( x ) #x, offsetof( clientdata_t, x ), sizeof( ((clientdata_t *)0)->x )
|
||||
#define WPDT_DEF( x ) #x, offsetof( weapon_data_t, x ), sizeof( ((weapon_data_t *)0)->x )
|
||||
#define DESC_DEF( x ) #x, offsetof( goldsrc_delta_t, x ), sizeof( ((goldsrc_delta_t *)0)->x )
|
||||
|
||||
static qboolean delta_init = false;
|
||||
|
||||
@@ -315,6 +317,18 @@ static const delta_field_t ent_fields[] =
|
||||
{ NULL },
|
||||
};
|
||||
|
||||
static const delta_field_t meta_fields[] =
|
||||
{
|
||||
{ DESC_DEF( fieldType ), },
|
||||
{ DESC_DEF( fieldName ), },
|
||||
{ DESC_DEF( fieldOffset ), },
|
||||
{ DESC_DEF( fieldSize ), },
|
||||
{ DESC_DEF( significant_bits ), },
|
||||
{ DESC_DEF( premultiply ), },
|
||||
{ DESC_DEF( postmultiply ), },
|
||||
{ NULL },
|
||||
};
|
||||
|
||||
#if XASH_ENGINE_TESTS
|
||||
typedef struct delta_test_struct_t
|
||||
{
|
||||
@@ -352,22 +366,6 @@ static const delta_field_t test_fields[] =
|
||||
};
|
||||
#endif
|
||||
|
||||
enum
|
||||
{
|
||||
DT_EVENT_T = 0,
|
||||
DT_MOVEVARS_T,
|
||||
DT_USERCMD_T,
|
||||
DT_CLIENTDATA_T,
|
||||
DT_WEAPONDATA_T,
|
||||
DT_ENTITY_STATE_T,
|
||||
DT_ENTITY_STATE_PLAYER_T,
|
||||
DT_CUSTOM_ENTITY_STATE_T,
|
||||
#if XASH_ENGINE_TESTS
|
||||
DT_DELTA_TEST_STRUCT_T,
|
||||
#endif
|
||||
DT_STRUCT_COUNT
|
||||
};
|
||||
|
||||
static delta_info_t dt_info[] =
|
||||
{
|
||||
[DT_EVENT_T] = { "event_t", ev_fields, NUM_FIELDS( ev_fields ) },
|
||||
@@ -375,9 +373,10 @@ static delta_info_t dt_info[] =
|
||||
[DT_USERCMD_T] = { "usercmd_t", cmd_fields, NUM_FIELDS( cmd_fields ) },
|
||||
[DT_CLIENTDATA_T] = { "clientdata_t", cd_fields, NUM_FIELDS( cd_fields ) },
|
||||
[DT_WEAPONDATA_T] = { "weapon_data_t", wd_fields, NUM_FIELDS( wd_fields ) },
|
||||
[DT_ENTITY_STATE_T] = { "entity_state_t", ent_fields, NUM_FIELDS( ent_fields ) },
|
||||
[DT_ENTITY_STATE_T] = { "entity_state_t", ent_fields, NUM_FIELDS( ent_fields ) },
|
||||
[DT_ENTITY_STATE_PLAYER_T] = { "entity_state_player_t", ent_fields, NUM_FIELDS( ent_fields ) },
|
||||
[DT_CUSTOM_ENTITY_STATE_T] = { "custom_entity_state_t", ent_fields, NUM_FIELDS( ent_fields ) },
|
||||
[DT_GOLDSRC_DELTA_T] = { "goldsrc_delta_t", meta_fields, NUM_FIELDS( meta_fields ) },
|
||||
#if XASH_ENGINE_TESTS
|
||||
[DT_DELTA_TEST_STRUCT_T] = { "delta_test_struct_t", test_fields, NUM_FIELDS( test_fields ) },
|
||||
#endif
|
||||
@@ -493,7 +492,7 @@ static qboolean Delta_AddField( delta_info_t *dt, const char *pName, int flags,
|
||||
int i;
|
||||
|
||||
// check for coexisting field
|
||||
for( i = 0, pField = dt->pFields; i < dt->numFields; i++, pField++ )
|
||||
for( i = 0, pField = dt->pFields; i < dt->numFields && pField; i++, pField++ )
|
||||
{
|
||||
if( !Q_strcmp( pField->name, pName ))
|
||||
{
|
||||
@@ -621,6 +620,64 @@ void Delta_ParseTableField( sizebuf_t *msg )
|
||||
Delta_AddField( dt, pName, flags, bits, mul, post_mul );
|
||||
}
|
||||
|
||||
void Delta_InitMeta( void )
|
||||
{
|
||||
delta_info_t *dt = Delta_FindStructByIndex( DT_GOLDSRC_DELTA_T );
|
||||
|
||||
if( dt->bInitialized )
|
||||
return;
|
||||
|
||||
Delta_AddField( dt, "fieldType", DT_INTEGER, 32, 1.0f, 1.0f );
|
||||
Delta_AddField( dt, "fieldName", DT_STRING, 1, 1.0f, 1.0f );
|
||||
Delta_AddField( dt, "fieldOffset", DT_INTEGER, 16, 1.0f, 1.0f );
|
||||
Delta_AddField( dt, "fieldSize", DT_INTEGER, 8, 1.0f, 1.0f );
|
||||
Delta_AddField( dt, "significant_bits", DT_INTEGER, 8, 1.0f, 1.0f );
|
||||
Delta_AddField( dt, "premultiply", DT_FLOAT, 32, 4000.0f, 1.0f );
|
||||
Delta_AddField( dt, "postmultiply", DT_FLOAT, 32, 4000.0f, 1.0f );
|
||||
dt->numFields = dt->maxFields;
|
||||
dt->bInitialized = true;
|
||||
}
|
||||
|
||||
void Delta_ParseTableField_GS( sizebuf_t *msg )
|
||||
{
|
||||
const char *s = MSG_ReadString( msg );
|
||||
delta_info_t *dt = Delta_FindStruct( s );
|
||||
goldsrc_delta_t null = { 0 };
|
||||
int i, num_fields;
|
||||
|
||||
|
||||
// delta encoders it's already initialized on this machine (local game)
|
||||
if( delta_init )
|
||||
{
|
||||
Delta_Shutdown();
|
||||
Delta_InitMeta();
|
||||
}
|
||||
|
||||
if( !dt )
|
||||
Host_Error( "%s: not initialized", __func__ );
|
||||
|
||||
num_fields = MSG_ReadShort( msg );
|
||||
if( num_fields > dt->maxFields )
|
||||
Host_Error( "%s: numFields > maxFields", __func__ );
|
||||
|
||||
MSG_StartBitWriting( msg );
|
||||
|
||||
for( i = 0; i < num_fields; i++ )
|
||||
{
|
||||
goldsrc_delta_t to;
|
||||
|
||||
Delta_ReadGSFields( msg, DT_GOLDSRC_DELTA_T, &null, &to, 0.0f );
|
||||
|
||||
// patch our DT_SIGNED flag
|
||||
if( FBitSet( to.fieldType, DT_SIGNED_GS ))
|
||||
SetBits( to.fieldType, DT_SIGNED );
|
||||
|
||||
Delta_AddField( dt, to.fieldName, to.fieldType, to.significant_bits, to.premultiply, to.postmultiply );
|
||||
}
|
||||
|
||||
MSG_EndBitWriting( msg );
|
||||
}
|
||||
|
||||
static qboolean Delta_ParseField( char **delta_script, const delta_field_t *pInfo, delta_t *pField, qboolean bPost )
|
||||
{
|
||||
string token;
|
||||
@@ -988,7 +1045,7 @@ compare fields by offsets
|
||||
assume from and to is valid
|
||||
=====================
|
||||
*/
|
||||
static qboolean Delta_CompareField( delta_t *pField, void *from, void *to, double timebase )
|
||||
static qboolean Delta_CompareField( delta_t *pField, const void *from, const void *to )
|
||||
{
|
||||
int signbit = ( pField->flags & DT_SIGNED ) ? 1 : 0;
|
||||
float val_a, val_b;
|
||||
@@ -1109,7 +1166,7 @@ Delta_TestBaseline
|
||||
compare baselines to find optimal
|
||||
=====================
|
||||
*/
|
||||
int Delta_TestBaseline( entity_state_t *from, entity_state_t *to, qboolean player, double timebase )
|
||||
int Delta_TestBaseline( const entity_state_t *from, const entity_state_t *to, qboolean player, double timebase )
|
||||
{
|
||||
delta_info_t *dt = NULL;
|
||||
delta_t *pField;
|
||||
@@ -1145,7 +1202,7 @@ int Delta_TestBaseline( entity_state_t *from, entity_state_t *to, qboolean playe
|
||||
// flag about field change (sets always)
|
||||
countBits++;
|
||||
|
||||
if( !Delta_CompareField( pField, from, to, timebase ))
|
||||
if( !Delta_CompareField( pField, from, to ))
|
||||
{
|
||||
// strings are handled differently
|
||||
if( FBitSet( pField->flags, DT_STRING ))
|
||||
@@ -1166,7 +1223,7 @@ write fields by offsets
|
||||
assume from and to is valid
|
||||
=====================
|
||||
*/
|
||||
static qboolean Delta_WriteField( sizebuf_t *msg, delta_t *pField, void *from, void *to, double timebase )
|
||||
static void Delta_WriteField_( sizebuf_t *msg, delta_t *pField, const void *from, const void *to, double timebase )
|
||||
{
|
||||
int signbit = FBitSet( pField->flags, DT_SIGNED ) ? 1 : 0;
|
||||
float flValue, flAngle;
|
||||
@@ -1174,14 +1231,6 @@ static qboolean Delta_WriteField( sizebuf_t *msg, delta_t *pField, void *from, v
|
||||
int dt;
|
||||
const char *pStr;
|
||||
|
||||
if( Delta_CompareField( pField, from, to, timebase ))
|
||||
{
|
||||
MSG_WriteOneBit( msg, 0 ); // unchanged
|
||||
return false;
|
||||
}
|
||||
|
||||
MSG_WriteOneBit( msg, 1 ); // changed
|
||||
|
||||
if( pField->flags & DT_BYTE )
|
||||
{
|
||||
if( signbit )
|
||||
@@ -1255,6 +1304,21 @@ static qboolean Delta_WriteField( sizebuf_t *msg, delta_t *pField, void *from, v
|
||||
pStr = (char *)((byte *)to + pField->offset );
|
||||
MSG_WriteString( msg, pStr );
|
||||
}
|
||||
}
|
||||
|
||||
static qboolean Delta_WriteField( sizebuf_t *msg, delta_t *pField, const void *from, const void *to, double timebase )
|
||||
{
|
||||
if( Delta_CompareField( pField, from, to ))
|
||||
{
|
||||
MSG_WriteOneBit( msg, 0 ); // unchanged
|
||||
return false;
|
||||
}
|
||||
|
||||
MSG_WriteOneBit( msg, 1 ); // changed
|
||||
|
||||
Delta_WriteField_( msg, pField, from, to, timebase );
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1264,7 +1328,7 @@ Delta_CopyField
|
||||
|
||||
====================
|
||||
*/
|
||||
static void Delta_CopyField( delta_t *pField, void *from, void *to, double timebase )
|
||||
static void Delta_CopyField( delta_t *pField, const void *from, void *to, double timebase )
|
||||
{
|
||||
qboolean bSigned = FBitSet( pField->flags, DT_SIGNED );
|
||||
uint8_t *to_field = (uint8_t *)to + pField->offset;
|
||||
@@ -1313,7 +1377,7 @@ read fields by offsets
|
||||
assume 'from' and 'to' is valid
|
||||
=====================
|
||||
*/
|
||||
static qboolean Delta_ReadField( sizebuf_t *msg, delta_t *pField, void *from, void *to, double timebase )
|
||||
static void Delta_ReadField_( sizebuf_t *msg, delta_t *pField, void *to, double timebase )
|
||||
{
|
||||
qboolean bSigned = ( pField->flags & DT_SIGNED ) ? true : false;
|
||||
float flValue, flAngle, flTime;
|
||||
@@ -1321,12 +1385,6 @@ static qboolean Delta_ReadField( sizebuf_t *msg, delta_t *pField, void *from, vo
|
||||
const char *pStr;
|
||||
char *pOut;
|
||||
|
||||
if( !MSG_ReadOneBit( msg ) )
|
||||
{
|
||||
Delta_CopyField( pField, from, to, timebase );
|
||||
return false;
|
||||
}
|
||||
|
||||
Assert( pField->multiplier != 0.0f );
|
||||
|
||||
if( pField->flags & DT_BYTE )
|
||||
@@ -1410,9 +1468,80 @@ static qboolean Delta_ReadField( sizebuf_t *msg, delta_t *pField, void *from, vo
|
||||
pOut = (char *)((byte *)to + pField->offset );
|
||||
Q_strncpy( pOut, pStr, pField->size );
|
||||
}
|
||||
}
|
||||
|
||||
static qboolean Delta_ReadField( sizebuf_t *msg, delta_t *pField, const void *from, void *to, double timebase )
|
||||
{
|
||||
if( !MSG_ReadOneBit( msg ))
|
||||
{
|
||||
Delta_CopyField( pField, from, to, timebase );
|
||||
return false;
|
||||
}
|
||||
|
||||
Delta_ReadField_( msg, pField, to, timebase );
|
||||
return true;
|
||||
}
|
||||
|
||||
void Delta_ReadGSFields( sizebuf_t *msg, int index, void *from, void *to, double timebase )
|
||||
{
|
||||
delta_info_t *dt = Delta_FindStructByIndex( index );
|
||||
uint8_t bits[8] = { 0 };
|
||||
delta_t *pField;
|
||||
byte c;
|
||||
int i;
|
||||
|
||||
c = MSG_ReadUBitLong( msg, 3 );
|
||||
|
||||
for( i = 0; i < c; i++ )
|
||||
bits[i] = MSG_ReadByte( msg );
|
||||
|
||||
for( i = 0, pField = dt->pFields; i < dt->numFields; i++, pField++ )
|
||||
{
|
||||
int b = i >> 3;
|
||||
int n = 1 << ( i & 7 );
|
||||
|
||||
if( FBitSet( bits[b], n ))
|
||||
Delta_ReadField_( msg, pField, to, timebase );
|
||||
else Delta_CopyField( pField, from, to, timebase );
|
||||
}
|
||||
}
|
||||
|
||||
void Delta_WriteGSFields( sizebuf_t *msg, int index, void *from, void *to, double timebase )
|
||||
{
|
||||
delta_info_t *dt = Delta_FindStructByIndex( index );
|
||||
delta_t *pField;
|
||||
uint8_t bits[8] = { 0 };
|
||||
uint c = 0;
|
||||
int i;
|
||||
|
||||
Delta_CustomEncode( dt, from, to );
|
||||
|
||||
for( i = 0, pField = dt->pFields; i < dt->numFields; i++, pField++ )
|
||||
{
|
||||
if( !Delta_CompareField( pField, from, to ))
|
||||
{
|
||||
int b = i >> 3;
|
||||
int n = 1 << ( i & 7 );
|
||||
|
||||
SetBits( bits[b], n );
|
||||
c = b + 1;
|
||||
}
|
||||
}
|
||||
|
||||
MSG_WriteUBitLong( msg, c, 3 );
|
||||
for( i = 0; i < c; i++ )
|
||||
MSG_WriteByte( msg, bits[i] );
|
||||
|
||||
for( i = 0, pField = dt->pFields; i < dt->numFields; i++, pField++ )
|
||||
{
|
||||
int b = i >> 3;
|
||||
int n = 1 << ( i & 7 );
|
||||
|
||||
if( FBitSet( bits[b], n ))
|
||||
Delta_WriteField_( msg, pField, from, to, timebase );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
=============================================================================
|
||||
|
||||
@@ -1425,7 +1554,7 @@ usercmd_t communication
|
||||
MSG_WriteDeltaUsercmd
|
||||
=====================
|
||||
*/
|
||||
void MSG_WriteDeltaUsercmd( sizebuf_t *msg, usercmd_t *from, usercmd_t *to )
|
||||
void MSG_WriteDeltaUsercmd( sizebuf_t *msg, const usercmd_t *from, const usercmd_t *to )
|
||||
{
|
||||
delta_t *pField;
|
||||
delta_info_t *dt;
|
||||
@@ -1452,7 +1581,7 @@ void MSG_WriteDeltaUsercmd( sizebuf_t *msg, usercmd_t *from, usercmd_t *to )
|
||||
MSG_ReadDeltaUsercmd
|
||||
=====================
|
||||
*/
|
||||
void MSG_ReadDeltaUsercmd( sizebuf_t *msg, usercmd_t *from, usercmd_t *to )
|
||||
void MSG_ReadDeltaUsercmd( sizebuf_t *msg, const usercmd_t *from, usercmd_t *to )
|
||||
{
|
||||
delta_t *pField;
|
||||
delta_info_t *dt;
|
||||
@@ -1487,7 +1616,7 @@ event_args_t communication
|
||||
MSG_WriteDeltaEvent
|
||||
=====================
|
||||
*/
|
||||
void MSG_WriteDeltaEvent( sizebuf_t *msg, event_args_t *from, event_args_t *to )
|
||||
void MSG_WriteDeltaEvent( sizebuf_t *msg, const event_args_t *from, const event_args_t *to )
|
||||
{
|
||||
delta_t *pField;
|
||||
delta_info_t *dt;
|
||||
@@ -1514,7 +1643,7 @@ void MSG_WriteDeltaEvent( sizebuf_t *msg, event_args_t *from, event_args_t *to )
|
||||
MSG_ReadDeltaEvent
|
||||
=====================
|
||||
*/
|
||||
void MSG_ReadDeltaEvent( sizebuf_t *msg, event_args_t *from, event_args_t *to )
|
||||
void MSG_ReadDeltaEvent( sizebuf_t *msg, const event_args_t *from, event_args_t *to )
|
||||
{
|
||||
delta_t *pField;
|
||||
delta_info_t *dt;
|
||||
@@ -1542,7 +1671,7 @@ movevars_t communication
|
||||
|
||||
=============================================================================
|
||||
*/
|
||||
qboolean MSG_WriteDeltaMovevars( sizebuf_t *msg, movevars_t *from, movevars_t *to )
|
||||
qboolean MSG_WriteDeltaMovevars( sizebuf_t *msg, const movevars_t *from, const movevars_t *to )
|
||||
{
|
||||
delta_t *pField;
|
||||
delta_info_t *dt;
|
||||
@@ -1578,7 +1707,7 @@ qboolean MSG_WriteDeltaMovevars( sizebuf_t *msg, movevars_t *from, movevars_t *t
|
||||
return true;
|
||||
}
|
||||
|
||||
void MSG_ReadDeltaMovevars( sizebuf_t *msg, movevars_t *from, movevars_t *to )
|
||||
void MSG_ReadDeltaMovevars( sizebuf_t *msg, const movevars_t *from, movevars_t *to )
|
||||
{
|
||||
delta_t *pField;
|
||||
delta_info_t *dt;
|
||||
@@ -1614,7 +1743,7 @@ Writes current client data only for local client
|
||||
Other clients can grab the client state from entity_state_t
|
||||
==================
|
||||
*/
|
||||
void MSG_WriteClientData( sizebuf_t *msg, clientdata_t *from, clientdata_t *to, double timebase )
|
||||
void MSG_WriteClientData( sizebuf_t *msg, const clientdata_t *from, const clientdata_t *to, double timebase )
|
||||
{
|
||||
delta_t *pField;
|
||||
delta_info_t *dt;
|
||||
@@ -1654,7 +1783,7 @@ MSG_ReadClientData
|
||||
Read the clientdata
|
||||
==================
|
||||
*/
|
||||
void MSG_ReadClientData( sizebuf_t *msg, clientdata_t *from, clientdata_t *to, double timebase )
|
||||
void MSG_ReadClientData( sizebuf_t *msg, const clientdata_t *from, clientdata_t *to, double timebase )
|
||||
{
|
||||
#if !XASH_DEDICATED
|
||||
delta_t *pField;
|
||||
@@ -1695,7 +1824,7 @@ Writes current client data only for local client
|
||||
Other clients can grab the client state from entity_state_t
|
||||
==================
|
||||
*/
|
||||
void MSG_WriteWeaponData( sizebuf_t *msg, weapon_data_t *from, weapon_data_t *to, double timebase, int index )
|
||||
void MSG_WriteWeaponData( sizebuf_t *msg, const weapon_data_t *from, const weapon_data_t *to, double timebase, int index )
|
||||
{
|
||||
delta_t *pField;
|
||||
delta_info_t *dt;
|
||||
@@ -1734,7 +1863,7 @@ MSG_ReadWeaponData
|
||||
Read the clientdata
|
||||
==================
|
||||
*/
|
||||
void MSG_ReadWeaponData( sizebuf_t *msg, weapon_data_t *from, weapon_data_t *to, double timebase )
|
||||
void MSG_ReadWeaponData( sizebuf_t *msg, const weapon_data_t *from, weapon_data_t *to, double timebase )
|
||||
{
|
||||
delta_t *pField;
|
||||
delta_info_t *dt;
|
||||
@@ -1771,7 +1900,7 @@ If force is not set, then nothing at all will be generated if the entity is
|
||||
identical, under the assumption that the in-order delta code will catch it.
|
||||
==================
|
||||
*/
|
||||
void MSG_WriteDeltaEntity( entity_state_t *from, entity_state_t *to, sizebuf_t *msg, qboolean force, int delta_type, double timebase, int baseline )
|
||||
void MSG_WriteDeltaEntity( const entity_state_t *from, const entity_state_t *to, sizebuf_t *msg, qboolean force, int delta_type, double timebase, int baseline )
|
||||
{
|
||||
delta_info_t *dt = NULL;
|
||||
delta_t *pField;
|
||||
@@ -1873,7 +2002,7 @@ If the delta removes the entity, entity_state_t->number will be set to MAX_EDICT
|
||||
Can go from either a baseline or a previous packet_entity
|
||||
==================
|
||||
*/
|
||||
qboolean MSG_ReadDeltaEntity( sizebuf_t *msg, entity_state_t *from, entity_state_t *to, int number, int delta_type, double timebase )
|
||||
qboolean MSG_ReadDeltaEntity( sizebuf_t *msg, const entity_state_t *from, entity_state_t *to, int number, int delta_type, double timebase )
|
||||
{
|
||||
#if !XASH_DEDICATED
|
||||
delta_info_t *dt = NULL;
|
||||
@@ -1882,7 +2011,10 @@ qboolean MSG_ReadDeltaEntity( sizebuf_t *msg, entity_state_t *from, entity_state
|
||||
int baseline_offset = 0;
|
||||
|
||||
if( number < 0 || number >= clgame.maxEntities )
|
||||
Host_Error( "%s: bad delta entity number: %i\n", __func__, number );
|
||||
{
|
||||
Con_Printf( S_ERROR "%s: bad delta entity number: %i\n", __func__, number );
|
||||
return false;
|
||||
}
|
||||
|
||||
fRemoveType = MSG_ReadUBitLong( msg, 2 );
|
||||
|
||||
@@ -1904,7 +2036,8 @@ qboolean MSG_ReadDeltaEntity( sizebuf_t *msg, entity_state_t *from, entity_state
|
||||
return false;
|
||||
}
|
||||
|
||||
Host_Error( "%s: unknown update type %i\n", __func__, fRemoveType );
|
||||
Con_Printf( S_ERROR "%s: unknown update type %i\n", __func__, fRemoveType );
|
||||
return false;
|
||||
}
|
||||
|
||||
if( !cls.legacymode )
|
||||
@@ -1952,7 +2085,11 @@ qboolean MSG_ReadDeltaEntity( sizebuf_t *msg, entity_state_t *from, entity_state
|
||||
dt = Delta_FindStructByIndex( DT_ENTITY_STATE_T );
|
||||
}
|
||||
|
||||
Assert( dt && dt->bInitialized );
|
||||
if( !dt || !dt->bInitialized )
|
||||
{
|
||||
Con_Printf( S_ERROR "%s: broken delta\n", __func__ );
|
||||
return true;
|
||||
}
|
||||
|
||||
pField = dt->pFields;
|
||||
Assert( pField != NULL );
|
||||
|
||||
+45
-13
@@ -33,6 +33,23 @@ enum
|
||||
DELTA_STATIC,
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
DT_EVENT_T = 0,
|
||||
DT_MOVEVARS_T,
|
||||
DT_USERCMD_T,
|
||||
DT_CLIENTDATA_T,
|
||||
DT_WEAPONDATA_T,
|
||||
DT_ENTITY_STATE_T,
|
||||
DT_ENTITY_STATE_PLAYER_T,
|
||||
DT_CUSTOM_ENTITY_STATE_T,
|
||||
DT_GOLDSRC_DELTA_T,
|
||||
#if XASH_ENGINE_TESTS
|
||||
DT_DELTA_TEST_STRUCT_T,
|
||||
#endif
|
||||
DT_STRUCT_COUNT
|
||||
};
|
||||
|
||||
// struct info (filled by engine)
|
||||
typedef struct
|
||||
{
|
||||
@@ -54,6 +71,17 @@ struct delta_s
|
||||
qboolean bInactive; // unsetted by user request
|
||||
};
|
||||
|
||||
typedef struct goldsrc_delta_s
|
||||
{
|
||||
int fieldType;
|
||||
char fieldName[32];
|
||||
int fieldOffset;
|
||||
short fieldSize;
|
||||
int significant_bits;
|
||||
float premultiply;
|
||||
float postmultiply;
|
||||
} goldsrc_delta_t;
|
||||
|
||||
typedef void (*pfnDeltaEncode)( struct delta_s *pFields, const byte *from, const byte *to );
|
||||
|
||||
typedef struct
|
||||
@@ -76,6 +104,7 @@ typedef struct
|
||||
//
|
||||
void Delta_Init( void );
|
||||
void Delta_InitClient( void );
|
||||
void Delta_InitMeta( void );
|
||||
void Delta_Shutdown( void );
|
||||
void Delta_AddEncoder( char *name, pfnDeltaEncode encodeFunc );
|
||||
int Delta_FindField( delta_t *pFields, const char *fieldname );
|
||||
@@ -87,6 +116,7 @@ void Delta_UnsetFieldByIndex( delta_t *pFields, int fieldNumber );
|
||||
// send table over network
|
||||
void Delta_WriteDescriptionToClient( sizebuf_t *msg );
|
||||
void Delta_ParseTableField( sizebuf_t *msg );
|
||||
void Delta_ParseTableField_GS( sizebuf_t *msg );
|
||||
|
||||
|
||||
// encode routines
|
||||
@@ -96,18 +126,20 @@ struct event_args_s;
|
||||
struct movevars_s;
|
||||
struct clientdata_s;
|
||||
struct weapon_data_s;
|
||||
void MSG_WriteDeltaUsercmd( sizebuf_t *msg, struct usercmd_s *from, struct usercmd_s *to );
|
||||
void MSG_ReadDeltaUsercmd( sizebuf_t *msg, struct usercmd_s *from, struct usercmd_s *to );
|
||||
void MSG_WriteDeltaEvent( sizebuf_t *msg, struct event_args_s *from, struct event_args_s *to );
|
||||
void MSG_ReadDeltaEvent( sizebuf_t *msg, struct event_args_s *from, struct event_args_s *to );
|
||||
qboolean MSG_WriteDeltaMovevars( sizebuf_t *msg, struct movevars_s *from, struct movevars_s *to );
|
||||
void MSG_ReadDeltaMovevars( sizebuf_t *msg, struct movevars_s *from, struct movevars_s *to );
|
||||
void MSG_WriteClientData( sizebuf_t *msg, struct clientdata_s *from, struct clientdata_s *to, double timebase );
|
||||
void MSG_ReadClientData( sizebuf_t *msg, struct clientdata_s *from, struct clientdata_s *to, double timebase );
|
||||
void MSG_WriteWeaponData( sizebuf_t *msg, struct weapon_data_s *from, struct weapon_data_s *to, double timebase, int index );
|
||||
void MSG_ReadWeaponData( sizebuf_t *msg, struct weapon_data_s *from, struct weapon_data_s *to, double timebase );
|
||||
void MSG_WriteDeltaEntity( struct entity_state_s *from, struct entity_state_s *to, sizebuf_t *msg, qboolean force, int type, double timebase, int ofs );
|
||||
qboolean MSG_ReadDeltaEntity( sizebuf_t *msg, struct entity_state_s *from, struct entity_state_s *to, int num, int type, double timebase );
|
||||
int Delta_TestBaseline( struct entity_state_s *from, struct entity_state_s *to, qboolean player, double timebase );
|
||||
void MSG_WriteDeltaUsercmd( sizebuf_t *msg, const struct usercmd_s *from, const struct usercmd_s *to );
|
||||
void MSG_ReadDeltaUsercmd( sizebuf_t *msg, const struct usercmd_s *from, struct usercmd_s *to );
|
||||
void MSG_WriteDeltaEvent( sizebuf_t *msg, const struct event_args_s *from, const struct event_args_s *to );
|
||||
void MSG_ReadDeltaEvent( sizebuf_t *msg, const struct event_args_s *from, struct event_args_s *to );
|
||||
qboolean MSG_WriteDeltaMovevars( sizebuf_t *msg, const struct movevars_s *from, const struct movevars_s *to );
|
||||
void MSG_ReadDeltaMovevars( sizebuf_t *msg, const struct movevars_s *from, struct movevars_s *to );
|
||||
void MSG_WriteClientData( sizebuf_t *msg, const struct clientdata_s *from, const struct clientdata_s *to, double timebase );
|
||||
void MSG_ReadClientData( sizebuf_t *msg, const struct clientdata_s *from, struct clientdata_s *to, double timebase );
|
||||
void MSG_WriteWeaponData( sizebuf_t *msg, const struct weapon_data_s *from, const struct weapon_data_s *to, double timebase, int index );
|
||||
void MSG_ReadWeaponData( sizebuf_t *msg, const struct weapon_data_s *from, struct weapon_data_s *to, double timebase );
|
||||
void MSG_WriteDeltaEntity( const struct entity_state_s *from, const struct entity_state_s *to, sizebuf_t *msg, qboolean force, int type, double timebase, int ofs );
|
||||
qboolean MSG_ReadDeltaEntity( sizebuf_t *msg, const struct entity_state_s *from, struct entity_state_s *to, int num, int type, double timebase );
|
||||
int Delta_TestBaseline( const struct entity_state_s *from, const struct entity_state_s *to, qboolean player, double timebase );
|
||||
void Delta_ReadGSFields( sizebuf_t *msg, int index, void *from, void *to, double timebase );
|
||||
void Delta_WriteGSFields( sizebuf_t *msg, int index, void *from, void *to, double timebase );
|
||||
|
||||
#endif//NET_ENCODE_H
|
||||
|
||||
+157
-117
@@ -18,16 +18,20 @@ GNU General Public License for more details.
|
||||
#include "netchan.h"
|
||||
#include "xash3d_mathlib.h"
|
||||
#include "ipv6text.h"
|
||||
#if XASH_WIN32
|
||||
#include "platform/win32/net.h"
|
||||
#elif defined XASH_NO_NETWORK
|
||||
|
||||
#if XASH_NO_NETWORK
|
||||
#include "platform/stub/net_stub.h"
|
||||
#elif XASH_WIN32
|
||||
#include "platform/win32/net.h"
|
||||
#elif XASH_PSVITA
|
||||
#include "platform/psvita/net_psvita.h"
|
||||
static const struct in6_addr in6addr_any;
|
||||
#else
|
||||
#include "platform/posix/net.h"
|
||||
#endif
|
||||
#if XASH_PSVITA
|
||||
#include "platform/psvita/net_psvita.h"
|
||||
static const struct in6_addr in6addr_any;
|
||||
|
||||
#if XASH_SDL == 2
|
||||
#include <SDL_thread.h>
|
||||
#endif
|
||||
|
||||
#define NET_USE_FRAGMENTS
|
||||
@@ -83,6 +87,13 @@ typedef struct
|
||||
int sequence_number;
|
||||
short packet_id;
|
||||
} SPLITPACKET;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int net_id;
|
||||
int sequence_number;
|
||||
unsigned char packet_id;
|
||||
} SPLITPACKETGS;
|
||||
#pragma pack(pop)
|
||||
|
||||
typedef struct
|
||||
@@ -115,6 +126,7 @@ static CVAR_DEFINE( net_ipclientport, "ip_clientport", "0", FCVAR_READ_ONLY, "ne
|
||||
static CVAR_DEFINE( net_clientport, "clientport", "0", FCVAR_READ_ONLY, "network default client port" );
|
||||
static CVAR_DEFINE( net_fakelag, "fakelag", "0", FCVAR_PRIVILEGED, "lag all incoming network data (including loopback) by xxx ms." );
|
||||
static CVAR_DEFINE( net_fakeloss, "fakeloss", "0", FCVAR_PRIVILEGED, "act like we dropped the packet this % of the time." );
|
||||
static CVAR_DEFINE_AUTO( net_resolve_debug, "0", FCVAR_PRIVILEGED, "print resolve thread debug messages" );
|
||||
CVAR_DEFINE( net_clockwindow, "clockwindow", "0.5", FCVAR_PRIVILEGED, "timewindow to execute client moves" );
|
||||
|
||||
netadr_t net_local;
|
||||
@@ -126,6 +138,8 @@ static CVAR_DEFINE( net_ip6hostport, "ip6_hostport", "0", FCVAR_READ_ONLY, "netw
|
||||
static CVAR_DEFINE( net_ip6clientport, "ip6_clientport", "0", FCVAR_READ_ONLY, "network ip6 client port" );
|
||||
static CVAR_DEFINE_AUTO( net6_address, "0", FCVAR_PRIVILEGED|FCVAR_READ_ONLY, "contain local IPv6 address of current client" );
|
||||
|
||||
static void NET_ClearLagData( qboolean bClient, qboolean bServer );
|
||||
|
||||
/*
|
||||
====================
|
||||
NET_ErrorString
|
||||
@@ -192,7 +206,7 @@ static char *NET_ErrorString( void )
|
||||
#endif
|
||||
}
|
||||
|
||||
_inline socklen_t NET_SockAddrLen( const struct sockaddr_storage *addr )
|
||||
static inline socklen_t NET_SockAddrLen( const struct sockaddr_storage *addr )
|
||||
{
|
||||
switch ( addr->ss_family )
|
||||
{
|
||||
@@ -205,7 +219,7 @@ _inline socklen_t NET_SockAddrLen( const struct sockaddr_storage *addr )
|
||||
}
|
||||
}
|
||||
|
||||
_inline qboolean NET_IsSocketError( int retval )
|
||||
static inline qboolean NET_IsSocketError( int retval )
|
||||
{
|
||||
#if XASH_WIN32 || XASH_DOS4GW
|
||||
return retval == SOCKET_ERROR ? true : false;
|
||||
@@ -214,7 +228,7 @@ _inline qboolean NET_IsSocketError( int retval )
|
||||
#endif
|
||||
}
|
||||
|
||||
_inline qboolean NET_IsSocketValid( int socket )
|
||||
static inline qboolean NET_IsSocketValid( int socket )
|
||||
{
|
||||
#if XASH_WIN32 || XASH_DOS4GW
|
||||
return socket != INVALID_SOCKET;
|
||||
@@ -249,40 +263,27 @@ static void NET_NetadrToSockadr( netadr_t *a, struct sockaddr_storage *s )
|
||||
|
||||
if( a->type == NA_BROADCAST )
|
||||
{
|
||||
((struct sockaddr_in *)s)->sin_family = AF_INET;
|
||||
s->ss_family = AF_INET;
|
||||
((struct sockaddr_in *)s)->sin_port = a->port;
|
||||
((struct sockaddr_in *)s)->sin_addr.s_addr = INADDR_BROADCAST;
|
||||
}
|
||||
else if( a->type == NA_IP )
|
||||
{
|
||||
((struct sockaddr_in *)s)->sin_family = AF_INET;
|
||||
s->ss_family = AF_INET;
|
||||
((struct sockaddr_in *)s)->sin_port = a->port;
|
||||
((struct sockaddr_in *)s)->sin_addr.s_addr = a->ip4;
|
||||
}
|
||||
else if( a->type6 == NA_IP6 )
|
||||
{
|
||||
struct in6_addr ip6;
|
||||
|
||||
NET_NetadrToIP6Bytes( ip6.s6_addr, a );
|
||||
|
||||
if( IN6_IS_ADDR_V4MAPPED( &ip6 ))
|
||||
{
|
||||
((struct sockaddr_in *)s)->sin_family = AF_INET;
|
||||
((struct sockaddr_in *)s)->sin_addr.s_addr = *(uint32_t *)(ip6.s6_addr + 12);
|
||||
((struct sockaddr_in *)s)->sin_port = a->port;
|
||||
}
|
||||
else
|
||||
{
|
||||
((struct sockaddr_in6 *)s)->sin6_family = AF_INET6;
|
||||
memcpy( &((struct sockaddr_in6 *)s)->sin6_addr, &ip6, sizeof( struct in6_addr ));
|
||||
((struct sockaddr_in6 *)s)->sin6_port = a->port;
|
||||
}
|
||||
s->ss_family = AF_INET6;
|
||||
((struct sockaddr_in6 *)s)->sin6_port = a->port;
|
||||
NET_NetadrToIP6Bytes(((struct sockaddr_in6 *)s)->sin6_addr.s6_addr, a );
|
||||
}
|
||||
else if( a->type6 == NA_MULTICAST_IP6 )
|
||||
{
|
||||
((struct sockaddr_in6 *)s)->sin6_family = AF_INET6;
|
||||
memcpy(((struct sockaddr_in6 *)s)->sin6_addr.s6_addr, k_ipv6Bytes_LinkLocalAllNodes, sizeof( struct in6_addr ));
|
||||
s->ss_family = AF_INET6;
|
||||
((struct sockaddr_in6 *)s)->sin6_port = a->port;
|
||||
memcpy(((struct sockaddr_in6 *)s)->sin6_addr.s6_addr, k_ipv6Bytes_LinkLocalAllNodes, sizeof( struct in6_addr ));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -301,13 +302,8 @@ static void NET_SockadrToNetadr( const struct sockaddr_storage *s, netadr_t *a )
|
||||
}
|
||||
else if( s->ss_family == AF_INET6 )
|
||||
{
|
||||
a->type6 = NA_IP6;
|
||||
NET_IP6BytesToNetadr( a, ((struct sockaddr_in6 *)s)->sin6_addr.s6_addr );
|
||||
|
||||
if( IN6_IS_ADDR_V4MAPPED( &((struct sockaddr_in6 *)s)->sin6_addr ))
|
||||
a->type = NA_IP;
|
||||
else
|
||||
a->type6 = NA_IP6;
|
||||
|
||||
a->port = ((struct sockaddr_in6 *)s)->sin6_port;
|
||||
}
|
||||
}
|
||||
@@ -324,6 +320,11 @@ static qboolean NET_GetHostByName( const char *hostname, int family, struct sock
|
||||
struct addrinfo hints;
|
||||
qboolean ret = false;
|
||||
|
||||
#if XASH_NO_IPV6_RESOLVE
|
||||
if( family == AF_INET6 )
|
||||
return false;
|
||||
#endif
|
||||
|
||||
memset( &hints, 0, sizeof( hints ));
|
||||
hints.ai_family = family;
|
||||
|
||||
@@ -346,6 +347,12 @@ static qboolean NET_GetHostByName( const char *hostname, int family, struct sock
|
||||
return ret;
|
||||
#else
|
||||
struct hostent *h;
|
||||
|
||||
#if XASH_NO_IPV6_RESOLVE
|
||||
if( family == AF_INET6 )
|
||||
return false;
|
||||
#endif
|
||||
|
||||
if(!( h = gethostbyname( hostname )))
|
||||
return false;
|
||||
|
||||
@@ -363,27 +370,44 @@ static qboolean NET_GetHostByName( const char *hostname, int family, struct sock
|
||||
#ifdef CAN_ASYNC_NS_RESOLVE
|
||||
static void NET_ResolveThread( void );
|
||||
|
||||
#if !XASH_WIN32
|
||||
#if XASH_SDL == 2
|
||||
#define mutex_create( x ) (( x ) = SDL_CreateMutex() )
|
||||
#define mutex_destroy( x ) SDL_DestroyMutex(( x ))
|
||||
#define mutex_lock( x ) SDL_LockMutex(( x ))
|
||||
#define mutex_unlock( x ) SDL_UnlockMutex(( x ))
|
||||
#define create_thread( thread, pfn ) (( thread ) = SDL_CreateThread(( pfn ), "DNS resolver thread", NULL ))
|
||||
#define detach_thread( x ) SDL_DetachThread(( x ))
|
||||
typedef SDL_mutex *mutex_t;
|
||||
typedef SDL_Thread *thread_t;
|
||||
static int NET_ThreadStart( void *ununsed )
|
||||
{
|
||||
NET_ResolveThread();
|
||||
return 0;
|
||||
}
|
||||
#elif !XASH_WIN32
|
||||
#include <pthread.h>
|
||||
#define mutex_lock pthread_mutex_lock
|
||||
#define mutex_unlock pthread_mutex_unlock
|
||||
#define exit_thread( x ) pthread_exit(x)
|
||||
#define create_thread( pfn ) !pthread_create( &nsthread.thread, NULL, (pfn), NULL )
|
||||
#define detach_thread( x ) pthread_detach(x)
|
||||
#define mutex_t pthread_mutex_t
|
||||
#define thread_t pthread_t
|
||||
#define mutex_create( x ) pthread_mutex_init( &( x ), NULL )
|
||||
#define mutex_destroy( x ) pthread_mutex_destroy( &( x ))
|
||||
#define mutex_lock( x ) pthread_mutex_lock( &( x ))
|
||||
#define mutex_unlock( x ) pthread_mutex_unlock( &( x ))
|
||||
#define create_thread( thread, pfn ) !pthread_create( &( thread ), NULL, ( pfn ), NULL )
|
||||
#define detach_thread( x ) pthread_detach( x )
|
||||
typedef pthread_mutex_t mutex_t;
|
||||
typedef pthread_t thread_t;
|
||||
static void *NET_ThreadStart( void *unused )
|
||||
{
|
||||
NET_ResolveThread();
|
||||
return NULL;
|
||||
}
|
||||
#else // WIN32
|
||||
#define mutex_lock EnterCriticalSection
|
||||
#define mutex_unlock LeaveCriticalSection
|
||||
#define detach_thread( x ) CloseHandle(x)
|
||||
#define create_thread( pfn ) ( nsthread.thread = CreateThread( NULL, 0, pfn, NULL, 0, NULL ))
|
||||
#define mutex_t CRITICAL_SECTION
|
||||
#define thread_t HANDLE
|
||||
#define mutex_create( x ) InitializeCriticalSection( &( x ))
|
||||
#define mutex_destroy( x ) DeleteCriticalSection( &( x ))
|
||||
#define mutex_lock( x ) EnterCriticalSection( &( x ))
|
||||
#define mutex_unlock( x ) LeaveCriticalSection( &( x ))
|
||||
#define create_thread( thread, pfn ) (( thread ) = CreateThread( NULL, 0, ( pfn ), NULL, 0, NULL ))
|
||||
#define detach_thread( x ) CloseHandle(( x ))
|
||||
typedef CRITICAL_SECTION mutex_t;
|
||||
typedef HANDLE thread_t;
|
||||
DWORD WINAPI NET_ThreadStart( LPVOID unused )
|
||||
{
|
||||
NET_ResolveThread();
|
||||
@@ -392,38 +416,42 @@ DWORD WINAPI NET_ThreadStart( LPVOID unused )
|
||||
}
|
||||
#endif // !_WIN32
|
||||
|
||||
#ifdef DEBUG_RESOLVE
|
||||
#define RESOLVE_DBG(x) Sys_PrintLog(x)
|
||||
#else
|
||||
#define RESOLVE_DBG(x)
|
||||
#endif // DEBUG_RESOLVE
|
||||
#define RESOLVE_DBG( x ) do { if( net_resolve_debug.value ) Sys_PrintLog(( x )); } while( 0 )
|
||||
|
||||
static struct nsthread_s
|
||||
{
|
||||
mutex_t mutexns;
|
||||
mutex_t mutexres;
|
||||
mutex_t mutexns;
|
||||
mutex_t mutexres;
|
||||
thread_t thread;
|
||||
int result;
|
||||
string hostname;
|
||||
int family;
|
||||
int result;
|
||||
string hostname;
|
||||
int family;
|
||||
struct sockaddr_storage addr;
|
||||
qboolean busy;
|
||||
} nsthread
|
||||
#if !XASH_WIN32
|
||||
= { PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER }
|
||||
#endif
|
||||
;
|
||||
} nsthread;
|
||||
|
||||
static void NET_InitializeCriticalSections( void )
|
||||
{
|
||||
net.threads_initialized = true;
|
||||
#if XASH_WIN32
|
||||
InitializeCriticalSection( &nsthread.mutexns );
|
||||
InitializeCriticalSection( &nsthread.mutexres );
|
||||
#endif
|
||||
|
||||
mutex_create( nsthread.mutexns );
|
||||
mutex_create( nsthread.mutexres );
|
||||
}
|
||||
|
||||
void NET_ResolveThread( void )
|
||||
static void NET_DeleteCriticalSections( void )
|
||||
{
|
||||
if( net.threads_initialized )
|
||||
{
|
||||
mutex_destroy( nsthread.mutexns );
|
||||
mutex_destroy( nsthread.mutexres );
|
||||
|
||||
net.threads_initialized = false;
|
||||
}
|
||||
|
||||
memset( &nsthread, 0, sizeof( nsthread ));
|
||||
}
|
||||
|
||||
static void NET_ResolveThread( void )
|
||||
{
|
||||
struct sockaddr_storage addr;
|
||||
qboolean res;
|
||||
@@ -440,12 +468,12 @@ void NET_ResolveThread( void )
|
||||
RESOLVE_DBG( "[resolve thread] success\n" );
|
||||
else
|
||||
RESOLVE_DBG( "[resolve thread] failed\n" );
|
||||
mutex_lock( &nsthread.mutexres );
|
||||
mutex_lock( nsthread.mutexres );
|
||||
nsthread.addr = addr;
|
||||
nsthread.busy = false;
|
||||
nsthread.result = res ? NET_EAI_OK : NET_EAI_NONAME;
|
||||
RESOLVE_DBG( "[resolve thread] returning result\n" );
|
||||
mutex_unlock( &nsthread.mutexres );
|
||||
mutex_unlock( nsthread.mutexres );
|
||||
RESOLVE_DBG( "[resolve thread] exiting thread\n" );
|
||||
}
|
||||
#endif // CAN_ASYNC_NS_RESOLVE
|
||||
@@ -510,11 +538,11 @@ static net_gai_state_t NET_StringToSockaddr( const char *s, struct sockaddr_stor
|
||||
#ifdef CAN_ASYNC_NS_RESOLVE
|
||||
if( net.threads_initialized && nonblocking )
|
||||
{
|
||||
mutex_lock( &nsthread.mutexres );
|
||||
mutex_lock( nsthread.mutexres );
|
||||
|
||||
if( nsthread.busy )
|
||||
{
|
||||
mutex_unlock( &nsthread.mutexres );
|
||||
mutex_unlock( nsthread.mutexres );
|
||||
return NET_EAI_AGAIN;
|
||||
}
|
||||
|
||||
@@ -535,28 +563,24 @@ static net_gai_state_t NET_StringToSockaddr( const char *s, struct sockaddr_stor
|
||||
Q_strncpy( nsthread.hostname, copy, sizeof( nsthread.hostname ));
|
||||
nsthread.family = family;
|
||||
nsthread.busy = true;
|
||||
mutex_unlock( &nsthread.mutexres );
|
||||
mutex_unlock( nsthread.mutexres );
|
||||
|
||||
if( create_thread( NET_ThreadStart ))
|
||||
if( create_thread( nsthread.thread, NET_ThreadStart ))
|
||||
{
|
||||
asyncfailed = false;
|
||||
return NET_EAI_AGAIN;
|
||||
}
|
||||
else // failed to create thread
|
||||
{
|
||||
Con_Reportf( S_ERROR "%s: failed to create thread!\n", __func__ );
|
||||
nsthread.busy = false;
|
||||
}
|
||||
|
||||
Con_Reportf( S_ERROR "%s: failed to create thread!\n", __func__ );
|
||||
nsthread.busy = false;
|
||||
}
|
||||
|
||||
mutex_unlock( &nsthread.mutexres );
|
||||
mutex_unlock( nsthread.mutexres );
|
||||
}
|
||||
#endif // CAN_ASYNC_NS_RESOLVE
|
||||
|
||||
if( asyncfailed )
|
||||
{
|
||||
ret = NET_GetHostByName( copy, family, &temp );
|
||||
}
|
||||
|
||||
if( !ret )
|
||||
{
|
||||
@@ -570,16 +594,9 @@ static net_gai_state_t NET_StringToSockaddr( const char *s, struct sockaddr_stor
|
||||
sadr->ss_family = temp.ss_family;
|
||||
|
||||
if( temp.ss_family == AF_INET )
|
||||
{
|
||||
((struct sockaddr_in *)sadr)->sin_addr =
|
||||
((struct sockaddr_in*)&temp)->sin_addr;
|
||||
}
|
||||
((struct sockaddr_in *)sadr)->sin_addr = ((struct sockaddr_in*)&temp)->sin_addr;
|
||||
else if( temp.ss_family == AF_INET6 )
|
||||
{
|
||||
memcpy(&((struct sockaddr_in6 *)sadr)->sin6_addr,
|
||||
&((struct sockaddr_in6*)&temp)->sin6_addr,
|
||||
sizeof( struct in6_addr ));
|
||||
}
|
||||
((struct sockaddr_in6 *)sadr)->sin6_addr = ((struct sockaddr_in6*)&temp)->sin6_addr;
|
||||
}
|
||||
|
||||
return NET_EAI_OK;
|
||||
@@ -1042,19 +1059,20 @@ qboolean NET_StringToAdr( const char *string, netadr_t *adr )
|
||||
return NET_StringToAdrEx( string, adr, AF_UNSPEC );
|
||||
}
|
||||
|
||||
net_gai_state_t NET_StringToAdrNB( const char *string, netadr_t *adr )
|
||||
net_gai_state_t NET_StringToAdrNB( const char *string, netadr_t *adr, qboolean v6only )
|
||||
{
|
||||
struct sockaddr_storage s;
|
||||
net_gai_state_t res;
|
||||
|
||||
memset( adr, 0, sizeof( netadr_t ));
|
||||
|
||||
if( !Q_stricmp( string, "localhost" ) || !Q_stricmp( string, "loopback" ))
|
||||
{
|
||||
adr->type = NA_LOOPBACK;
|
||||
return NET_EAI_OK;
|
||||
}
|
||||
|
||||
res = NET_StringToSockaddr( string, &s, true, AF_UNSPEC );
|
||||
res = NET_StringToSockaddr( string, &s, true, v6only ? AF_INET6 : AF_UNSPEC );
|
||||
|
||||
if( res == NET_EAI_OK )
|
||||
NET_SockadrToNetadr( &s, adr );
|
||||
@@ -1209,7 +1227,7 @@ static void NET_AddToLagged( netsrc_t sock, packetlag_t *list, packetlag_t *pack
|
||||
packet->data = pStart;
|
||||
packet->size = length;
|
||||
packet->receivedtime = timestamp;
|
||||
memcpy( &packet->from, from, sizeof( netadr_t ));
|
||||
packet->from = *from;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1321,7 +1339,7 @@ static qboolean NET_LagPacket( qboolean newdata, netsrc_t sock, netadr_t *from,
|
||||
|
||||
// delivery packet from fake lag queue
|
||||
memcpy( data, pPacket->data, pPacket->size );
|
||||
memcpy( &net_from, &pPacket->from, sizeof( netadr_t ));
|
||||
net_from = pPacket->from;
|
||||
*length = pPacket->size;
|
||||
|
||||
if( pPacket->data )
|
||||
@@ -1339,28 +1357,42 @@ NET_GetLong
|
||||
receive long packet from network
|
||||
==================
|
||||
*/
|
||||
static qboolean NET_GetLong( byte *pData, int size, size_t *outSize, int splitsize )
|
||||
static qboolean NET_GetLong( byte *pData, int size, size_t *outSize, int splitsize, connprotocol_t proto )
|
||||
{
|
||||
int i, sequence_number, offset;
|
||||
SPLITPACKET *pHeader = (SPLITPACKET *)pData;
|
||||
int packet_number;
|
||||
int packet_count;
|
||||
short packet_id;
|
||||
int body_size = splitsize - sizeof( SPLITPACKET );
|
||||
size_t header_size = proto == PROTO_GOLDSRC ? sizeof( SPLITPACKETGS ) : sizeof( SPLITPACKET );
|
||||
int body_size = splitsize - header_size;
|
||||
|
||||
if( body_size < 0 )
|
||||
return false;
|
||||
|
||||
if( size < sizeof( SPLITPACKET ))
|
||||
if( size < header_size )
|
||||
{
|
||||
Con_Printf( S_ERROR "invalid split packet length %i\n", size );
|
||||
return false;
|
||||
}
|
||||
|
||||
sequence_number = pHeader->sequence_number;
|
||||
packet_id = pHeader->packet_id;
|
||||
packet_count = ( packet_id & 0xFF );
|
||||
packet_number = ( packet_id >> 8 );
|
||||
if( proto == PROTO_GOLDSRC )
|
||||
{
|
||||
SPLITPACKETGS *pHeader = (SPLITPACKETGS *)pData;
|
||||
|
||||
sequence_number = pHeader->sequence_number;
|
||||
packet_id = pHeader->packet_id;
|
||||
packet_count = ( packet_id & 0xF );
|
||||
packet_number = ( packet_id >> 4 );
|
||||
}
|
||||
else
|
||||
{
|
||||
SPLITPACKET *pHeader = (SPLITPACKET *)pData;
|
||||
|
||||
sequence_number = pHeader->sequence_number;
|
||||
packet_id = pHeader->packet_id;
|
||||
packet_count = ( packet_id & 0xFF );
|
||||
packet_number = ( packet_id >> 8 );
|
||||
}
|
||||
|
||||
if( packet_number >= NET_MAX_FRAGMENTS || packet_count > NET_MAX_FRAGMENTS )
|
||||
{
|
||||
@@ -1382,7 +1414,7 @@ static qboolean NET_GetLong( byte *pData, int size, size_t *outSize, int splitsi
|
||||
Con_Printf( "<-- Split packet restart %i count %i seq\n", net.split.split_count, sequence_number );
|
||||
}
|
||||
|
||||
size -= sizeof( SPLITPACKET );
|
||||
size -= header_size;
|
||||
|
||||
if( net.split_flags[packet_number] != sequence_number )
|
||||
{
|
||||
@@ -1401,7 +1433,7 @@ static qboolean NET_GetLong( byte *pData, int size, size_t *outSize, int splitsi
|
||||
}
|
||||
|
||||
offset = (packet_number * body_size);
|
||||
memcpy( net.split.buffer + offset, pData + sizeof( SPLITPACKET ), size );
|
||||
memcpy( net.split.buffer + offset, pData + header_size, size );
|
||||
|
||||
// have we received all of the pieces to the packet?
|
||||
if( net.split.split_count <= 0 )
|
||||
@@ -1464,13 +1496,15 @@ static qboolean NET_QueuePacket( netsrc_t sock, netadr_t *from, byte *data, size
|
||||
memcpy( data, buf, ret );
|
||||
*length = ret;
|
||||
#if !XASH_DEDICATED
|
||||
if( CL_LegacyMode( ))
|
||||
return NET_LagPacket( true, sock, from, length, data );
|
||||
|
||||
// check for split message
|
||||
if( sock == NS_CLIENT && *(int *)data == NET_HEADER_SPLITPACKET )
|
||||
{
|
||||
return NET_GetLong( data, ret, length, CL_GetSplitSize( ));
|
||||
connprotocol_t proto = CL_Protocol();
|
||||
|
||||
if( proto == PROTO_LEGACY )
|
||||
return NET_LagPacket( true, sock, from, length, data );
|
||||
|
||||
// check for split message
|
||||
if( sock == NS_CLIENT && *(int *)data == NET_HEADER_SPLITPACKET )
|
||||
return NET_GetLong( data, ret, length, CL_GetSplitSize( ), proto );
|
||||
}
|
||||
#endif
|
||||
// lag the packet, if needed
|
||||
@@ -1735,7 +1769,7 @@ static int NET_IPSocket( const char *net_iface, int port, int family )
|
||||
|
||||
if( COM_CheckStringEmpty( net_iface ) && Q_stricmp( net_iface, "localhost" ))
|
||||
NET_StringToSockaddr( net_iface, &addr, false, AF_INET6 );
|
||||
else memcpy(((struct sockaddr_in6 *)&addr)->sin6_addr.s6_addr, &in6addr_any, sizeof( struct in6_addr ));
|
||||
else ((struct sockaddr_in6 *)&addr)->sin6_addr = in6addr_any;
|
||||
|
||||
if( port == PORT_ANY ) ((struct sockaddr_in6 *)&addr)->sin6_port = 0;
|
||||
else ((struct sockaddr_in6 *)&addr)->sin6_port = htons((short)port);
|
||||
@@ -2068,7 +2102,7 @@ NET_ClearLagData
|
||||
clear fakelag list
|
||||
====================
|
||||
*/
|
||||
void NET_ClearLagData( qboolean bClient, qboolean bServer )
|
||||
static void NET_ClearLagData( qboolean bClient, qboolean bServer )
|
||||
{
|
||||
if( bClient ) NET_ClearLaggedList( &net.lagdata[NS_CLIENT] );
|
||||
if( bServer ) NET_ClearLaggedList( &net.lagdata[NS_SERVER] );
|
||||
@@ -2094,6 +2128,7 @@ void NET_Init( void )
|
||||
Cvar_RegisterVariable( &net_clientport );
|
||||
Cvar_RegisterVariable( &net_fakelag );
|
||||
Cvar_RegisterVariable( &net_fakeloss );
|
||||
Cvar_RegisterVariable( &net_resolve_debug );
|
||||
|
||||
Q_snprintf( cmd, sizeof( cmd ), "%i", PORT_SERVER );
|
||||
Cvar_FullSet( "hostport", cmd, FCVAR_READ_ONLY );
|
||||
@@ -2167,6 +2202,11 @@ void NET_Shutdown( void )
|
||||
NET_ClearLagData( true, true );
|
||||
|
||||
NET_Config( false, false );
|
||||
|
||||
#ifdef CAN_ASYNC_NS_RESOLVE
|
||||
NET_DeleteCriticalSections();
|
||||
#endif
|
||||
|
||||
#if XASH_WIN32
|
||||
WSACleanup();
|
||||
#endif
|
||||
@@ -2282,7 +2322,7 @@ static void HTTP_FreeFile( httpfile_t *file, qboolean error )
|
||||
|
||||
file->socket = -1;
|
||||
|
||||
Q_snprintf( incname, 256, "downloaded/%s.incomplete", file->path );
|
||||
Q_snprintf( incname, sizeof( incname ), DEFAULT_DOWNLOADED_DIRECTORY "%s.incomplete", file->path );
|
||||
if( error )
|
||||
{
|
||||
// Switch to next fastdl server if present
|
||||
@@ -2308,7 +2348,7 @@ static void HTTP_FreeFile( httpfile_t *file, qboolean error )
|
||||
// Success, rename and process file
|
||||
char name[256];
|
||||
|
||||
Q_snprintf( name, 256, "downloaded/%s", file->path );
|
||||
Q_snprintf( name, sizeof( name ), DEFAULT_DOWNLOADED_DIRECTORY "%s", file->path );
|
||||
FS_Rename( incname, name );
|
||||
|
||||
if( file->process )
|
||||
@@ -2527,7 +2567,7 @@ void HTTP_Run( void )
|
||||
}
|
||||
|
||||
Con_Reportf( "HTTP: Starting download %s from %s\n", curfile->path, curfile->server->host );
|
||||
Q_snprintf( name, sizeof( name ), "downloaded/%s.incomplete", curfile->path );
|
||||
Q_snprintf( name, sizeof( name ), DEFAULT_DOWNLOADED_DIRECTORY "%s.incomplete", curfile->path );
|
||||
|
||||
curfile->file = FS_Open( name, "wb", true );
|
||||
|
||||
|
||||
@@ -66,7 +66,7 @@ qboolean NET_IsReservedAdr( netadr_t a );
|
||||
qboolean NET_CompareClassBAdr( const netadr_t a, const netadr_t b );
|
||||
qboolean NET_StringToAdr( const char *string, netadr_t *adr );
|
||||
qboolean NET_StringToFilterAdr( const char *s, netadr_t *adr, uint *prefixlen );
|
||||
net_gai_state_t NET_StringToAdrNB( const char *string, netadr_t *adr );
|
||||
net_gai_state_t NET_StringToAdrNB( const char *string, netadr_t *adr, qboolean v6only );
|
||||
int NET_CompareAdrSort( const void *_a, const void *_b );
|
||||
qboolean NET_CompareAdr( const netadr_t a, const netadr_t b );
|
||||
qboolean NET_CompareBaseAdr( const netadr_t a, const netadr_t b );
|
||||
@@ -74,12 +74,10 @@ qboolean NET_CompareAdrByMask( const netadr_t a, const netadr_t b, uint prefixle
|
||||
qboolean NET_GetPacket( netsrc_t sock, netadr_t *from, byte *data, size_t *length );
|
||||
void NET_SendPacket( netsrc_t sock, size_t length, const void *data, netadr_t to );
|
||||
void NET_SendPacketEx( netsrc_t sock, size_t length, const void *data, netadr_t to, size_t splitsize );
|
||||
void NET_ClearLagData( qboolean bClient, qboolean bServer );
|
||||
void NET_IP6BytesToNetadr( netadr_t *adr, const uint8_t *ip6 );
|
||||
void NET_NetadrToIP6Bytes( uint8_t *ip6, const netadr_t *adr );
|
||||
|
||||
#if !XASH_DEDICATED
|
||||
qboolean CL_LegacyMode( void );
|
||||
int CL_GetSplitSize( void );
|
||||
#endif
|
||||
|
||||
|
||||
+16
-4
@@ -184,13 +184,13 @@ typedef struct fragbuf_s
|
||||
struct fragbuf_s *next; // next buffer in chain
|
||||
int bufferid; // id of this buffer
|
||||
sizebuf_t frag_message; // message buffer where raw data is stored
|
||||
byte *frag_message_buf; // the actual data sits here
|
||||
qboolean isfile; // is this a file buffer?
|
||||
qboolean isbuffer; // is this file buffer from memory ( custom decal, etc. ).
|
||||
qboolean iscompressed; // is compressed file, we should using filename.ztmp
|
||||
char filename[MAX_OSPATH]; // name of the file to save out on remote host
|
||||
int foffset; // offset in file from which to read data
|
||||
int size; // size of data to read at that offset
|
||||
byte frag_message_buf[]; // the actual data sits here (flexible)
|
||||
} fragbuf_t;
|
||||
|
||||
// Waiting list of fragbuf chains
|
||||
@@ -208,6 +208,14 @@ typedef enum fragsize_e
|
||||
FRAGSIZE_UNRELIABLE
|
||||
} fragsize_t;
|
||||
|
||||
typedef enum netchan_flags_e
|
||||
{
|
||||
NETCHAN_USE_LEGACY_SPLIT = BIT( 0 ),
|
||||
NETCHAN_USE_MUNGE = BIT( 1 ),
|
||||
NETCHAN_USE_BZIP2 = BIT( 2 ),
|
||||
NETCHAN_GOLDSRC = BIT( 3 ),
|
||||
} netchan_flags_t;
|
||||
|
||||
// Network Connection Channel
|
||||
typedef struct netchan_s
|
||||
{
|
||||
@@ -270,10 +278,14 @@ typedef struct netchan_s
|
||||
// added for net_speeds
|
||||
size_t total_sended;
|
||||
size_t total_received;
|
||||
qboolean split;
|
||||
unsigned int maxpacket;
|
||||
unsigned int splitid;
|
||||
netsplit_t netsplit;
|
||||
netsplit_t netsplit;
|
||||
|
||||
qboolean split;
|
||||
qboolean use_munge;
|
||||
qboolean use_bz2;
|
||||
qboolean gs_netchan;
|
||||
} netchan_t;
|
||||
|
||||
extern netadr_t net_from;
|
||||
@@ -287,7 +299,7 @@ extern int net_drop;
|
||||
|
||||
void Netchan_Init( void );
|
||||
void Netchan_Shutdown( void );
|
||||
void Netchan_Setup( netsrc_t sock, netchan_t *chan, netadr_t adr, int qport, void *client, int (*pfnBlockSize)(void *, fragsize_t mode ) );
|
||||
void Netchan_Setup( netsrc_t sock, netchan_t *chan, netadr_t adr, int qport, void *client, int (*pfnBlockSize)(void *, fragsize_t mode ), uint flags );
|
||||
void Netchan_CreateFileFragmentsFromBuffer( netchan_t *chan, const char *filename, byte *pbuf, int size );
|
||||
qboolean Netchan_CopyNormalFragments( netchan_t *chan, sizebuf_t *msg, size_t *length );
|
||||
qboolean Netchan_CopyFileFragments( netchan_t *chan, sizebuf_t *msg );
|
||||
|
||||
+14
-14
@@ -186,7 +186,7 @@ hull_t *PM_HullForBsp( physent_t *pe, playermove_t *pmove, float *offset )
|
||||
Assert( hull != NULL );
|
||||
|
||||
// calculate an offset value to center the origin
|
||||
VectorSubtract( hull->clip_mins, pmove->player_mins[pmove->usehull], offset );
|
||||
VectorSubtract( hull->clip_mins, host.player_mins[pmove->usehull], offset );
|
||||
VectorAdd( offset, pe->origin, offset );
|
||||
|
||||
return hull;
|
||||
@@ -203,7 +203,7 @@ static hull_t *PM_HullForStudio( physent_t *pe, playermove_t *pmove, int *numhit
|
||||
{
|
||||
vec3_t size;
|
||||
|
||||
VectorSubtract( pmove->player_maxs[pmove->usehull], pmove->player_mins[pmove->usehull], size );
|
||||
VectorSubtract( host.player_maxs[pmove->usehull], host.player_mins[pmove->usehull], size );
|
||||
VectorScale( size, 0.5f, size );
|
||||
|
||||
return Mod_HullForStudio( pe->studiomodel, pe->frame, pe->sequence, pe->angles, pe->origin, size, pe->controller, pe->blending, numhitboxes, NULL );
|
||||
@@ -379,8 +379,8 @@ pmtrace_t PM_PlayerTraceExt( playermove_t *pmove, vec3_t start, vec3_t end, int
|
||||
|
||||
if( pe->solid == SOLID_CUSTOM )
|
||||
{
|
||||
VectorCopy( pmove->player_mins[pmove->usehull], mins );
|
||||
VectorCopy( pmove->player_maxs[pmove->usehull], maxs );
|
||||
VectorCopy( host.player_mins[pmove->usehull], mins );
|
||||
VectorCopy( host.player_maxs[pmove->usehull], maxs );
|
||||
VectorClear( offset );
|
||||
}
|
||||
else if( pe->model )
|
||||
@@ -401,8 +401,8 @@ pmtrace_t PM_PlayerTraceExt( playermove_t *pmove, vec3_t start, vec3_t end, int
|
||||
}
|
||||
else
|
||||
{
|
||||
VectorSubtract( pe->mins, pmove->player_maxs[pmove->usehull], mins );
|
||||
VectorSubtract( pe->maxs, pmove->player_mins[pmove->usehull], maxs );
|
||||
VectorSubtract( pe->mins, host.player_maxs[pmove->usehull], mins );
|
||||
VectorSubtract( pe->maxs, host.player_mins[pmove->usehull], maxs );
|
||||
|
||||
hull = PM_HullForBox( mins, maxs );
|
||||
VectorCopy( pe->origin, offset );
|
||||
@@ -410,8 +410,8 @@ pmtrace_t PM_PlayerTraceExt( playermove_t *pmove, vec3_t start, vec3_t end, int
|
||||
}
|
||||
else
|
||||
{
|
||||
VectorSubtract( pe->mins, pmove->player_maxs[pmove->usehull], mins );
|
||||
VectorSubtract( pe->maxs, pmove->player_mins[pmove->usehull], maxs );
|
||||
VectorSubtract( pe->mins, host.player_maxs[pmove->usehull], mins );
|
||||
VectorSubtract( pe->maxs, host.player_mins[pmove->usehull], maxs );
|
||||
|
||||
hull = PM_HullForBox( mins, maxs );
|
||||
VectorCopy( pe->origin, offset );
|
||||
@@ -442,7 +442,7 @@ pmtrace_t PM_PlayerTraceExt( playermove_t *pmove, vec3_t start, vec3_t end, int
|
||||
|
||||
if( transform_bbox )
|
||||
{
|
||||
World_TransformAABB( matrix, pmove->player_mins[pmove->usehull], pmove->player_maxs[pmove->usehull], mins, maxs );
|
||||
World_TransformAABB( matrix, host.player_mins[pmove->usehull], host.player_maxs[pmove->usehull], mins, maxs );
|
||||
VectorSubtract( hull->clip_mins, mins, offset ); // calc new local offset
|
||||
|
||||
for( j = 0; j < 3; j++ )
|
||||
@@ -569,8 +569,8 @@ int PM_TestPlayerPosition( playermove_t *pmove, vec3_t pos, pmtrace_t *ptrace, p
|
||||
|
||||
if( pe->solid == SOLID_CUSTOM )
|
||||
{
|
||||
VectorCopy( pmove->player_mins[pmove->usehull], mins );
|
||||
VectorCopy( pmove->player_maxs[pmove->usehull], maxs );
|
||||
VectorCopy( host.player_mins[pmove->usehull], mins );
|
||||
VectorCopy( host.player_maxs[pmove->usehull], maxs );
|
||||
VectorClear( offset );
|
||||
}
|
||||
else if( pe->model )
|
||||
@@ -584,8 +584,8 @@ int PM_TestPlayerPosition( playermove_t *pmove, vec3_t pos, pmtrace_t *ptrace, p
|
||||
}
|
||||
else
|
||||
{
|
||||
VectorSubtract( pe->mins, pmove->player_maxs[pmove->usehull], mins );
|
||||
VectorSubtract( pe->maxs, pmove->player_mins[pmove->usehull], maxs );
|
||||
VectorSubtract( pe->mins, host.player_maxs[pmove->usehull], mins );
|
||||
VectorSubtract( pe->maxs, host.player_mins[pmove->usehull], maxs );
|
||||
|
||||
hull = PM_HullForBox( mins, maxs );
|
||||
VectorCopy( pe->origin, offset );
|
||||
@@ -611,7 +611,7 @@ int PM_TestPlayerPosition( playermove_t *pmove, vec3_t pos, pmtrace_t *ptrace, p
|
||||
|
||||
if( transform_bbox )
|
||||
{
|
||||
World_TransformAABB( matrix, pmove->player_mins[pmove->usehull], pmove->player_maxs[pmove->usehull], mins, maxs );
|
||||
World_TransformAABB( matrix, host.player_mins[pmove->usehull], host.player_maxs[pmove->usehull], mins, maxs );
|
||||
VectorSubtract( hull->clip_mins, mins, offset ); // calc new local offset
|
||||
|
||||
for( j = 0; j < 3; j++ )
|
||||
|
||||
@@ -73,7 +73,7 @@ GNU General Public License for more details.
|
||||
#define svc_director 51 // <variable sized>
|
||||
#define svc_voiceinit 52 // <see code>
|
||||
#define svc_voicedata 53 // [byte][short][...]
|
||||
#define svc_deltapacketbones 54 // [short][byte][...]
|
||||
// reserved
|
||||
// reserved
|
||||
#define svc_resourcelocation 56 // [string]
|
||||
#define svc_querycvarvalue 57 // [string]
|
||||
@@ -320,8 +320,7 @@ extern const char *clc_strings[clc_lastmsg+1];
|
||||
#define MS_SCAN_REQUEST "1\xFF" "0.0.0.0:0\0" // TODO: implement IP filter
|
||||
|
||||
// GoldSrc protocol definitions
|
||||
#define PROTOCOL_GOLDSRC_VERSION_REAL 48
|
||||
#define PROTOCOL_GOLDSRC_VERSION (PROTOCOL_GOLDSRC_VERSION_REAL | (BIT( 7 ))) // should be 48, only to differentiate it from PROTOCOL_LEGACY_VERSION
|
||||
#define PROTOCOL_GOLDSRC_VERSION 48
|
||||
|
||||
#define svc_goldsrc_version svc_changing
|
||||
#define svc_goldsrc_serverinfo svc_serverdata
|
||||
@@ -349,6 +348,7 @@ extern const char *clc_strings[clc_lastmsg+1];
|
||||
#define S2C_CHALLENGE "A00000000"
|
||||
#define S2C_CONNECTION "B"
|
||||
|
||||
#define MAX_GOLDSRC_MODEL_BITS 10
|
||||
#define MAX_GOLDSRC_RESOURCE_BITS 12
|
||||
#define MAX_GOLDSRC_ENTITY_BITS 11
|
||||
// #define MAX_GOLDSRC_EDICTS BIT( MAX_ENTITY_BITS )
|
||||
|
||||
@@ -30,7 +30,7 @@ static void Sound_Reset( void )
|
||||
sound.size = 0;
|
||||
}
|
||||
|
||||
static wavdata_t *SoundPack( void )
|
||||
static MALLOC_LIKE( FS_FreeSound, 1 ) wavdata_t *SoundPack( void )
|
||||
{
|
||||
wavdata_t *pack = Mem_Calloc( host.soundpool, sizeof( wavdata_t ));
|
||||
|
||||
|
||||
@@ -25,8 +25,7 @@ typedef struct did3v2_header_s
|
||||
uint8_t flags;
|
||||
uint32_t length; // size of extended header, padding and frames
|
||||
} did3v2_header_t;
|
||||
STATIC_ASSERT( sizeof( did3v2_header_t ) == 10,
|
||||
"invalid did3v2_header_t size" );
|
||||
STATIC_CHECK_SIZEOF( did3v2_header_t, 10, 10 );
|
||||
|
||||
typedef struct did3v2_extended_header_s
|
||||
{
|
||||
@@ -34,8 +33,7 @@ typedef struct did3v2_extended_header_s
|
||||
uint8_t flags_length;
|
||||
uint8_t flags[1];
|
||||
} did3v2_extended_header_t;
|
||||
STATIC_ASSERT( sizeof( did3v2_extended_header_t ) == 6,
|
||||
"invalid did3v2_extended_header_t size" );
|
||||
STATIC_CHECK_SIZEOF( did3v2_extended_header_t, 6, 6 );
|
||||
|
||||
typedef struct did3v2_frame_s
|
||||
{
|
||||
@@ -43,8 +41,7 @@ typedef struct did3v2_frame_s
|
||||
uint32_t length;
|
||||
uint8_t flags[2];
|
||||
} did3v2_frame_t;
|
||||
STATIC_ASSERT( sizeof( did3v2_frame_t ) == 10,
|
||||
"invalid did3v2_frame_t size" );
|
||||
STATIC_CHECK_SIZEOF( did3v2_frame_t, 10, 10 );
|
||||
#pragma pack( pop )
|
||||
|
||||
typedef enum did3v2_header_flags_e
|
||||
|
||||
+233
-304
@@ -90,8 +90,8 @@ static byte *Sound_Copy( size_t size )
|
||||
{
|
||||
byte *out;
|
||||
|
||||
out = Mem_Malloc( host.soundpool, size );
|
||||
memcpy( out, sound.tempbuffer, size );
|
||||
out = Mem_Realloc( host.soundpool, sound.tempbuffer, size );
|
||||
sound.tempbuffer = NULL;
|
||||
|
||||
return out;
|
||||
}
|
||||
@@ -133,346 +133,275 @@ uint GAME_EXPORT Sound_GetApproxWavePlayLen( const char *filepath )
|
||||
return msecs;
|
||||
}
|
||||
|
||||
static qboolean Sound_ConvertNoResample( wavdata_t *sc, int inwidth, int outwidth, int outcount )
|
||||
#define SOUND_FORMATCONVERT_BOILERPLATE( resamplemacro ) \
|
||||
if( inwidth == 1 ) \
|
||||
{ \
|
||||
const int8_t *data = (const int8_t *)sc->buffer; \
|
||||
if( outwidth == 1 ) \
|
||||
{ \
|
||||
int8_t *outdata = (int8_t *)sound.tempbuffer; \
|
||||
resamplemacro( 1 ) \
|
||||
} \
|
||||
else if( outwidth == 2 ) \
|
||||
{ \
|
||||
int16_t *outdata = (int16_t *)sound.tempbuffer; \
|
||||
resamplemacro( 256 ) \
|
||||
} \
|
||||
else \
|
||||
return false; \
|
||||
} \
|
||||
else if( inwidth == 2 ) \
|
||||
{ \
|
||||
const int16_t *data = (const int16_t *)sc->buffer; \
|
||||
if( outwidth == 1 ) \
|
||||
{ \
|
||||
int8_t *outdata = (int8_t *)sound.tempbuffer; \
|
||||
resamplemacro( 1 / 256.0 ) \
|
||||
} \
|
||||
else if( outwidth == 2 ) \
|
||||
{ \
|
||||
int16_t *outdata = (int16_t *)sound.tempbuffer; \
|
||||
resamplemacro( 1 ) \
|
||||
} \
|
||||
else \
|
||||
return false; \
|
||||
} \
|
||||
else \
|
||||
return false; \
|
||||
|
||||
|
||||
#define SOUND_CONVERTNORESAMPLE_BOILERPLATE( multiplier ) \
|
||||
if( inchannels == 1 ) \
|
||||
{ \
|
||||
if( outchannels == 1 ) \
|
||||
{ \
|
||||
for( i = 0; i < outcount * outchannels; i++ ) \
|
||||
outdata[i] = data[i] * ( multiplier ); \
|
||||
} \
|
||||
else if( outchannels == 2 ) \
|
||||
{ \
|
||||
for( i = 0; i < outcount; i++ ) \
|
||||
{ \
|
||||
outdata[i * 2 + 0] = data[i] * ( multiplier ); \
|
||||
outdata[i * 2 + 1] = data[i] * ( multiplier ); \
|
||||
} \
|
||||
} \
|
||||
else \
|
||||
return false; \
|
||||
} \
|
||||
else if( inchannels == 2 ) \
|
||||
{ \
|
||||
if( outchannels == 1 ) \
|
||||
{ \
|
||||
for( i = 0; i < outcount; i++ ) \
|
||||
outdata[i] = ( data[i * 2 + 0] + data[i * 2 + 1] ) * ( multiplier ) / 2; \
|
||||
} \
|
||||
else if( outchannels == 2 ) \
|
||||
{ \
|
||||
for( i = 0; i < outcount * outchannels; i++ ) \
|
||||
outdata[i] = data[i] * ( multiplier ); \
|
||||
} \
|
||||
else \
|
||||
return false; \
|
||||
} \
|
||||
else \
|
||||
return false; \
|
||||
|
||||
#define SOUND_CONVERTDOWNSAMPLE_BOILERPLATE( multiplier ) \
|
||||
if( inchannels == 1 ) \
|
||||
{ \
|
||||
if( outchannels == 1 ) \
|
||||
{ \
|
||||
for( i = 0; i < outcount; i++ ) \
|
||||
{ \
|
||||
double j = stepscale * i; \
|
||||
outdata[i] = data[(int)j] * ( multiplier ); \
|
||||
} \
|
||||
} \
|
||||
else if( outchannels == 2 ) \
|
||||
{ \
|
||||
for( i = 0; i < outcount; i++ ) \
|
||||
{ \
|
||||
double j = stepscale * i;\
|
||||
outdata[i * 2 + 0] = data[(int)j] * ( multiplier ); \
|
||||
outdata[i * 2 + 1] = data[(int)j] * ( multiplier ); \
|
||||
} \
|
||||
} \
|
||||
else \
|
||||
return false; \
|
||||
} \
|
||||
else if( inchannels == 2 ) \
|
||||
{ \
|
||||
if( outchannels == 1 ) \
|
||||
{ \
|
||||
for( i = 0; i < outcount; i++ ) \
|
||||
{ \
|
||||
double j = stepscale * i; \
|
||||
outdata[i] = ( data[((int)j) * 2 + 0] + data[((int)j) * 2 + 1] ) * ( multiplier ) / 2; \
|
||||
} \
|
||||
} \
|
||||
else if( outchannels == 2 ) \
|
||||
{ \
|
||||
for( i = 0; i < outcount; i++ ) \
|
||||
{ \
|
||||
double j = stepscale * i; \
|
||||
outdata[i * 2 + 0] = data[((int)j) * 2 + 0] * ( multiplier ); \
|
||||
outdata[i * 2 + 1] = data[((int)j) * 2 + 1] * ( multiplier ); \
|
||||
} \
|
||||
} \
|
||||
else \
|
||||
return false; \
|
||||
} \
|
||||
else \
|
||||
return false; \
|
||||
|
||||
|
||||
#define SOUND_CONVERTUPSAMPLE_BOILERPLATE( multiplier ) \
|
||||
if( inchannels == 1 ) \
|
||||
{ \
|
||||
if( outchannels == 1 ) \
|
||||
{ \
|
||||
for( i = 0; i < outcount; i++ ) \
|
||||
{ \
|
||||
double j = stepscale * i; \
|
||||
outdata[i] = data[(int)j] * ( multiplier ); \
|
||||
if( j != (int)j && j < incount ) \
|
||||
{ \
|
||||
double frac = ( j - (int)j ) * ( multiplier ); \
|
||||
outdata[i] += (data[(int)j+1] - data[(int)j]) * frac; \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
else if( outchannels == 2 ) \
|
||||
{ \
|
||||
for( i = 0; i < outcount; i++ ) \
|
||||
{ \
|
||||
double j = stepscale * i; \
|
||||
outdata[i * 2 + 0] = data[(int)j] * ( multiplier ); \
|
||||
if( j != (int)j && j < incount ) \
|
||||
{ \
|
||||
double frac = ( j - (int)j ) * ( multiplier ); \
|
||||
outdata[i * 2 + 0] += (data[(int)j+1] - data[(int)j]) * frac; \
|
||||
} \
|
||||
outdata[i * 2 + 1] = outdata[i * 2 + 0]; \
|
||||
} \
|
||||
} \
|
||||
else \
|
||||
return false; \
|
||||
} \
|
||||
else if( inchannels == 2 ) \
|
||||
{ \
|
||||
if( outchannels == 1 ) \
|
||||
{ \
|
||||
for( i = 0; i < outcount; i++ ) \
|
||||
{ \
|
||||
double j = stepscale * i; \
|
||||
outdata[i] = ( data[((int)j) * 2 + 0] + data[((int)j) * 2 + 1] ) * ( multiplier ) / 2; \
|
||||
if( j != (int)j && j < incount ) \
|
||||
{ \
|
||||
double frac = ( j - (int)j ) * ( multiplier ) / 2; \
|
||||
outdata[i] += (data[((int)j + 1 ) * 2 + 0] - data[((int)j) * 2 + 0]) * frac; \
|
||||
outdata[i] += (data[((int)j + 1 ) * 2 + 1] - data[((int)j) * 2 + 1]) * frac; \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
else if( outchannels == 2 ) \
|
||||
{ \
|
||||
for( i = 0; i < outcount; i++ ) \
|
||||
{ \
|
||||
double j = stepscale * i; \
|
||||
outdata[i*2+0] = data[((int)j)*2+0] * ( multiplier ); \
|
||||
outdata[i*2+1] = data[((int)j)*2+1] * ( multiplier ); \
|
||||
if( j != (int)j && j < incount ) \
|
||||
{ \
|
||||
double frac = ( j - (int)j ) * ( multiplier ); \
|
||||
outdata[i*2+0] += (data[((int)j+1)*2+0] - data[((int)j)*2+0]) * frac; \
|
||||
outdata[i*2+1] += (data[((int)j+1)*2+1] - data[((int)j)*2+1]) * frac; \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
else \
|
||||
return false; \
|
||||
} \
|
||||
else \
|
||||
return false; \
|
||||
|
||||
static qboolean Sound_ConvertNoResample( wavdata_t *sc, int inwidth, int inchannels, int outwidth, int outchannels, int outcount )
|
||||
{
|
||||
size_t i;
|
||||
|
||||
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;
|
||||
return true;
|
||||
}
|
||||
// I could write a generic case here but I also want to make it easier for compiler
|
||||
// to unroll these for-loops
|
||||
|
||||
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;
|
||||
return true;
|
||||
}
|
||||
SOUND_FORMATCONVERT_BOILERPLATE( SOUND_CONVERTNORESAMPLE_BOILERPLATE )
|
||||
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static qboolean Sound_ConvertDownsample( wavdata_t *sc, int inwidth, int outwidth, int outcount, double stepscale )
|
||||
static qboolean Sound_ConvertDownsample( wavdata_t *sc, int inwidth, int inchannels, int outwidth, int outchannels, int outcount, double stepscale )
|
||||
{
|
||||
size_t i;
|
||||
double j;
|
||||
|
||||
if( inwidth == 1 && outwidth == 1 )
|
||||
{
|
||||
int8_t *data = (int8_t *)sc->buffer;
|
||||
SOUND_FORMATCONVERT_BOILERPLATE( SOUND_CONVERTDOWNSAMPLE_BOILERPLATE )
|
||||
|
||||
if( outwidth == 1 )
|
||||
{
|
||||
int8_t *outdata = (int8_t *)sound.tempbuffer;
|
||||
|
||||
if( sc->channels == 2 )
|
||||
{
|
||||
for( i = 0; i < outcount; i++ )
|
||||
{
|
||||
j = stepscale * i;
|
||||
outdata[i*2+0] = data[((int)j)*2+0];
|
||||
outdata[i*2+1] = data[((int)j)*2+1];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for( i = 0; i < outcount; i++ )
|
||||
{
|
||||
j = stepscale * i;
|
||||
outdata[i] = data[(int)j];
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if( outwidth == 2 )
|
||||
{
|
||||
int16_t *outdata = (int16_t *)sound.tempbuffer;
|
||||
|
||||
if( sc->channels == 2 )
|
||||
{
|
||||
for( i = 0; i < outcount; i++ )
|
||||
{
|
||||
j = stepscale * i;
|
||||
outdata[i*2+0] = data[((int)j)*2+0] * 256;
|
||||
outdata[i*2+1] = data[((int)j)*2+1] * 256;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for( i = 0; i < outcount; i++ )
|
||||
{
|
||||
j = stepscale * i;
|
||||
outdata[i] = data[(int)j] * 256;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if( inwidth == 2 )
|
||||
{
|
||||
int16_t *data = (int16_t *)sc->buffer;
|
||||
|
||||
if( outwidth == 1 )
|
||||
{
|
||||
int8_t *outdata = (int8_t *)sound.tempbuffer;
|
||||
|
||||
if( sc->channels == 2 )
|
||||
{
|
||||
for( i = 0; i < outcount; i++ )
|
||||
{
|
||||
j = stepscale * i;
|
||||
outdata[i*2+0] = data[((int)j)*2+0] / 256;
|
||||
outdata[i*2+1] = data[((int)j)*2+1] / 256;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for( i = 0; i < outcount; i++ )
|
||||
{
|
||||
j = stepscale * i;
|
||||
outdata[i] = data[(int)j] / 256;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if( outwidth == 2 )
|
||||
{
|
||||
int16_t *outdata = (int16_t *)sound.tempbuffer;
|
||||
|
||||
if( sc->channels == 2 )
|
||||
{
|
||||
for( i = 0; i < outcount; i++ )
|
||||
{
|
||||
j = stepscale * i;
|
||||
outdata[i*2+0] = data[((int)j)*2+0];
|
||||
outdata[i*2+1] = data[((int)j)*2+1];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for( i = 0; i < outcount; i++ )
|
||||
{
|
||||
j = stepscale * i;
|
||||
outdata[i] = data[(int)j];
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static qboolean Sound_ConvertUpsample( wavdata_t *sc, int inwidth, int outwidth, int outcount, int incount, double stepscale )
|
||||
static qboolean Sound_ConvertUpsample( wavdata_t *sc, int inwidth, int inchannels, int incount, int outwidth, int outchannels, int outcount, double stepscale )
|
||||
{
|
||||
size_t i;
|
||||
double j;
|
||||
double frac;
|
||||
|
||||
incount--; // to not go past last sample while interpolating
|
||||
|
||||
if( inwidth == 1 )
|
||||
{
|
||||
int8_t *data = (int8_t *)sc->buffer;
|
||||
SOUND_FORMATCONVERT_BOILERPLATE( SOUND_CONVERTUPSAMPLE_BOILERPLATE )
|
||||
|
||||
if( outwidth == 1 )
|
||||
{
|
||||
int8_t *outdata = (int8_t *)sound.tempbuffer;
|
||||
|
||||
if( sc->channels == 2 )
|
||||
{
|
||||
for( i = 0; i < outcount; i++ )
|
||||
{
|
||||
j = stepscale * i;
|
||||
outdata[i*2+0] = data[((int)j)*2+0];
|
||||
outdata[i*2+1] = data[((int)j)*2+1];
|
||||
if( j != (int)j && j < incount )
|
||||
{
|
||||
frac = j - (int)j;
|
||||
outdata[i*2+0] += (data[((int)j+1)*2+0] - data[((int)j)*2+0]) * frac;
|
||||
outdata[i*2+1] += (data[((int)j+1)*2+1] - data[((int)j)*2+1]) * frac;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for( i = 0; i < outcount; i++ )
|
||||
{
|
||||
j = stepscale * i;
|
||||
outdata[i] = data[(int)j];
|
||||
if( j != (int)j && j < incount )
|
||||
{
|
||||
frac = j - (int)j;
|
||||
outdata[i] += (data[(int)j+1] - data[(int)j]) * frac;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if( outwidth == 2 )
|
||||
{
|
||||
int16_t *outdata = (int16_t *)sound.tempbuffer;
|
||||
|
||||
if( sc->channels == 2 )
|
||||
{
|
||||
for( i = 0; i < outcount; i++ )
|
||||
{
|
||||
j = stepscale * i;
|
||||
outdata[i*2+0] = data[((int)j)*2+0] * 256;
|
||||
outdata[i*2+1] = data[((int)j)*2+1] * 256;
|
||||
if( j != (int)j && j < incount )
|
||||
{
|
||||
frac = ( j - (int)j ) * 256;
|
||||
outdata[i*2+0] += (data[((int)j+1)*2+0] - data[((int)j)*2+0]) * frac;
|
||||
outdata[i*2+1] += (data[((int)j+1)*2+1] - data[((int)j)*2+1]) * frac;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for( i = 0; i < outcount; i++ )
|
||||
{
|
||||
j = stepscale * i;
|
||||
outdata[i] = data[(int)j] * 256;
|
||||
if( j != (int)j && j < incount )
|
||||
{
|
||||
frac = ( j - (int)j ) * 256;
|
||||
outdata[i] += (data[(int)j+1] - data[(int)j]) * frac;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if( inwidth == 2 )
|
||||
{
|
||||
int16_t *data = (int16_t *)sc->buffer;
|
||||
|
||||
if( outwidth == 1 )
|
||||
{
|
||||
int8_t *outdata = (int8_t *)sound.tempbuffer;
|
||||
|
||||
if( sc->channels == 2 )
|
||||
{
|
||||
for( i = 0; i < outcount; i++ )
|
||||
{
|
||||
j = stepscale * i;
|
||||
outdata[i*2+0] = data[((int)j)*2+0] / 256;
|
||||
outdata[i*2+1] = data[((int)j)*2+1] / 256;
|
||||
if( j != (int)j && j < incount )
|
||||
{
|
||||
frac = ( j - (int)j ) / 256;
|
||||
outdata[i*2+0] += (data[((int)j+1)*2+0] - data[((int)j)*2+0]) * frac;
|
||||
outdata[i*2+1] += (data[((int)j+1)*2+1] - data[((int)j)*2+1]) * frac;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for( i = 0; i < outcount; i++ )
|
||||
{
|
||||
j = stepscale * i;
|
||||
outdata[i] = data[(int)j] / 256;
|
||||
if( j != (int)j && j < incount )
|
||||
{
|
||||
frac = ( j - (int)j ) / 256;
|
||||
outdata[i] += (data[(int)j+1] - data[(int)j]) * frac;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if( outwidth == 2 )
|
||||
{
|
||||
int16_t *outdata = (int16_t *)sound.tempbuffer;
|
||||
|
||||
if( sc->channels == 2 )
|
||||
{
|
||||
for( i = 0; i < outcount; i++ )
|
||||
{
|
||||
j = stepscale * i;
|
||||
outdata[i*2+0] = data[((int)j)*2+0];
|
||||
outdata[i*2+1] = data[((int)j)*2+1];
|
||||
if( j != (int)j && j < incount )
|
||||
{
|
||||
frac = j - (int)j;
|
||||
outdata[i*2+0] += (data[((int)j+1)*2+0] - data[((int)j)*2+0]) * frac;
|
||||
outdata[i*2+1] += (data[((int)j+1)*2+1] - data[((int)j)*2+1]) * frac;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for( i = 0; i < outcount; i++ )
|
||||
{
|
||||
j = stepscale * i;
|
||||
outdata[i] = data[(int)j];
|
||||
if( j != (int)j && j < incount )
|
||||
{
|
||||
frac = j - (int)j;
|
||||
outdata[i] += (data[(int)j+1] - data[(int)j]) * frac;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
#undef SOUND_FORMATCONVERT_BOILERPLATE
|
||||
#undef SOUND_CONVERTNORESAMPLE_BOILERPLATE
|
||||
#undef SOUND_CONVERTDOWNSAMPLE_BOILERPLATE
|
||||
#undef SOUND_CONVERTUPSAMPLE_BOILERPLATE
|
||||
|
||||
/*
|
||||
================
|
||||
Sound_ResampleInternal
|
||||
|
||||
We need convert sound to signed even if nothing to resample
|
||||
================
|
||||
*/
|
||||
static qboolean Sound_ResampleInternal( wavdata_t *sc, int inrate, int inwidth, int outrate, int outwidth )
|
||||
static qboolean Sound_ResampleInternal( wavdata_t *sc, int outrate, int outwidth, int outchannels )
|
||||
{
|
||||
const size_t oldsize = sc->size;
|
||||
const int inrate = sc->rate;
|
||||
const int inwidth = sc->width;
|
||||
const int inchannels = sc->channels;
|
||||
const int incount = sc->samples;
|
||||
qboolean handled = false;
|
||||
double stepscale;
|
||||
double t1, t2;
|
||||
int outcount, incount = sc->samples;
|
||||
int outcount;
|
||||
|
||||
if( inrate == outrate && inwidth == outwidth )
|
||||
if( inrate == outrate && inwidth == outwidth && inchannels == outchannels )
|
||||
return false;
|
||||
|
||||
t1 = Sys_DoubleTime();
|
||||
|
||||
stepscale = (double)inrate / outrate; // this is usually 0.5, 1, or 2
|
||||
outcount = sc->samples / stepscale;
|
||||
sc->size = outcount * outwidth * sc->channels;
|
||||
sc->size = outcount * outwidth * outchannels;
|
||||
sc->channels = outchannels;
|
||||
|
||||
sc->samples = outcount;
|
||||
if( FBitSet( sc->flags, SOUND_LOOPED ))
|
||||
sc->loopStart = sc->loopStart / stepscale;
|
||||
|
||||
#if 0 && XASH_SDL // slow but somewhat accurate
|
||||
#if 0 && XASH_SDL // slow but somewhat accurate (wasn't updated to channel manipulation!!!)
|
||||
{
|
||||
const SDL_AudioFormat infmt = inwidth == 1 ? AUDIO_S8 : AUDIO_S16;
|
||||
const SDL_AudioFormat outfmt = outwidth == 1 ? AUDIO_S8 : AUDIO_S16;
|
||||
SDL_AudioCVT cvt;
|
||||
|
||||
// SDL_AudioCVT does conversion in place, original buffer is used for it
|
||||
if( SDL_BuildAudioCVT( &cvt, infmt, sc->channels, inrate, outfmt, sc->channels, outrate ) > 0 && cvt.needed )
|
||||
if( SDL_BuildAudioCVT( &cvt, infmt, inchannels, inrate, outfmt, outchannels, outrate ) > 0 && cvt.needed )
|
||||
{
|
||||
sc->buffer = (byte *)Mem_Realloc( host.soundpool, sc->buffer, oldsize * cvt.len_mult );
|
||||
cvt.len = oldsize;
|
||||
@@ -493,23 +422,23 @@ static qboolean Sound_ResampleInternal( wavdata_t *sc, int inrate, int inwidth,
|
||||
sound.tempbuffer = (byte *)Mem_Realloc( host.soundpool, sound.tempbuffer, sc->size );
|
||||
|
||||
if( inrate == outrate ) // no resampling, just copy data
|
||||
handled = Sound_ConvertNoResample( sc, inwidth, outwidth, outcount );
|
||||
handled = Sound_ConvertNoResample( sc, inwidth, inchannels, outwidth, outchannels, outcount );
|
||||
else if( inrate > outrate ) // fast case, usually downsample but is also ok for upsampling
|
||||
handled = Sound_ConvertDownsample( sc, inwidth, outwidth, outcount, stepscale );
|
||||
handled = Sound_ConvertDownsample( sc, inwidth, inchannels, outwidth, outchannels, outcount, stepscale );
|
||||
else // upsample case, w/ interpolation
|
||||
handled = Sound_ConvertUpsample( sc, inwidth, outwidth, outcount, incount, stepscale );
|
||||
handled = Sound_ConvertUpsample( sc, inwidth, inchannels, incount, outwidth, outchannels, outcount, stepscale );
|
||||
|
||||
t2 = Sys_DoubleTime();
|
||||
|
||||
if( handled )
|
||||
{
|
||||
if( t2 - t1 > 0.01f ) // critical, report to mod developer
|
||||
Con_Printf( S_WARN "%s: from [%d bit %d Hz] to [%d bit %d Hz] (took %.3fs)\n", __func__, inwidth * 8, inrate, outwidth * 8, outrate, t2 - t1 );
|
||||
Con_Printf( S_WARN "%s: from [%d bit %d Hz %dch] to [%d bit %d Hz %dch] (took %.3fs)\n", __func__, inwidth * 8, inrate, inchannels, outwidth * 8, outrate, outchannels, t2 - t1 );
|
||||
else
|
||||
Con_Reportf( "%s: from [%d bit %d Hz] to [%d bit %d Hz] (took %.3fs)\n", __func__, inwidth * 8, inrate, outwidth * 8, outrate, t2 - t1 );
|
||||
Con_Reportf( "%s: from [%d bit %d Hz %dch] to [%d bit %d Hz %dch] (took %.3fs)\n", __func__, inwidth * 8, inrate, inchannels, outwidth * 8, outrate, outchannels, t2 - t1 );
|
||||
}
|
||||
else
|
||||
Con_Printf( S_ERROR "%s: unsupported from [%d bit %d Hz] to [%d bit %d Hz]\n", __func__, inwidth * 8, inrate, outwidth * 8, outrate );
|
||||
Con_Printf( S_ERROR "%s: unsupported from [%d bit %d Hz %dch] to [%d bit %d Hz %dch]\n", __func__, inwidth * 8, inrate, inchannels, outwidth * 8, outrate, outchannels );
|
||||
|
||||
sc->rate = outrate;
|
||||
sc->width = outwidth;
|
||||
@@ -517,23 +446,23 @@ static qboolean Sound_ResampleInternal( wavdata_t *sc, int inrate, int inwidth,
|
||||
return handled;
|
||||
}
|
||||
|
||||
qboolean Sound_Process( wavdata_t **wav, int rate, int width, uint flags )
|
||||
qboolean Sound_Process( wavdata_t **wav, int rate, int width, int channels, uint flags )
|
||||
{
|
||||
wavdata_t *snd = *wav;
|
||||
qboolean result = true;
|
||||
|
||||
// check for buffers
|
||||
if( !snd || !snd->buffer )
|
||||
if( unlikely( !snd || !snd->buffer ))
|
||||
return false;
|
||||
|
||||
if( FBitSet( flags, SOUND_RESAMPLE ) && ( width > 0 || rate > 0 ))
|
||||
if( likely( FBitSet( flags, SOUND_RESAMPLE ) && ( width > 0 || rate > 0 || channels > 0 )))
|
||||
{
|
||||
result = Sound_ResampleInternal( snd, snd->rate, snd->width, rate, width );
|
||||
result = Sound_ResampleInternal( snd, rate, width, channels );
|
||||
|
||||
if( result )
|
||||
{
|
||||
Mem_Free( snd->buffer ); // free original image buffer
|
||||
snd->buffer = Sound_Copy( snd->size ); // unzone buffer (don't touch sound.tempbuffer)
|
||||
snd->buffer = Sound_Copy( snd->size ); // unzone buffer
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -241,14 +241,14 @@ qboolean Sound_LoadWAV( const char *name, const byte *buffer, fs_offset_t filesi
|
||||
// get cue chunk
|
||||
FindChunk( name, "cue " );
|
||||
|
||||
if( iff_dataPtr )
|
||||
if( iff_dataPtr && iff_end - iff_dataPtr >= 36 )
|
||||
{
|
||||
iff_dataPtr += 32;
|
||||
sound.loopstart = GetLittleLong();
|
||||
SetBits( sound.flags, SOUND_LOOPED );
|
||||
FindNextChunk( name, "LIST" ); // if the next chunk is a LIST chunk, look for a cue length marker
|
||||
|
||||
if( iff_dataPtr )
|
||||
if( iff_dataPtr && iff_end - iff_dataPtr >= 32 )
|
||||
{
|
||||
if( IsFourCC( iff_dataPtr + 28, "mark" ))
|
||||
{
|
||||
|
||||
+45
-40
@@ -199,20 +199,20 @@ static void Sys_WriteEscapeSequenceForColorcode( int fd, int c )
|
||||
{
|
||||
static const char *q3ToAnsi[ 8 ] =
|
||||
{
|
||||
"\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[1;30m", // COLOR_BLACK
|
||||
"\033[1;31m", // COLOR_RED
|
||||
"\033[1;32m", // COLOR_GREEN
|
||||
"\033[1;33m", // COLOR_YELLOW
|
||||
"\033[1;34m", // COLOR_BLUE
|
||||
"\033[1;36m", // COLOR_CYAN
|
||||
"\033[1;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 write( fd, esc, 7 );
|
||||
}
|
||||
#else
|
||||
static void Sys_WriteEscapeSequenceForColorcode( int fd, int c ) {}
|
||||
@@ -230,13 +230,20 @@ static void Sys_PrintLogfile( const int fd, const char *logtime, const char *msg
|
||||
|
||||
if( p == NULL )
|
||||
{
|
||||
write( fd, msg, Q_strlen( msg ));
|
||||
if( write( fd, msg, Q_strlen( msg )) < 0 )
|
||||
{
|
||||
// don't call engine Msg, might cause recursion
|
||||
fprintf( stderr, "%s: write failed: %s\n", __func__, strerror( errno ));
|
||||
}
|
||||
break;
|
||||
}
|
||||
else if( IsColorString( p ))
|
||||
{
|
||||
if( p != msg )
|
||||
write( fd, msg, p - msg );
|
||||
{
|
||||
if( write( fd, msg, p - msg ) < 0 )
|
||||
fprintf( stderr, "%s: write failed: %s\n", __func__, strerror( errno ));
|
||||
}
|
||||
msg = p + 2;
|
||||
|
||||
if( colorize )
|
||||
@@ -244,7 +251,8 @@ static void Sys_PrintLogfile( const int fd, const char *logtime, const char *msg
|
||||
}
|
||||
else
|
||||
{
|
||||
write( fd, msg, p - msg + 1 );
|
||||
if( write( fd, msg, p - msg + 1 ) < 0 )
|
||||
fprintf( stderr, "%s: write failed: %s\n", __func__, strerror( errno ));
|
||||
msg = p + 1;
|
||||
}
|
||||
}
|
||||
@@ -297,6 +305,7 @@ void Sys_PrintLog( const char *pMsg )
|
||||
const struct tm *crt_tm;
|
||||
char logtime[32] = "";
|
||||
static char lastchar;
|
||||
size_t len;
|
||||
|
||||
time( &crt_time );
|
||||
crt_tm = localtime( &crt_time );
|
||||
@@ -307,10 +316,12 @@ void Sys_PrintLog( const char *pMsg )
|
||||
// spew to stdout
|
||||
Sys_PrintStdout( logtime, pMsg );
|
||||
|
||||
len = Q_strlen( pMsg );
|
||||
|
||||
if( !s_ld.logfile )
|
||||
{
|
||||
// save last char to detect when line was not ended
|
||||
lastchar = pMsg[Q_strlen( pMsg ) - 1];
|
||||
lastchar = len > 0 ? pMsg[len - 1] : 0;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -318,7 +329,7 @@ void Sys_PrintLog( const char *pMsg )
|
||||
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];
|
||||
lastchar = len > 0 ? pMsg[len - 1] : 0;
|
||||
|
||||
Sys_PrintLogfile( s_ld.logfileno, logtime, pMsg, false );
|
||||
Sys_FlushLogfile();
|
||||
@@ -331,6 +342,21 @@ CONSOLE PRINT
|
||||
|
||||
=============================================================================
|
||||
*/
|
||||
static void Con_Printfv( qboolean debug, const char *szFmt, va_list args )
|
||||
{
|
||||
static char buffer[MAX_PRINT_MSG];
|
||||
qboolean add_newline;
|
||||
|
||||
add_newline = Q_vsnprintf( buffer, sizeof( buffer ), szFmt, args ) < 0;
|
||||
|
||||
if( debug && !Q_strcmp( buffer, "0\n" ))
|
||||
return; // hlrally spam
|
||||
|
||||
Sys_Print( buffer );
|
||||
if( add_newline )
|
||||
Sys_Print( "\n" );
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
Con_Printf
|
||||
@@ -339,20 +365,14 @@ Con_Printf
|
||||
*/
|
||||
void GAME_EXPORT Con_Printf( const char *szFmt, ... )
|
||||
{
|
||||
static char buffer[MAX_PRINT_MSG];
|
||||
va_list args;
|
||||
qboolean add_newline;
|
||||
va_list args;
|
||||
|
||||
if( !host.allow_console )
|
||||
return;
|
||||
|
||||
va_start( args, szFmt );
|
||||
add_newline = Q_vsnprintf( buffer, sizeof( buffer ), szFmt, args ) < 0;
|
||||
Con_Printfv( false, szFmt, args );
|
||||
va_end( args );
|
||||
|
||||
Sys_Print( buffer );
|
||||
if( add_newline )
|
||||
Sys_Print( "\n" );
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -363,23 +383,14 @@ Con_DPrintf
|
||||
*/
|
||||
void GAME_EXPORT Con_DPrintf( const char *szFmt, ... )
|
||||
{
|
||||
static char buffer[MAX_PRINT_MSG];
|
||||
va_list args;
|
||||
qboolean add_newline;
|
||||
va_list args;
|
||||
|
||||
if( host_developer.value < DEV_NORMAL )
|
||||
return;
|
||||
|
||||
va_start( args, szFmt );
|
||||
add_newline = Q_vsnprintf( buffer, sizeof( buffer ), szFmt, args ) < 0;
|
||||
Con_Printfv( true, szFmt, args );
|
||||
va_end( args );
|
||||
|
||||
if( buffer[0] == '0' && buffer[1] == '\n' && buffer[2] == '\0' )
|
||||
return; // hlrally spam
|
||||
|
||||
Sys_Print( buffer );
|
||||
if( add_newline )
|
||||
Sys_Print( "\n" );
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -390,20 +401,14 @@ Con_Reportf
|
||||
*/
|
||||
void Con_Reportf( const char *szFmt, ... )
|
||||
{
|
||||
static char buffer[MAX_PRINT_MSG];
|
||||
va_list args;
|
||||
qboolean add_newline;
|
||||
va_list args;
|
||||
|
||||
if( host_developer.value < DEV_EXTENDED )
|
||||
return;
|
||||
|
||||
va_start( args, szFmt );
|
||||
add_newline = Q_vsnprintf( buffer, sizeof( buffer ), szFmt, args ) < 0;
|
||||
Con_Printfv( false, szFmt, args );
|
||||
va_end( args );
|
||||
|
||||
Sys_Print( buffer );
|
||||
if( add_newline )
|
||||
Sys_Print( "\n" );
|
||||
}
|
||||
|
||||
|
||||
|
||||
+20
-7
@@ -72,15 +72,28 @@ Sys_DebugBreak
|
||||
*/
|
||||
void Sys_DebugBreak( void )
|
||||
{
|
||||
#if XASH_SDL
|
||||
int was_grabbed = host.hWnd != NULL && SDL_GetWindowGrab( host.hWnd );
|
||||
#endif
|
||||
|
||||
if( !Sys_DebuggerPresent( ))
|
||||
return;
|
||||
|
||||
#if XASH_SDL
|
||||
if( was_grabbed ) // so annoying...
|
||||
SDL_SetWindowGrab( host.hWnd, SDL_FALSE );
|
||||
#endif // XASH_SDL
|
||||
|
||||
#if _MSC_VER
|
||||
if( Sys_DebuggerPresent( ))
|
||||
__debugbreak();
|
||||
__debugbreak();
|
||||
#else // !_MSC_VER
|
||||
if( Sys_DebuggerPresent( ))
|
||||
{
|
||||
INLINE_RAISE( SIGINT );
|
||||
INLINE_NANOSLEEP1(); // sometimes signal comes with delay, let it interrupt nanosleep
|
||||
}
|
||||
INLINE_RAISE( SIGINT );
|
||||
INLINE_NANOSLEEP1(); // sometimes signal comes with delay, let it interrupt nanosleep
|
||||
#endif // !_MSC_VER
|
||||
|
||||
#if XASH_SDL
|
||||
if( was_grabbed )
|
||||
SDL_SetWindowGrab( host.hWnd, SDL_TRUE );
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -78,20 +78,6 @@ void Sys_InitLog( void );
|
||||
void Sys_PrintLog( const char *pMsg );
|
||||
int Sys_LogFileNo( void );
|
||||
|
||||
//
|
||||
// con_win.c
|
||||
//
|
||||
#if XASH_WIN32
|
||||
void Wcon_InitConsoleCommands( void );
|
||||
void Wcon_ShowConsole( qboolean show );
|
||||
void Wcon_CreateConsole( void );
|
||||
void Wcon_DestroyConsole( void );
|
||||
void Wcon_DisableInput( void );
|
||||
char *Wcon_Input( void );
|
||||
void Wcon_WinPrint( const char *pMsg );
|
||||
void Wcon_SetStatus( const char *pStatus );
|
||||
#endif
|
||||
|
||||
// text messages
|
||||
#define Msg Con_Printf
|
||||
|
||||
|
||||
@@ -40,6 +40,7 @@ void Test_RunVOX( void );
|
||||
void Test_RunIPFilter( void );
|
||||
void Test_RunGamma( void );
|
||||
void Test_RunDelta( void );
|
||||
void Test_RunBuffer( void );
|
||||
|
||||
#define TEST_LIST_0 \
|
||||
Test_RunLibCommon(); \
|
||||
@@ -47,7 +48,9 @@ void Test_RunDelta( void );
|
||||
Test_RunCmd(); \
|
||||
Test_RunCvar(); \
|
||||
Test_RunIPFilter(); \
|
||||
Test_RunDelta();
|
||||
Test_RunBuffer(); \
|
||||
Test_RunDelta(); \
|
||||
Test_RunMunge();
|
||||
|
||||
#define TEST_LIST_0_CLIENT \
|
||||
Test_RunCon(); \
|
||||
|
||||
+20
-8
@@ -241,6 +241,21 @@ void _Mem_Free( void *data, const char *filename, int fileline )
|
||||
Mem_FreeBlock((memheader_t *)((byte *)data - sizeof( memheader_t )), filename, fileline );
|
||||
}
|
||||
|
||||
static void Mem_MigratePool( poolhandle_t newpoolptr, memheader_t *mem, const char *filename, int fileline )
|
||||
{
|
||||
mempool_t *oldpool = Mem_FindPool( mem->poolptr );
|
||||
mempool_t *newpool = Mem_FindPool( newpoolptr );
|
||||
|
||||
// dettach allocation from one pool and reattach it to new pool
|
||||
// might be made into public function at some point
|
||||
|
||||
Mem_PoolUnlinkAlloc( oldpool, mem );
|
||||
Mem_PoolSubtract( oldpool, mem->size );
|
||||
|
||||
Mem_PoolLinkAlloc( newpool, mem );
|
||||
Mem_PoolAdd( newpool, mem->size );
|
||||
}
|
||||
|
||||
void *_Mem_Realloc( poolhandle_t poolptr, void *data, size_t size, qboolean clear, const char *filename, int fileline )
|
||||
{
|
||||
memheader_t *mem;
|
||||
@@ -262,15 +277,12 @@ void *_Mem_Realloc( poolhandle_t poolptr, void *data, size_t size, qboolean clea
|
||||
|
||||
mem = (memheader_t *)((byte *)data - sizeof( memheader_t ));
|
||||
|
||||
if( !Mem_CheckAllocHeader( "Mem_Realloc", mem, filename, fileline ))
|
||||
if( !Mem_CheckAllocHeader( __func__, mem, filename, fileline ))
|
||||
return NULL;
|
||||
|
||||
if( unlikely( mem->poolptr != poolptr ))
|
||||
{
|
||||
Sys_Error( "%s: pool migration is not allowed (alloc at %s:%i, realloc at %s:%i)\n",
|
||||
__func__, Mem_CheckFilename( mem->filename ), mem->fileline, filename, fileline );
|
||||
return NULL;
|
||||
}
|
||||
// migrate pool if requested, even if no reallocation needed
|
||||
if( mem->poolptr != poolptr )
|
||||
Mem_MigratePool( poolptr, mem, filename, fileline );
|
||||
|
||||
oldsize = mem->size;
|
||||
if( size == oldsize )
|
||||
@@ -439,7 +451,7 @@ void _Mem_Check( const char *filename, int fileline )
|
||||
|
||||
for( i = 0, pool = poolchain; i < poolcount; i++, pool++ )
|
||||
for( mem = pool->chain; mem; mem = mem->next )
|
||||
Mem_CheckAllocHeader( "Mem_CheckSentinels", mem, filename, fileline );
|
||||
Mem_CheckAllocHeader( __func__, mem, filename, fileline );
|
||||
}
|
||||
|
||||
void Mem_PrintStats( void )
|
||||
|
||||
@@ -53,6 +53,10 @@ typedef struct resourceinfo_s
|
||||
#define RES_ALWAYS (1<<5) // Download always even if available on client
|
||||
#define RES_CHECKFILE (1<<7) // Check file on client
|
||||
|
||||
// this archive was already mounted after rescan
|
||||
// only makes sense for archives and on client
|
||||
#define RES_EXTRA_ARCHIVE_CHECKED BIT( 0 )
|
||||
|
||||
typedef struct resource_s
|
||||
{
|
||||
char szFileName[64]; // File name to download/precache.
|
||||
@@ -67,6 +71,7 @@ typedef struct resource_s
|
||||
// if it's a custom resource.
|
||||
|
||||
unsigned char rguc_reserved[32]; // For future expansion
|
||||
unsigned short ucExtraFlags; // fwgs extension, doesn't change the size of struct because of compiler padding
|
||||
struct resource_s *pNext; // Next in chain.
|
||||
struct resource_s *pPrev;
|
||||
} resource_t;
|
||||
@@ -90,4 +95,7 @@ typedef struct customization_s
|
||||
#define FCUST_WIPEDATA ( 1<<1 )
|
||||
#define FCUST_IGNOREINIT ( 1<<2 )
|
||||
|
||||
STATIC_CHECK_SIZEOF( customization_t, 164, 192 );
|
||||
STATIC_CHECK_SIZEOF( resource_t, 136, 144 );
|
||||
|
||||
#endif // CUSTOM_H
|
||||
|
||||
@@ -218,6 +218,10 @@ typedef struct ui_extendedfuncs_s {
|
||||
int (*pfnCompareAdr)( const void *a, const void *b ); // netadr_t
|
||||
void *(*pfnGetNativeObject)( const char *name );
|
||||
struct net_api_s *pNetAPI;
|
||||
|
||||
// new mods info
|
||||
gameinfo2_t *(*pfnGetGameInfo)( int gi_version ); // might return NULL if gi_version is unsupported
|
||||
gameinfo2_t *(*pfnGetModInfo)( int gi_version, int mod_index ); // continiously call it until it returns null
|
||||
} ui_extendedfuncs_t;
|
||||
|
||||
// deprecated export from old engine
|
||||
|
||||
@@ -71,6 +71,11 @@ void Android_Shutdown( void );
|
||||
#if XASH_WIN32
|
||||
void Wcon_CreateConsole( qboolean con_showalways );
|
||||
void Wcon_DestroyConsole( void );
|
||||
void Wcon_InitConsoleCommands( void );
|
||||
void Wcon_ShowConsole( qboolean show );
|
||||
void Wcon_DisableInput( void );
|
||||
char *Wcon_Input( void );
|
||||
void Wcon_WinPrint( const char *pMsg );
|
||||
#endif
|
||||
|
||||
#if XASH_NSWITCH
|
||||
|
||||
@@ -18,8 +18,10 @@ GNU General Public License for more details.
|
||||
#define NET_PSVITA_H
|
||||
|
||||
#include <vitasdk.h>
|
||||
#include "platform/posix/net.h"
|
||||
|
||||
/* we're missing IPv6 support; define some trash */
|
||||
#define XASH_NO_IPV6_RESOLVE 1
|
||||
|
||||
#ifndef IN6_IS_ADDR_V4MAPPED
|
||||
#define IN6_IS_ADDR_V4MAPPED( p ) ( 0 )
|
||||
|
||||
@@ -46,6 +46,7 @@ extern void *__aeabi_idivmod;
|
||||
extern void *__aeabi_uidivmod;
|
||||
extern void *__aeabi_d2ulz;
|
||||
extern void *__aeabi_ul2d;
|
||||
extern void *__aeabi_ul2f;
|
||||
|
||||
static const vrtld_export_t aux_exports[] =
|
||||
{
|
||||
@@ -55,6 +56,7 @@ static const vrtld_export_t aux_exports[] =
|
||||
VRTLD_EXPORT_SYMBOL( __aeabi_uidivmod ),
|
||||
VRTLD_EXPORT_SYMBOL( __aeabi_uidiv ),
|
||||
VRTLD_EXPORT_SYMBOL( __aeabi_ul2d ),
|
||||
VRTLD_EXPORT_SYMBOL( __aeabi_ul2f ),
|
||||
VRTLD_EXPORT_SYMBOL( _impure_ptr ),
|
||||
VRTLD_EXPORT_SYMBOL( ctime ),
|
||||
VRTLD_EXPORT_SYMBOL( vasprintf ),
|
||||
|
||||
@@ -350,7 +350,7 @@ void Platform_SetCursorType( VGUI_DefaultCursor type )
|
||||
}
|
||||
|
||||
// never disable cursor in touch emulation mode
|
||||
if( !visible && touch_emulate.value )
|
||||
if( !visible && Touch_Emulated( ))
|
||||
return;
|
||||
|
||||
host.mouse_visible = visible;
|
||||
|
||||
@@ -47,10 +47,13 @@ qboolean SW_CreateBuffer( int width, int height, uint *stride, uint *bpp, uint *
|
||||
if( sw.renderer )
|
||||
{
|
||||
unsigned int format = SDL_GetWindowPixelFormat( host.hWnd );
|
||||
SDL_RenderSetLogicalSize(sw.renderer, refState.width, refState.height);
|
||||
SDL_RenderSetLogicalSize( sw.renderer, refState.width, refState.height );
|
||||
|
||||
if( sw.tex )
|
||||
{
|
||||
SDL_DestroyTexture( sw.tex );
|
||||
sw.tex = NULL;
|
||||
}
|
||||
|
||||
// guess
|
||||
if( format == SDL_PIXELFORMAT_UNKNOWN )
|
||||
@@ -63,20 +66,16 @@ qboolean SW_CreateBuffer( int width, int height, uint *stride, uint *bpp, uint *
|
||||
|
||||
// we can only copy fast 16 or 32 bits
|
||||
// SDL_Renderer does not allow zero-copy, so 24 bits will be ineffective
|
||||
if( !( SDL_BYTESPERPIXEL(format) == 2 || SDL_BYTESPERPIXEL(format) == 4 ) )
|
||||
if( SDL_BYTESPERPIXEL( format ) != 2 && SDL_BYTESPERPIXEL( format ) != 4 )
|
||||
format = SDL_PIXELFORMAT_RGBA8888;
|
||||
|
||||
sw.tex = SDL_CreateTexture(sw.renderer, format,
|
||||
SDL_TEXTUREACCESS_STREAMING,
|
||||
width, height);
|
||||
sw.tex = SDL_CreateTexture( sw.renderer, format, SDL_TEXTUREACCESS_STREAMING, width, height );
|
||||
|
||||
// fallback
|
||||
if( !sw.tex && format != SDL_PIXELFORMAT_RGBA8888 )
|
||||
{
|
||||
format = SDL_PIXELFORMAT_RGBA8888;
|
||||
sw.tex = SDL_CreateTexture(sw.renderer, format,
|
||||
SDL_TEXTUREACCESS_STREAMING,
|
||||
width, height);
|
||||
sw.tex = SDL_CreateTexture( sw.renderer, format, SDL_TEXTUREACCESS_STREAMING, width, height );
|
||||
}
|
||||
|
||||
if( !sw.tex )
|
||||
@@ -89,25 +88,26 @@ qboolean SW_CreateBuffer( int width, int height, uint *stride, uint *bpp, uint *
|
||||
void *pixels;
|
||||
int pitch;
|
||||
|
||||
if( !SDL_LockTexture(sw.tex, NULL, &pixels, &pitch ) )
|
||||
if( !SDL_LockTexture( sw.tex, NULL, &pixels, &pitch ))
|
||||
{
|
||||
int bits;
|
||||
uint amask;
|
||||
|
||||
// lock successfull, release
|
||||
SDL_UnlockTexture(sw.tex);
|
||||
SDL_UnlockTexture( sw.tex );
|
||||
|
||||
// enough for building blitter tables
|
||||
SDL_PixelFormatEnumToMasks( format, &bits, r, g, b, &amask );
|
||||
*bpp = SDL_BYTESPERPIXEL(format);
|
||||
*bpp = SDL_BYTESPERPIXEL( format );
|
||||
*stride = pitch / *bpp;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// fallback to surf
|
||||
SDL_DestroyTexture(sw.tex);
|
||||
SDL_DestroyTexture( sw.tex );
|
||||
sw.tex = NULL;
|
||||
SDL_DestroyRenderer(sw.renderer);
|
||||
SDL_DestroyRenderer( sw.renderer );
|
||||
sw.renderer = NULL;
|
||||
}
|
||||
}
|
||||
@@ -126,7 +126,7 @@ qboolean SW_CreateBuffer( int width, int height, uint *stride, uint *bpp, uint *
|
||||
// if it is failed, it is not possible to draw with SDL in REF_SOFTWARE mode
|
||||
if( !sw.win )
|
||||
{
|
||||
Sys_Warn("failed to initialize software output, try enable sw_glblit");
|
||||
Sys_Warn( "failed to initialize software output, try running with -glblit flag" );
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -141,9 +141,10 @@ qboolean SW_CreateBuffer( int width, int height, uint *stride, uint *bpp, uint *
|
||||
{
|
||||
sw.surf = SDL_CreateRGBSurfaceWithFormat( 0, width, height, 16, SDL_PIXELFORMAT_RGB565 );
|
||||
if( !sw.surf )
|
||||
Sys_Error(SDL_GetError());
|
||||
Sys_Error( "%s: %s", __func__, SDL_GetError( ));
|
||||
}
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
// we can't create ref_soft buffer
|
||||
@@ -640,9 +641,17 @@ void VID_RestoreScreenResolution( void )
|
||||
switch((window_mode_t)vid_fullscreen.value )
|
||||
{
|
||||
case WINDOW_MODE_WINDOWED:
|
||||
// TODO: this line is from very old SDL video backend
|
||||
// figure out why we need it, because in windowed mode we
|
||||
// always have borders
|
||||
SDL_SetWindowBordered( host.hWnd, SDL_TRUE );
|
||||
break;
|
||||
default:
|
||||
case WINDOW_MODE_BORDERLESS:
|
||||
// in borderless fullscreen we don't change screen resolution, so no-op
|
||||
break;
|
||||
case WINDOW_MODE_FULLSCREEN:
|
||||
// TODO: we might want to not minimize window if current desktop mode
|
||||
// and window mode are the same
|
||||
SDL_MinimizeWindow( host.hWnd );
|
||||
SDL_SetWindowFullscreen( host.hWnd, 0 );
|
||||
break;
|
||||
@@ -1006,9 +1015,10 @@ qboolean R_Init_Video( const int type )
|
||||
{
|
||||
string safe;
|
||||
qboolean retval;
|
||||
|
||||
#if SDL_VERSION_ATLEAST( 2, 0, 0 )
|
||||
SDL_DisplayMode displayMode;
|
||||
SDL_GetCurrentDisplayMode(0, &displayMode);
|
||||
SDL_GetCurrentDisplayMode( 0, &displayMode );
|
||||
refState.desktopBitsPixel = SDL_BITSPERPIXEL( displayMode.format );
|
||||
#else
|
||||
refState.desktopBitsPixel = 16;
|
||||
@@ -1086,7 +1096,7 @@ rserr_t R_ChangeDisplaySettings( int width, int height, window_mode_t window_mod
|
||||
|
||||
if( SDL_GetCurrentDisplayMode( 0, &displayMode ) < 0 )
|
||||
{
|
||||
Con_Printf( S_ERROR "SDL_GetCurrentDisplayMode: %s", SDL_GetError( ));
|
||||
Con_Printf( S_ERROR "SDL_GetCurrentDisplayMode: %s\n", SDL_GetError( ));
|
||||
return rserr_invalid_mode;
|
||||
}
|
||||
|
||||
@@ -1180,14 +1190,8 @@ qboolean VID_SetMode( void )
|
||||
}
|
||||
#endif
|
||||
|
||||
if( !FBitSet( vid_fullscreen.flags, FCVAR_CHANGED ))
|
||||
Cvar_DirectSet( &vid_fullscreen, DEFAULT_FULLSCREEN );
|
||||
else
|
||||
ClearBits( vid_fullscreen.flags, FCVAR_CHANGED );
|
||||
|
||||
SetBits( gl_vsync.flags, FCVAR_CHANGED );
|
||||
|
||||
window_mode = bound( 0, vid_fullscreen.value, WINDOW_MODE_COUNT - 1 );
|
||||
SetBits( gl_vsync.flags, FCVAR_CHANGED );
|
||||
|
||||
if(( err = R_ChangeDisplaySettings( iScreenWidth, iScreenHeight, window_mode )) == rserr_ok )
|
||||
{
|
||||
@@ -1236,10 +1240,6 @@ void R_Free_Video( void )
|
||||
R_FreeVideoModes();
|
||||
|
||||
ref.dllFuncs.GL_ClearExtensions();
|
||||
|
||||
#if SDL_VERSION_ATLEAST( 2, 0, 0 )
|
||||
SDL_VideoQuit();
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif // XASH_DEDICATED
|
||||
|
||||
+6
-3
@@ -389,10 +389,13 @@ typedef struct ref_api_s
|
||||
int (*pfnGetStudioModelInterface)( int version, struct r_studio_interface_s **ppinterface, struct engine_studio_api_s *pstudio );
|
||||
|
||||
// memory
|
||||
poolhandle_t (*_Mem_AllocPool)( const char *name, const char *filename, int fileline );
|
||||
poolhandle_t (*_Mem_AllocPool)( const char *name, const char *filename, int fileline )
|
||||
WARN_UNUSED_RESULT;
|
||||
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 ) ALLOC_CHECK( 2 );
|
||||
void *(*_Mem_Realloc)( poolhandle_t poolptr, void *memptr, size_t size, qboolean clear, const char *filename, int fileline ) ALLOC_CHECK( 3 );
|
||||
void *(*_Mem_Alloc)( poolhandle_t poolptr, size_t size, qboolean clear, const char *filename, int fileline )
|
||||
ALLOC_CHECK( 2 ) WARN_UNUSED_RESULT;
|
||||
void *(*_Mem_Realloc)( poolhandle_t poolptr, void *memptr, size_t size, qboolean clear, const char *filename, int fileline )
|
||||
ALLOC_CHECK( 3 ) WARN_UNUSED_RESULT;
|
||||
void (*_Mem_Free)( void *data, const char *filename, int fileline );
|
||||
|
||||
// library management
|
||||
|
||||
@@ -444,7 +444,7 @@ static void SV_ConnectClient( netadr_t from )
|
||||
newcl->listeners = -1;
|
||||
|
||||
// initailize netchan
|
||||
Netchan_Setup( NS_SERVER, &newcl->netchan, from, qport, newcl, SV_GetFragmentSize );
|
||||
Netchan_Setup( NS_SERVER, &newcl->netchan, from, qport, newcl, SV_GetFragmentSize, 0 );
|
||||
MSG_Init( &newcl->datagram, "Datagram", newcl->datagram_buf, sizeof( newcl->datagram_buf )); // datagram buf
|
||||
|
||||
Q_strncpy( newcl->hashedcdkey, Info_ValueForKey( protinfo, "uuid" ), 32 );
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user