Compare commits

...

88 Commits

Author SHA1 Message Date
Alibek Omarov
215feb3ba9 engine: client: support GoldSrc signon and refactor parsing delta entities for current and legacy protocols 2024-10-07 21:44:25 +03:00
Alibek Omarov
150e2607d9 engine: client: support parsing GoldSrc event messages 2024-10-07 21:16:00 +03:00
Alibek Omarov
e8452c68d7 engine: client: add support for parsing GoldSrc messages 2024-10-07 21:09:57 +03:00
Alibek Omarov
7fe0aba71c engine: client: refactor and implement GoldSrc-specific parsing bits in common message parsing code 2024-10-07 21:09:57 +03:00
Alibek Omarov
adcc9eb0df engine: client: add support for parsing GoldSrc svc_temp_entity 2024-10-07 21:09:57 +03:00
Alibek Omarov
081d1da640 engine: client: get rid of PROTOCOL_GOLDSRC_VERSION, as connprotocol_t enum does it's job 2024-10-07 21:09:57 +03:00
Alibek Omarov
4aadea40a3 engine: common: add GoldSrc delta support 2024-10-07 21:09:57 +03:00
Alibek Omarov
8deea9dc7e engine: common: add GoldSrc bitbuf operations, add support for GoldSrc signed integers 2024-10-07 19:34:19 +03:00
Alibek Omarov
d650d8c271 engine: common: add support for GoldSrc split packet 2024-10-07 19:11:30 +03:00
Alibek Omarov
eb89c8b222 engine: client: rename CL_LegacyMode to CL_Protocol 2024-10-07 19:04:24 +03:00
Alibek Omarov
659ffc4519 engine: common: add GoldSrc netchan support 2024-10-07 18:57:52 +03:00
Alibek Omarov
63a63a52de engine: common: add buffer munge functions 2024-10-07 18:57:52 +03:00
Alibek Omarov
e082d76a45 engine: remove unused svc_deltapacketbones 2024-10-07 18:57:52 +03:00
Alibek Omarov
cb8e2a4f9f 3rdparty: bzip2: add wscript for bzip2, check for system-wide bzip2, add readme note 2024-10-07 18:57:52 +03:00
Alibek Omarov
5f55930cb7 3rdparty: add bzip2 submodule 2024-10-07 18:10:06 +03:00
Alibek Omarov
dd03723144 readme: add libopus-dev to dependencies list on Debian/Ubuntu 2024-10-07 18:09:32 +03:00
xiaodo
26f07196ea engine: Format Codes. 2024-10-07 17:22:27 +03:00
xiaodo
8c291fdfe3 engine: fix CenterPrint Wrong Y Position. 2024-10-07 17:22:27 +03:00
xiaodoxd
d1e118f07c Fix CenterPrint Wrong X Position 2024-10-07 17:22:27 +03:00
Alibek Omarov
6c531c14e6 engine: common: cvar: compatibility hack for mods that depend on HL25 widescreen FOV
Fixes Natural Selection 3.3 beta 9.
2024-10-04 19:09:43 +03:00
Alibek Omarov
433213c915 engine: server: fix cvar description for mp_footsteps 2024-10-04 19:07:44 +03:00
Alibek Omarov
ab0c0b18c2 engine: server: remove limit on sv_zmax value as it breaks Natural Selection mod 2024-10-04 19:07:08 +03:00
Alibek Omarov
29fd5f9fbe engine: server: remove FCVAR_SERVER flag from sv_zmax
The problem is that FCVAR_SERVER flagged cvars get saved to listenserver.cfg.

The game code usually sets sv_zmax value to worldspawn parameters and
listenserver.cfg gets generated before server DLL gets initialized.
2024-10-04 19:04:34 +03:00
Alibek Omarov
882d8afc93 engine: server: stub SV_RestartDecals for dedicated server 2024-10-04 01:28:22 +03:00
Alibek Omarov
e11635d15c engine: server: slight refactoring, hide client calls under XASH_DEDICATED, remove useless dedicated stub 2024-10-04 01:22:59 +03:00
Alibek Omarov
5d79d93aac engine: server: use safe cvar unlinking for mods that deallocate cvars (like HL Unified SDK) 2024-10-03 15:32:14 +03:00
Alibek Omarov
7ccf651fd0 engine: cvar: implement safer cvar unlinking in case when game deallocates cvar 2024-10-03 15:32:14 +03:00
Alibek Omarov
67af41cce8 engine: common: net_ws: more minor refactoring, avoid memcpy for same type structs 2024-10-02 23:30:42 +03:00
Alibek Omarov
e2c96e62e1 engine: common: net_ws: drop IPv4 mapped as IPv6 support, it's an artifact from dual-stacking experiments and not used anymore 2024-10-02 23:26:28 +03:00
Alibek Omarov
2ecae442fc engine: common: net_ws: minor refactoring 2024-10-02 23:25:12 +03:00
Alibek Omarov
a1060b0eb5 engine: add v6only master servers, add v6only flag for NET_StringToAdrNB 2024-10-02 23:23:08 +03:00
Alibek Omarov
ddd8de888f engine: add macro XASH_NO_IPV6_RESOLVE to completely skip resolving addresses with family AF_INET6 2024-10-02 23:21:25 +03:00
Alibek Omarov
a758dffbc1 public: avoid useless copy in Q_timestamp 2024-10-02 22:18:16 +03:00
Alibek Omarov
87775faeca engine: common: properly check if we can destroy resolve mutexes. Add net_resolve_debug cvar to enable printing resolve thread debug messages. 2024-10-02 22:16:51 +03:00
Alibek Omarov
ef0fc46ed8 wscript: allow async resolving for NSwitch 2024-10-02 00:55:53 +03:00
Alibek Omarov
138b4fa247 wscript: allow async resolving for PSVita 2024-10-02 00:55:53 +03:00
Alibek Omarov
47d1f3459c engine: common: try to implement DNS resolve thread through SDL2 functions if SDL2 build is enabled 2024-10-02 00:55:53 +03:00
Alibek Omarov
4712aae834 engine: server: move autoprecaching wads after parsing reslists
An attempt to avoid assert() in HL Unified SDK.
2024-09-30 18:46:01 +03:00
Ivan Avdeev
2900ee1cde engine: allow specifying screenshot filenames in command directly 2024-09-30 17:15:09 +03:00
Alibek Omarov
c6c4178dd2 engine: client: set TE_SPRAY to collide with world, fixes c7ad8e4bf 2024-09-30 04:15:22 +03:00
Alibek Omarov
a3ce0e6b1b public: tests: test_efp: mark Test_ExtractFilePath as static 2024-09-30 04:00:28 +03:00
Alibek Omarov
0b1ad3b7f0 engine: imagelib: fix mismatched dealloc in a test 2024-09-30 04:00:28 +03:00
Alibek Omarov
37fb46f092 wscript: enable mismatched-dealloc and free-nonheap-object, now that we mark all malloc-like functions with malloc attribute 2024-09-30 04:00:28 +03:00
Alibek Omarov
bc8bf9a9fb engine: add const on delta functions 2024-09-30 04:00:28 +03:00
Alibek Omarov
9e28c98911 engine: print to stderr if writing message to logfile failed 2024-09-30 04:00:28 +03:00
Alibek Omarov
0a1269d52d filesystem: zip: fix non-heap object dealloc 2024-09-30 04:00:28 +03:00
Alibek Omarov
2e5bc31c9e filesystem: set malloc like attribute for imported zone memory allocator functions 2024-09-30 04:00:28 +03:00
Alibek Omarov
1b335fd945 ref: soft: set malloc like attribute for imported zone memory allocator functions 2024-09-30 04:00:28 +03:00
Alibek Omarov
0c8b2d007a ref: gl: set malloc like attribute for imported zone memory allocator functions 2024-09-30 04:00:28 +03:00
Alibek Omarov
9ee1b32e2d engine: set malloc like and warn_unused_result attributes on common allocation functions, fs, image and soundlib 2024-09-30 04:00:28 +03:00
Alibek Omarov
953ad98a16 engine: workaround buggy stringop-overflow 2024-09-30 04:00:28 +03:00
Alibek Omarov
1357057bd8 common: add GCC malloc and warn_unused_result attribute macro 2024-09-30 04:00:28 +03:00
Alibek Omarov
35c9323de6 public: make vec3_origin and identity matrix inlined 2024-09-30 00:15:47 +03:00
Alibek Omarov
13a0afef06 public: reorganize mathlib, inline more functions 2024-09-30 00:15:47 +03:00
Alibek Omarov
c7ad8e4bf6 engine: client: more accurate implementation of TE_SPRAY and TE_SPRITE_SPRAY 2024-09-29 20:36:09 +03:00
Alibek Omarov
f1754bdd5f wscript: disable cast-align diagnostic, it's mostly useless 2024-09-29 20:36:09 +03:00
Alibek Omarov
c462a1c500 wscript: add commented out freevgui subproject 2024-09-29 20:36:09 +03:00
Alibek Omarov
0bba184994 public: add VectorUnpack macro to read vector values into variables 2024-09-29 20:33:33 +03:00
Alibek Omarov
178602ea1f engine: fix loading map in Dark Future mod with broken mark surface id 2024-09-05 15:23:23 +03:00
Alibek Omarov
2eb8f88a20 engine: move attenuation none sound spatialize fix to bugcomp mode, as Xash native games use this 2024-09-05 13:50:15 +03:00
Alibek Omarov
96d11df06c Revert "engine: client: sounds with zero attenuation must get spatialized anyway"
This reverts commit 0870536405.
2024-09-05 13:27:54 +03:00
Alibek Omarov
950d210ec5 Revert ABI2, it wasn't meant to end up in master branch. 2024-09-05 04:31:50 +03:00
Alibek Omarov
55c1bddac5 ref: gl: implement generating VBO only when gl_vbo was set to 1
* Make it safer by creating a function that returns VBO state, was it
  generated or enabled by user
2024-09-05 04:10:56 +03:00
Alibek Omarov
ac50c762d7 ref: gl: slight refactoring, split large R_RenderBrushPoly to smaller functions
* Use R_RenderDetailsForSurface in R_AddSurfToVBO instead of copypaste
* Use existing VBO's R_CheckLightMap in R_RenderLightmapForSurface
2024-09-05 02:40:57 +03:00
Alibek Omarov
5c2ab150b3 ref: gl: move forcing gl_vbo to 0 after checking GL extensions out from R_GenerateVBO 2024-09-05 01:47:14 +03:00
Alibek Omarov
0870536405 engine: client: sounds with zero attenuation must get spatialized anyway 2024-09-05 01:28:55 +03:00
Alibek Omarov
b47ede477a engine: server: strip 64-bit string pool stuff for now, to not mess up abi2 2024-09-05 01:28:55 +03:00
Alibek Omarov
eef5cc17b3 breaking engine headers by replacing int with string_t where it's supposed to be 2024-09-05 01:28:55 +03:00
Alibek Omarov
ad2191333d engine: add _st64 prefix to load abi2 binaries 2024-09-05 01:28:55 +03:00
SNMetamorph
a85cac497d ref: disabled verbose reporting about tracer invalid color index 2024-09-03 15:31:51 +03:00
SNMetamorph
e0c69d7df5 gha: fixed binaries signing in Windows workflow 2024-08-30 07:34:40 +03:00
Alibek Omarov
ff3d91ceb4 engine: add aaaa.mentality.rip:27011 master server 2024-08-28 19:56:41 +03:00
Alibek Omarov
5777431577 engine: common: insert spaces between arguments in echo command 2024-08-22 16:45:42 +03:00
Alibek Omarov
cd86f80203 engine: common: make MSG_WriteOneBit inlined, as it's usually called with literal argument 2024-08-22 12:51:47 +03:00
Alibek Omarov
8c885d3f37 mainui: update 2024-08-22 12:50:01 +03:00
Alibek Omarov
dddb46a6d0 mainui: update 2024-08-21 18:14:21 +03:00
Alibek Omarov
6b0f378c5b engine: client: ensure requested (but failed) renderer won't be loaded twice 2024-08-21 12:18:06 +03:00
Alibek Omarov
9dd7f37d42 Revert "engine: client: add missing ref_null to R_CollectRendererNames"
This reverts commit 69ec810ed0.
2024-08-21 12:18:06 +03:00
Alibek Omarov
9f10fb6472 engine: client: ensure RefDll cvars have FCVAR_REFDLL flag, clean up them automatically. Don't unload failed renderer, it will be done in R_UnloadProgs 2024-08-21 12:18:06 +03:00
Alibek Omarov
64dbccb9bd engine: platform: sdl: do not call SDL_VideoQuit in R_Free_Video, as one failed renderer will shut down whole SDL video subsystem 2024-08-21 12:18:06 +03:00
Alibek Omarov
9a432a5a13 common: rewrite cvardef.h from scratch based on Quake definitions
* unify cvar.h and cvardef.h, enable private definitions only for refdll and engine

* add FCVAR_REFDLL for easier RefDll cvars cleanup
2024-08-21 12:18:06 +03:00
Alibek Omarov
842e494fa6 common: add macro for simultaneously checking data type size for ILP32 and LP64 2024-08-21 12:00:35 +03:00
Alibek Omarov
7fc9ee154a engine: client: fail with Sys_Error when no renderer is loaded, as we can't recover from it 2024-08-19 13:25:07 +03:00
Alibek Omarov
5f84010c2a engine: server: enable allocating 64-bit string pool closer to server library only for Linux amd64, as mmap() isn't reliable anywhere else 2024-08-19 13:22:04 +03:00
Alibek Omarov
3dcd6cb80b wscript: set crosscompiling msvc toolchain on 64-bit systems 2024-08-18 14:13:51 +03:00
Alibek Omarov
79e94bf766 Revert "scripts: gha: use 64-bit compiler for 32-bit target for faster compilation on Win32"
This reverts commit 3de370f3d5.
2024-08-18 14:13:01 +03:00
Alibek Omarov
3de370f3d5 scripts: gha: use 64-bit compiler for 32-bit target for faster compilation on Win32 2024-08-18 14:04:54 +03:00
Alibek Omarov
c84d2f4624 gha: first attempt at signing binaries 2024-08-18 13:52:02 +03:00
88 changed files with 3610 additions and 1903 deletions

View File

@@ -60,6 +60,8 @@ jobs:
- 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@v4

3
.gitmodules vendored
View File

@@ -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
3rdparty/bzip2/bzip2 vendored Submodule

Submodule 3rdparty/bzip2/bzip2 added at 66c46b8c94

35
3rdparty/bzip2/wscript vendored Normal file
View File

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

View File

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

View File

@@ -67,9 +67,9 @@ This repository contains our fork of HLSDK and restored source code for Half-Lif
`$ 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`

View File

@@ -543,14 +543,8 @@ typedef struct
#define MAX_CLIENT_SPRITES 512 // SpriteTextures (0-256 hud, 256-512 client)
#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

View File

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

View File

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

View File

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

View File

@@ -56,6 +56,8 @@ color24 gTracerColors[] =
};
*/
#define TRACER_COLORINDEX_DEFAULT 4
// Temporary entity array
#define TENTPRIORITY_LOW 0
#define TENTPRIORITY_HIGH 1

View File

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

View File

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

View File

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

View File

@@ -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",
@@ -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;
}
@@ -706,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;

View File

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

View File

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

View File

@@ -669,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 )
@@ -694,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;
@@ -707,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 ))
@@ -717,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
@@ -787,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;
@@ -803,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;
@@ -817,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;
}
}
@@ -860,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 ))
@@ -892,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 )
@@ -911,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;
}
@@ -940,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 )
@@ -972,7 +947,7 @@ int CL_ParsePacketEntities( sizebuf_t *msg, qboolean delta )
cls.signon = SIGNONS;
// Clear loading plaque.
CL_SignonReply ();
CL_SignonReply( proto );
}
return playerbytes;

View File

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

View File

@@ -170,6 +170,11 @@ int CL_IsDevOverviewMode( void )
return 0;
}
connprotocol_t CL_Protocol( void )
{
return cls.legacymode;
}
/*
===============
CL_CheckClientState
@@ -217,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 );
@@ -225,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;
@@ -693,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 );
}
/*
@@ -792,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 );
@@ -829,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;
@@ -1048,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 )
@@ -1147,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 )
{
@@ -1278,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;
}
}
@@ -1477,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 );
}
}
@@ -1494,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
{
@@ -2047,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;
@@ -2169,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
@@ -2206,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];
@@ -2214,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 );
@@ -2378,6 +2429,8 @@ static void CL_ReadNetMessage( void )
parsefn = CL_ParseQuakeMessage;
break;
case PROTO_GOLDSRC:
parsefn = CL_ParseGoldSrcServerMessage;
break;
default:
ASSERT( 0 );
return;
@@ -2697,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 )
{

View File

@@ -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 );
}
/*
@@ -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,7 +1481,7 @@ 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 ) gameui.playerinfo = *player;
@@ -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 );

View File

@@ -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;
@@ -658,8 +658,3 @@ void CL_LegacyPrecache_f( void )
MSG_WriteStringf( &cls.netchan.message, "begin %i", spawncount );
cls.signon = SIGNONS - 1;
}
qboolean CL_LegacyMode( void )
{
return cls.legacymode == PROTO_LEGACY;
}

761
engine/client/cl_parse_gs.c Normal file
View File

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

View File

@@ -431,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
@@ -626,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;
@@ -1006,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

View File

@@ -1269,6 +1269,73 @@ void GAME_EXPORT R_Sprite_Smoke( TEMPENTITY *pTemp, float scale )
pTemp->entity.curstate.scale = scale;
}
static void R_Spray_Generic( const char *func, const vec3_t pos, const vec3_t dir, int modelIndex, int count, int speed, int spread, int rendermode, qboolean sprite_spray )
{
model_t *mod = CL_ModelHandle( modelIndex );
float noise = spread / 100.0f;
float znoise = noise * 1.5f;
int i;
znoise = Q_min( 1.0f, znoise );
if( !mod )
{
Con_Reportf( "%s: No model %d!\n", func, modelIndex );
return;
}
for( i = 0; i < count; i++ )
{
TEMPENTITY *tent = CL_TempEntAlloc( pos, mod );
float rand_speed;
vec3_t noise_vec, vout;
if( !tent )
break;
tent->flags |= FTENT_SLOWGRAVITY;
tent->entity.curstate.rendermode = rendermode;
tent->entity.curstate.renderamt = 255;
tent->entity.baseline.renderamt = 255;
tent->entity.curstate.renderfx = kRenderFxNoDissipation;
noise_vec[0] = COM_RandomFloat( -noise, noise );
noise_vec[1] = COM_RandomFloat( -noise, noise );
noise_vec[2] = COM_RandomFloat( 0.0f, znoise );
rand_speed = COM_RandomFloat( speed * 0.8f, speed * 1.2f );
VectorAdd( dir, noise_vec, vout );
VectorScale( vout, rand_speed, tent->entity.baseline.origin );
if( sprite_spray ) // if TE_SPRITE_SPRAY
{
tent->flags |= FTENT_FADEOUT;
tent->fadeSpeed = 2.0f;
tent->entity.curstate.framerate = 0.5f;
tent->die = cl.time + 0.35;
tent->entity.curstate.frame = COM_RandomLong( 0, tent->frameMax ); // frameMax inclusive
}
else
{
tent->flags |= FTENT_COLLIDEWORLD;
if( tent->frameMax > 1 )
{
tent->flags |= FTENT_SPRANIMATE;
tent->entity.curstate.framerate = 10.0f;
tent->die = cl.time + tent->frameMax * 0.1;
}
else
{
tent->entity.curstate.framerate = 1.0f;
tent->die = cl.time + 0.35;
}
tent->entity.curstate.frame = 0.0f;
}
}
}
/*
===============
R_Spray
@@ -1278,61 +1345,7 @@ Throws a shower of sprites or models
*/
void GAME_EXPORT R_Spray( const vec3_t pos, const vec3_t dir, int modelIndex, int count, int speed, int spread, int rendermode )
{
TEMPENTITY *pTemp;
float noise;
float znoise;
model_t *pmodel;
int i;
if(( pmodel = CL_ModelHandle( modelIndex )) == NULL )
{
Con_Reportf( "No model %d!\n", modelIndex );
return;
}
noise = (float)spread / 100.0f;
// more vertical displacement
znoise = Q_min( 1.0f, noise * 1.5f );
for( i = 0; i < count; i++ )
{
pTemp = CL_TempEntAlloc( pos, pmodel );
if( !pTemp ) return;
pTemp->entity.curstate.rendermode = rendermode;
pTemp->entity.baseline.renderamt = pTemp->entity.curstate.renderamt = 255;
pTemp->entity.curstate.renderfx = kRenderFxNoDissipation;
if( rendermode != kRenderGlow )
{
// spray
pTemp->flags |= FTENT_COLLIDEWORLD | FTENT_SLOWGRAVITY;
if( pTemp->frameMax > 1 )
{
pTemp->flags |= FTENT_COLLIDEWORLD | FTENT_SLOWGRAVITY | FTENT_SPRANIMATE;
pTemp->die = cl.time + (pTemp->frameMax * 0.1f);
pTemp->entity.curstate.framerate = 10;
}
else pTemp->die = cl.time + 0.35f;
}
else
{
// sprite spray
pTemp->entity.curstate.frame = COM_RandomLong( 0, pTemp->frameMax );
pTemp->flags |= FTENT_FADEOUT | FTENT_SLOWGRAVITY;
pTemp->entity.curstate.framerate = 0.5;
pTemp->die = cl.time + 0.35f;
pTemp->fadeSpeed = 2.0;
}
// make the spittle fly the direction indicated, but mix in some noise.
pTemp->entity.baseline.origin[0] = dir[0] + COM_RandomFloat( -noise, noise );
pTemp->entity.baseline.origin[1] = dir[1] + COM_RandomFloat( -noise, noise );
pTemp->entity.baseline.origin[2] = dir[2] + COM_RandomFloat( 0, znoise );
VectorScale( pTemp->entity.baseline.origin, COM_RandomFloat(( speed * 0.8f ), ( speed * 1.2f )), pTemp->entity.baseline.origin );
}
R_Spray_Generic( __func__, pos, dir, modelIndex, count, speed, spread, rendermode, false );
}
/*
@@ -1344,7 +1357,7 @@ Spray of alpha sprites
*/
void GAME_EXPORT R_Sprite_Spray( const vec3_t pos, const vec3_t dir, int modelIndex, int count, int speed, int spread )
{
R_Spray( pos, dir, modelIndex, count, speed, spread, kRenderGlow );
R_Spray_Generic( __func__, pos, dir, modelIndex, count, speed, spread, kRenderTransAlpha, true );
}
/*
@@ -1879,13 +1892,13 @@ CL_ParseTempEntity
handle temp-entity messages
==============
*/
void CL_ParseTempEntity( sizebuf_t *msg )
void CL_ParseTempEntity( sizebuf_t *msg, connprotocol_t proto )
{
sizebuf_t buf;
byte pbuf[2048];
sizebuf_t buf, *pbuf;
byte msg_data[2048];
int iSize;
int type, color, count, flags;
int decalIndex, modelIndex, entityIndex;
int decalIndex = 0, modelIndex = 0, entityIndex = 0;
float scale, life, frameRate, vel, random;
float brightness, r, g, b;
vec3_t pos, pos2, ang;
@@ -1896,23 +1909,30 @@ void CL_ParseTempEntity( sizebuf_t *msg )
sound_t hSound;
const char *name;
if( cls.legacymode )
iSize = MSG_ReadByte( msg );
else iSize = MSG_ReadWord( msg );
if( proto != PROTO_GOLDSRC )
{
if( proto == PROTO_LEGACY )
iSize = MSG_ReadByte( msg );
else iSize = MSG_ReadWord( msg );
decalIndex = modelIndex = entityIndex = 0;
// this will probably be fatal anyway
if( iSize > sizeof( pbuf ))
Con_Printf( S_ERROR "%s: Temp buffer overflow!\n", __func__ );
// this will probably be fatal anyway
if( iSize > sizeof( pbuf ))
Con_Printf( S_ERROR "%s: Temp buffer overflow!\n", __func__ );
// parse user message into buffer
MSG_ReadBytes( msg, pbuf, iSize );
// parse user message into buffer
MSG_ReadBytes( msg, pbuf, iSize );
// init a safe tempbuffer
MSG_Init( pbuf, "TempEntity", pbuf, iSize );
// init a safe tempbuffer
MSG_Init( &buf, "TempEntity", pbuf, iSize );
pbuf = pbuf;
}
else
{
pbuf = msg;
}
type = MSG_ReadByte( &buf );
type = MSG_ReadByte( pbuf );
switch( type )
{
@@ -1929,29 +1949,29 @@ void CL_ParseTempEntity( sizebuf_t *msg )
case TE_BEAMRING:
case TE_BEAMHOSE:
case TE_KILLBEAM:
CL_ParseViewBeam( &buf, type );
CL_ParseViewBeam( pbuf, type );
break;
case TE_GUNSHOT:
pos[0] = MSG_ReadCoord( &buf );
pos[1] = MSG_ReadCoord( &buf );
pos[2] = MSG_ReadCoord( &buf );
pos[0] = MSG_ReadCoord( pbuf );
pos[1] = MSG_ReadCoord( pbuf );
pos[2] = MSG_ReadCoord( pbuf );
R_RicochetSound( pos );
R_RunParticleEffect( pos, vec3_origin, 0, 20 );
break;
case TE_EXPLOSION:
pos[0] = MSG_ReadCoord( &buf );
pos[1] = MSG_ReadCoord( &buf );
pos[2] = MSG_ReadCoord( &buf );
modelIndex = MSG_ReadShort( &buf );
scale = (float)(MSG_ReadByte( &buf ) * 0.1f);
frameRate = MSG_ReadByte( &buf );
flags = MSG_ReadByte( &buf );
pos[0] = MSG_ReadCoord( pbuf );
pos[1] = MSG_ReadCoord( pbuf );
pos[2] = MSG_ReadCoord( pbuf );
modelIndex = MSG_ReadShort( pbuf );
scale = (float)(MSG_ReadByte( pbuf ) * 0.1f);
frameRate = MSG_ReadByte( pbuf );
flags = MSG_ReadByte( pbuf );
R_Explosion( pos, modelIndex, scale, frameRate, flags );
break;
case TE_TAREXPLOSION:
pos[0] = MSG_ReadCoord( &buf );
pos[1] = MSG_ReadCoord( &buf );
pos[2] = MSG_ReadCoord( &buf );
pos[0] = MSG_ReadCoord( pbuf );
pos[1] = MSG_ReadCoord( pbuf );
pos[2] = MSG_ReadCoord( pbuf );
R_BlobExplosion( pos );
if(( name = SoundList_Get( Explode, 0 )))
@@ -1961,48 +1981,48 @@ void CL_ParseTempEntity( sizebuf_t *msg )
}
break;
case TE_SMOKE:
pos[0] = MSG_ReadCoord( &buf );
pos[1] = MSG_ReadCoord( &buf );
pos[2] = MSG_ReadCoord( &buf );
modelIndex = MSG_ReadShort( &buf );
scale = (float)(MSG_ReadByte( &buf ) * 0.1f);
frameRate = MSG_ReadByte( &buf );
pos[0] = MSG_ReadCoord( pbuf );
pos[1] = MSG_ReadCoord( pbuf );
pos[2] = MSG_ReadCoord( pbuf );
modelIndex = MSG_ReadShort( pbuf );
scale = (float)(MSG_ReadByte( pbuf ) * 0.1f);
frameRate = MSG_ReadByte( pbuf );
pTemp = R_DefaultSprite( pos, modelIndex, frameRate );
R_Sprite_Smoke( pTemp, scale );
break;
case TE_TRACER:
pos[0] = MSG_ReadCoord( &buf );
pos[1] = MSG_ReadCoord( &buf );
pos[2] = MSG_ReadCoord( &buf );
pos2[0] = MSG_ReadCoord( &buf );
pos2[1] = MSG_ReadCoord( &buf );
pos2[2] = MSG_ReadCoord( &buf );
pos[0] = MSG_ReadCoord( pbuf );
pos[1] = MSG_ReadCoord( pbuf );
pos[2] = MSG_ReadCoord( pbuf );
pos2[0] = MSG_ReadCoord( pbuf );
pos2[1] = MSG_ReadCoord( pbuf );
pos2[2] = MSG_ReadCoord( pbuf );
R_TracerEffect( pos, pos2 );
break;
case TE_SPARKS:
pos[0] = MSG_ReadCoord( &buf );
pos[1] = MSG_ReadCoord( &buf );
pos[2] = MSG_ReadCoord( &buf );
pos[0] = MSG_ReadCoord( pbuf );
pos[1] = MSG_ReadCoord( pbuf );
pos[2] = MSG_ReadCoord( pbuf );
R_SparkShower( pos );
break;
case TE_LAVASPLASH:
pos[0] = MSG_ReadCoord( &buf );
pos[1] = MSG_ReadCoord( &buf );
pos[2] = MSG_ReadCoord( &buf );
pos[0] = MSG_ReadCoord( pbuf );
pos[1] = MSG_ReadCoord( pbuf );
pos[2] = MSG_ReadCoord( pbuf );
R_LavaSplash( pos );
break;
case TE_TELEPORT:
pos[0] = MSG_ReadCoord( &buf );
pos[1] = MSG_ReadCoord( &buf );
pos[2] = MSG_ReadCoord( &buf );
pos[0] = MSG_ReadCoord( pbuf );
pos[1] = MSG_ReadCoord( pbuf );
pos[2] = MSG_ReadCoord( pbuf );
R_TeleportSplash( pos );
break;
case TE_EXPLOSION2:
pos[0] = MSG_ReadCoord( &buf );
pos[1] = MSG_ReadCoord( &buf );
pos[2] = MSG_ReadCoord( &buf );
color = MSG_ReadByte( &buf );
count = MSG_ReadByte( &buf );
pos[0] = MSG_ReadCoord( pbuf );
pos[1] = MSG_ReadCoord( pbuf );
pos[2] = MSG_ReadCoord( pbuf );
color = MSG_ReadByte( pbuf );
count = MSG_ReadByte( pbuf );
R_ParticleExplosion2( pos, color, count );
dl = CL_AllocDlight( 0 );
@@ -2022,25 +2042,25 @@ void CL_ParseTempEntity( sizebuf_t *msg )
case TE_WORLDDECAL:
case TE_WORLDDECALHIGH:
case TE_DECALHIGH:
pos[0] = MSG_ReadCoord( &buf );
pos[1] = MSG_ReadCoord( &buf );
pos[2] = MSG_ReadCoord( &buf );
pos[0] = MSG_ReadCoord( pbuf );
pos[1] = MSG_ReadCoord( pbuf );
pos[2] = MSG_ReadCoord( pbuf );
if( type == TE_BSPDECAL )
{
decalIndex = MSG_ReadShort( &buf );
entityIndex = MSG_ReadShort( &buf );
decalIndex = MSG_ReadShort( pbuf );
entityIndex = MSG_ReadShort( pbuf );
if( entityIndex )
modelIndex = MSG_ReadShort( &buf );
modelIndex = MSG_ReadShort( pbuf );
else modelIndex = 0;
}
else
{
decalIndex = MSG_ReadByte( &buf );
decalIndex = MSG_ReadByte( pbuf );
if( type == TE_DECALHIGH || type == TE_WORLDDECALHIGH )
decalIndex += 256;
if( type == TE_DECALHIGH || type == TE_DECAL )
entityIndex = MSG_ReadShort( &buf );
entityIndex = MSG_ReadShort( pbuf );
else entityIndex = 0;
pEnt = CL_GetEntityByIndex( entityIndex );
@@ -2049,197 +2069,197 @@ void CL_ParseTempEntity( sizebuf_t *msg )
CL_DecalShoot( CL_DecalIndex( decalIndex ), entityIndex, modelIndex, pos, type == TE_BSPDECAL ? FDECAL_PERMANENT : 0 );
break;
case TE_IMPLOSION:
pos[0] = MSG_ReadCoord( &buf );
pos[1] = MSG_ReadCoord( &buf );
pos[2] = MSG_ReadCoord( &buf );
scale = MSG_ReadByte( &buf );
count = MSG_ReadByte( &buf );
life = (float)(MSG_ReadByte( &buf ) * 0.1f);
pos[0] = MSG_ReadCoord( pbuf );
pos[1] = MSG_ReadCoord( pbuf );
pos[2] = MSG_ReadCoord( pbuf );
scale = MSG_ReadByte( pbuf );
count = MSG_ReadByte( pbuf );
life = (float)(MSG_ReadByte( pbuf ) * 0.1f);
R_Implosion( pos, scale, count, life );
break;
case TE_SPRITETRAIL:
pos[0] = MSG_ReadCoord( &buf );
pos[1] = MSG_ReadCoord( &buf );
pos[2] = MSG_ReadCoord( &buf );
pos2[0] = MSG_ReadCoord( &buf );
pos2[1] = MSG_ReadCoord( &buf );
pos2[2] = MSG_ReadCoord( &buf );
modelIndex = MSG_ReadShort( &buf );
count = MSG_ReadByte( &buf );
life = (float)MSG_ReadByte( &buf ) * 0.1f;
scale = (float)MSG_ReadByte( &buf );
pos[0] = MSG_ReadCoord( pbuf );
pos[1] = MSG_ReadCoord( pbuf );
pos[2] = MSG_ReadCoord( pbuf );
pos2[0] = MSG_ReadCoord( pbuf );
pos2[1] = MSG_ReadCoord( pbuf );
pos2[2] = MSG_ReadCoord( pbuf );
modelIndex = MSG_ReadShort( pbuf );
count = MSG_ReadByte( pbuf );
life = (float)MSG_ReadByte( pbuf ) * 0.1f;
scale = (float)MSG_ReadByte( pbuf );
if( !scale ) scale = 1.0f;
else scale *= 0.1f;
vel = (float)MSG_ReadByte( &buf ) * 10;
random = (float)MSG_ReadByte( &buf ) * 10;
vel = (float)MSG_ReadByte( pbuf ) * 10;
random = (float)MSG_ReadByte( pbuf ) * 10;
R_Sprite_Trail( type, pos, pos2, modelIndex, count, life, scale, random, 255, vel );
break;
case TE_SPRITE:
pos[0] = MSG_ReadCoord( &buf );
pos[1] = MSG_ReadCoord( &buf );
pos[2] = MSG_ReadCoord( &buf );
modelIndex = MSG_ReadShort( &buf );
scale = (float)MSG_ReadByte( &buf ) * 0.1f;
brightness = (float)MSG_ReadByte( &buf ) / 255.0f;
pos[0] = MSG_ReadCoord( pbuf );
pos[1] = MSG_ReadCoord( pbuf );
pos[2] = MSG_ReadCoord( pbuf );
modelIndex = MSG_ReadShort( pbuf );
scale = (float)MSG_ReadByte( pbuf ) * 0.1f;
brightness = (float)MSG_ReadByte( pbuf ) / 255.0f;
R_TempSprite( pos, vec3_origin, scale, modelIndex,
kRenderTransAdd, kRenderFxNone, brightness, 0.0, FTENT_SPRANIMATE );
break;
case TE_GLOWSPRITE:
pos[0] = MSG_ReadCoord( &buf );
pos[1] = MSG_ReadCoord( &buf );
pos[2] = MSG_ReadCoord( &buf );
modelIndex = MSG_ReadShort( &buf );
life = (float)MSG_ReadByte( &buf ) * 0.1f;
scale = (float)MSG_ReadByte( &buf ) * 0.1f;
brightness = (float)MSG_ReadByte( &buf ) / 255.0f;
pos[0] = MSG_ReadCoord( pbuf );
pos[1] = MSG_ReadCoord( pbuf );
pos[2] = MSG_ReadCoord( pbuf );
modelIndex = MSG_ReadShort( pbuf );
life = (float)MSG_ReadByte( pbuf ) * 0.1f;
scale = (float)MSG_ReadByte( pbuf ) * 0.1f;
brightness = (float)MSG_ReadByte( pbuf ) / 255.0f;
R_TempSprite( pos, vec3_origin, scale, modelIndex,
kRenderGlow, kRenderFxNoDissipation, brightness, life, FTENT_FADEOUT );
break;
case TE_STREAK_SPLASH:
pos[0] = MSG_ReadCoord( &buf );
pos[1] = MSG_ReadCoord( &buf );
pos[2] = MSG_ReadCoord( &buf );
pos2[0] = MSG_ReadCoord( &buf );
pos2[1] = MSG_ReadCoord( &buf );
pos2[2] = MSG_ReadCoord( &buf );
color = MSG_ReadByte( &buf );
count = MSG_ReadShort( &buf );
vel = (float)MSG_ReadShort( &buf );
random = (float)MSG_ReadShort( &buf );
pos[0] = MSG_ReadCoord( pbuf );
pos[1] = MSG_ReadCoord( pbuf );
pos[2] = MSG_ReadCoord( pbuf );
pos2[0] = MSG_ReadCoord( pbuf );
pos2[1] = MSG_ReadCoord( pbuf );
pos2[2] = MSG_ReadCoord( pbuf );
color = MSG_ReadByte( pbuf );
count = MSG_ReadShort( pbuf );
vel = (float)MSG_ReadShort( pbuf );
random = (float)MSG_ReadShort( pbuf );
R_StreakSplash( pos, pos2, color, count, vel, -random, random );
break;
case TE_DLIGHT:
dl = CL_AllocDlight( 0 );
dl->origin[0] = MSG_ReadCoord( &buf );
dl->origin[1] = MSG_ReadCoord( &buf );
dl->origin[2] = MSG_ReadCoord( &buf );
dl->radius = (float)(MSG_ReadByte( &buf ) * 10.0f);
dl->color.r = MSG_ReadByte( &buf );
dl->color.g = MSG_ReadByte( &buf );
dl->color.b = MSG_ReadByte( &buf );
dl->die = cl.time + (float)(MSG_ReadByte( &buf ) * 0.1f);
dl->decay = (float)(MSG_ReadByte( &buf ) * 10.0f);
dl->origin[0] = MSG_ReadCoord( pbuf );
dl->origin[1] = MSG_ReadCoord( pbuf );
dl->origin[2] = MSG_ReadCoord( pbuf );
dl->radius = (float)(MSG_ReadByte( pbuf ) * 10.0f);
dl->color.r = MSG_ReadByte( pbuf );
dl->color.g = MSG_ReadByte( pbuf );
dl->color.b = MSG_ReadByte( pbuf );
dl->die = cl.time + (float)(MSG_ReadByte( pbuf ) * 0.1f);
dl->decay = (float)(MSG_ReadByte( pbuf ) * 10.0f);
break;
case TE_ELIGHT:
dl = CL_AllocElight( MSG_ReadShort( &buf ));
dl->origin[0] = MSG_ReadCoord( &buf );
dl->origin[1] = MSG_ReadCoord( &buf );
dl->origin[2] = MSG_ReadCoord( &buf );
dl->radius = MSG_ReadCoord( &buf );
dl->color.r = MSG_ReadByte( &buf );
dl->color.g = MSG_ReadByte( &buf );
dl->color.b = MSG_ReadByte( &buf );
life = (float)MSG_ReadByte( &buf ) * 0.1f;
dl = CL_AllocElight( MSG_ReadShort( pbuf ));
dl->origin[0] = MSG_ReadCoord( pbuf );
dl->origin[1] = MSG_ReadCoord( pbuf );
dl->origin[2] = MSG_ReadCoord( pbuf );
dl->radius = MSG_ReadCoord( pbuf );
dl->color.r = MSG_ReadByte( pbuf );
dl->color.g = MSG_ReadByte( pbuf );
dl->color.b = MSG_ReadByte( pbuf );
life = (float)MSG_ReadByte( pbuf ) * 0.1f;
dl->die = cl.time + life;
dl->decay = MSG_ReadCoord( &buf );
dl->decay = MSG_ReadCoord( pbuf );
if( life != 0 ) dl->decay /= life;
break;
case TE_TEXTMESSAGE:
CL_ParseTextMessage( &buf );
CL_ParseTextMessage( pbuf );
break;
case TE_LINE:
case TE_BOX:
pos[0] = MSG_ReadCoord( &buf );
pos[1] = MSG_ReadCoord( &buf );
pos[2] = MSG_ReadCoord( &buf );
pos2[0] = MSG_ReadCoord( &buf );
pos2[1] = MSG_ReadCoord( &buf );
pos2[2] = MSG_ReadCoord( &buf );
life = (float)(MSG_ReadShort( &buf ) * 0.1f);
r = MSG_ReadByte( &buf );
g = MSG_ReadByte( &buf );
b = MSG_ReadByte( &buf );
pos[0] = MSG_ReadCoord( pbuf );
pos[1] = MSG_ReadCoord( pbuf );
pos[2] = MSG_ReadCoord( pbuf );
pos2[0] = MSG_ReadCoord( pbuf );
pos2[1] = MSG_ReadCoord( pbuf );
pos2[2] = MSG_ReadCoord( pbuf );
life = (float)(MSG_ReadShort( pbuf ) * 0.1f);
r = MSG_ReadByte( pbuf );
g = MSG_ReadByte( pbuf );
b = MSG_ReadByte( pbuf );
if( type == TE_LINE ) R_ParticleLine( pos, pos2, r, g, b, life );
else R_ParticleBox( pos, pos2, r, g, b, life );
break;
case TE_LARGEFUNNEL:
pos[0] = MSG_ReadCoord( &buf );
pos[1] = MSG_ReadCoord( &buf );
pos[2] = MSG_ReadCoord( &buf );
modelIndex = MSG_ReadShort( &buf );
flags = MSG_ReadShort( &buf );
pos[0] = MSG_ReadCoord( pbuf );
pos[1] = MSG_ReadCoord( pbuf );
pos[2] = MSG_ReadCoord( pbuf );
modelIndex = MSG_ReadShort( pbuf );
flags = MSG_ReadShort( pbuf );
R_LargeFunnel( pos, flags );
R_FunnelSprite( pos, modelIndex, flags );
break;
case TE_BLOODSTREAM:
case TE_BLOOD:
pos[0] = MSG_ReadCoord( &buf );
pos[1] = MSG_ReadCoord( &buf );
pos[2] = MSG_ReadCoord( &buf );
pos2[0] = MSG_ReadCoord( &buf );
pos2[1] = MSG_ReadCoord( &buf );
pos2[2] = MSG_ReadCoord( &buf );
color = MSG_ReadByte( &buf );
count = MSG_ReadByte( &buf );
pos[0] = MSG_ReadCoord( pbuf );
pos[1] = MSG_ReadCoord( pbuf );
pos[2] = MSG_ReadCoord( pbuf );
pos2[0] = MSG_ReadCoord( pbuf );
pos2[1] = MSG_ReadCoord( pbuf );
pos2[2] = MSG_ReadCoord( pbuf );
color = MSG_ReadByte( pbuf );
count = MSG_ReadByte( pbuf );
if( type == TE_BLOOD ) R_Blood( pos, pos2, color, count );
else R_BloodStream( pos, pos2, color, count );
break;
case TE_SHOWLINE:
pos[0] = MSG_ReadCoord( &buf );
pos[1] = MSG_ReadCoord( &buf );
pos[2] = MSG_ReadCoord( &buf );
pos2[0] = MSG_ReadCoord( &buf );
pos2[1] = MSG_ReadCoord( &buf );
pos2[2] = MSG_ReadCoord( &buf );
pos[0] = MSG_ReadCoord( pbuf );
pos[1] = MSG_ReadCoord( pbuf );
pos[2] = MSG_ReadCoord( pbuf );
pos2[0] = MSG_ReadCoord( pbuf );
pos2[1] = MSG_ReadCoord( pbuf );
pos2[2] = MSG_ReadCoord( pbuf );
R_ShowLine( pos, pos2 );
break;
case TE_FIZZ:
entityIndex = MSG_ReadShort( &buf );
modelIndex = MSG_ReadShort( &buf );
scale = MSG_ReadByte( &buf ); // same as density
entityIndex = MSG_ReadShort( pbuf );
modelIndex = MSG_ReadShort( pbuf );
scale = MSG_ReadByte( pbuf ); // same as density
pEnt = CL_GetEntityByIndex( entityIndex );
R_FizzEffect( pEnt, modelIndex, scale );
break;
case TE_MODEL:
pos[0] = MSG_ReadCoord( &buf );
pos[1] = MSG_ReadCoord( &buf );
pos[2] = MSG_ReadCoord( &buf );
pos2[0] = MSG_ReadCoord( &buf );
pos2[1] = MSG_ReadCoord( &buf );
pos2[2] = MSG_ReadCoord( &buf );
pos[0] = MSG_ReadCoord( pbuf );
pos[1] = MSG_ReadCoord( pbuf );
pos[2] = MSG_ReadCoord( pbuf );
pos2[0] = MSG_ReadCoord( pbuf );
pos2[1] = MSG_ReadCoord( pbuf );
pos2[2] = MSG_ReadCoord( pbuf );
ang[0] = 0.0f;
ang[1] = MSG_ReadAngle( &buf ); // yaw angle
ang[1] = MSG_ReadAngle( pbuf ); // yaw angle
ang[2] = 0.0f;
modelIndex = MSG_ReadShort( &buf );
flags = MSG_ReadByte( &buf ); // sound flags
life = (float)(MSG_ReadByte( &buf ) * 0.1f);
modelIndex = MSG_ReadShort( pbuf );
flags = MSG_ReadByte( pbuf ); // sound flags
life = (float)(MSG_ReadByte( pbuf ) * 0.1f);
R_TempModel( pos, pos2, ang, life, modelIndex, flags );
break;
case TE_EXPLODEMODEL:
pos[0] = MSG_ReadCoord( &buf );
pos[1] = MSG_ReadCoord( &buf );
pos[2] = MSG_ReadCoord( &buf );
vel = MSG_ReadCoord( &buf );
modelIndex = MSG_ReadShort( &buf );
count = MSG_ReadShort( &buf );
life = (float)(MSG_ReadByte( &buf ) * 0.1f);
pos[0] = MSG_ReadCoord( pbuf );
pos[1] = MSG_ReadCoord( pbuf );
pos[2] = MSG_ReadCoord( pbuf );
vel = MSG_ReadCoord( pbuf );
modelIndex = MSG_ReadShort( pbuf );
count = MSG_ReadShort( pbuf );
life = (float)(MSG_ReadByte( pbuf ) * 0.1f);
R_TempSphereModel( pos, vel, life, count, modelIndex );
break;
case TE_BREAKMODEL:
pos[0] = MSG_ReadCoord( &buf );
pos[1] = MSG_ReadCoord( &buf );
pos[2] = MSG_ReadCoord( &buf );
pos2[0] = MSG_ReadCoord( &buf );
pos2[1] = MSG_ReadCoord( &buf );
pos2[2] = MSG_ReadCoord( &buf );
ang[0] = MSG_ReadCoord( &buf );
ang[1] = MSG_ReadCoord( &buf );
ang[2] = MSG_ReadCoord( &buf );
random = (float)MSG_ReadByte( &buf ) * 10.0f;
modelIndex = MSG_ReadShort( &buf );
count = MSG_ReadByte( &buf );
life = (float)(MSG_ReadByte( &buf ) * 0.1f);
flags = MSG_ReadByte( &buf );
pos[0] = MSG_ReadCoord( pbuf );
pos[1] = MSG_ReadCoord( pbuf );
pos[2] = MSG_ReadCoord( pbuf );
pos2[0] = MSG_ReadCoord( pbuf );
pos2[1] = MSG_ReadCoord( pbuf );
pos2[2] = MSG_ReadCoord( pbuf );
ang[0] = MSG_ReadCoord( pbuf );
ang[1] = MSG_ReadCoord( pbuf );
ang[2] = MSG_ReadCoord( pbuf );
random = (float)MSG_ReadByte( pbuf ) * 10.0f;
modelIndex = MSG_ReadShort( pbuf );
count = MSG_ReadByte( pbuf );
life = (float)(MSG_ReadByte( pbuf ) * 0.1f);
flags = MSG_ReadByte( pbuf );
R_BreakModel( pos, pos2, ang, random, life, count, modelIndex, (char)flags );
break;
case TE_GUNSHOTDECAL:
pos[0] = MSG_ReadCoord( &buf );
pos[1] = MSG_ReadCoord( &buf );
pos[2] = MSG_ReadCoord( &buf );
entityIndex = MSG_ReadShort( &buf );
decalIndex = MSG_ReadByte( &buf );
pos[0] = MSG_ReadCoord( pbuf );
pos[1] = MSG_ReadCoord( pbuf );
pos[2] = MSG_ReadCoord( pbuf );
entityIndex = MSG_ReadShort( pbuf );
decalIndex = MSG_ReadByte( pbuf );
CL_DecalShoot( CL_DecalIndex( decalIndex ), entityIndex, 0, pos, 0 );
R_BulletImpactParticles( pos );
flags = COM_RandomLong( 0, 0x7fff );
@@ -2248,139 +2268,139 @@ void CL_ParseTempEntity( sizebuf_t *msg )
break;
case TE_SPRAY:
case TE_SPRITE_SPRAY:
pos[0] = MSG_ReadCoord( &buf );
pos[1] = MSG_ReadCoord( &buf );
pos[2] = MSG_ReadCoord( &buf );
pos2[0] = MSG_ReadCoord( &buf );
pos2[1] = MSG_ReadCoord( &buf );
pos2[2] = MSG_ReadCoord( &buf );
modelIndex = MSG_ReadShort( &buf );
count = MSG_ReadByte( &buf );
vel = (float)MSG_ReadByte( &buf );
random = (float)MSG_ReadByte( &buf );
pos[0] = MSG_ReadCoord( pbuf );
pos[1] = MSG_ReadCoord( pbuf );
pos[2] = MSG_ReadCoord( pbuf );
pos2[0] = MSG_ReadCoord( pbuf );
pos2[1] = MSG_ReadCoord( pbuf );
pos2[2] = MSG_ReadCoord( pbuf );
modelIndex = MSG_ReadShort( pbuf );
count = MSG_ReadByte( pbuf );
vel = (float)MSG_ReadByte( pbuf );
random = (float)MSG_ReadByte( pbuf );
if( type == TE_SPRAY )
{
flags = MSG_ReadByte( &buf ); // rendermode
flags = MSG_ReadByte( pbuf ); // rendermode
R_Spray( pos, pos2, modelIndex, count, vel, random, flags );
}
else R_Sprite_Spray( pos, pos2, modelIndex, count, vel * 2.0f, random );
break;
case TE_ARMOR_RICOCHET:
pos[0] = MSG_ReadCoord( &buf );
pos[1] = MSG_ReadCoord( &buf );
pos[2] = MSG_ReadCoord( &buf );
scale = (float)(MSG_ReadByte( &buf ) * 0.1f);
pos[0] = MSG_ReadCoord( pbuf );
pos[1] = MSG_ReadCoord( pbuf );
pos[2] = MSG_ReadCoord( pbuf );
scale = (float)(MSG_ReadByte( pbuf ) * 0.1f);
R_RicochetSprite( pos, cl_sprite_ricochet, 0.1f, scale );
R_RicochetSound( pos );
break;
case TE_PLAYERDECAL:
color = MSG_ReadByte( &buf ) - 1; // playernum
pos[0] = MSG_ReadCoord( &buf );
pos[1] = MSG_ReadCoord( &buf );
pos[2] = MSG_ReadCoord( &buf );
entityIndex = MSG_ReadShort( &buf );
decalIndex = MSG_ReadByte( &buf );
color = MSG_ReadByte( pbuf ) - 1; // playernum
pos[0] = MSG_ReadCoord( pbuf );
pos[1] = MSG_ReadCoord( pbuf );
pos[2] = MSG_ReadCoord( pbuf );
entityIndex = MSG_ReadShort( pbuf );
decalIndex = MSG_ReadByte( pbuf );
CL_PlayerDecal( color, decalIndex, entityIndex, pos );
break;
case TE_BUBBLES:
case TE_BUBBLETRAIL:
pos[0] = MSG_ReadCoord( &buf );
pos[1] = MSG_ReadCoord( &buf );
pos[2] = MSG_ReadCoord( &buf );
pos2[0] = MSG_ReadCoord( &buf );
pos2[1] = MSG_ReadCoord( &buf );
pos2[2] = MSG_ReadCoord( &buf );
scale = MSG_ReadCoord( &buf ); // water height
modelIndex = MSG_ReadShort( &buf );
count = MSG_ReadByte( &buf );
vel = MSG_ReadCoord( &buf );
pos[0] = MSG_ReadCoord( pbuf );
pos[1] = MSG_ReadCoord( pbuf );
pos[2] = MSG_ReadCoord( pbuf );
pos2[0] = MSG_ReadCoord( pbuf );
pos2[1] = MSG_ReadCoord( pbuf );
pos2[2] = MSG_ReadCoord( pbuf );
scale = MSG_ReadCoord( pbuf ); // water height
modelIndex = MSG_ReadShort( pbuf );
count = MSG_ReadByte( pbuf );
vel = MSG_ReadCoord( pbuf );
if( type == TE_BUBBLES ) R_Bubbles( pos, pos2, scale, modelIndex, count, vel );
else R_BubbleTrail( pos, pos2, scale, modelIndex, count, vel );
break;
case TE_BLOODSPRITE:
pos[0] = MSG_ReadCoord( &buf );
pos[1] = MSG_ReadCoord( &buf );
pos[2] = MSG_ReadCoord( &buf );
modelIndex = MSG_ReadShort( &buf ); // sprite #1
decalIndex = MSG_ReadShort( &buf ); // sprite #2
color = MSG_ReadByte( &buf );
scale = (float)MSG_ReadByte( &buf );
pos[0] = MSG_ReadCoord( pbuf );
pos[1] = MSG_ReadCoord( pbuf );
pos[2] = MSG_ReadCoord( pbuf );
modelIndex = MSG_ReadShort( pbuf ); // sprite #1
decalIndex = MSG_ReadShort( pbuf ); // sprite #2
color = MSG_ReadByte( pbuf );
scale = (float)MSG_ReadByte( pbuf );
R_BloodSprite( pos, color, modelIndex, decalIndex, scale );
break;
case TE_PROJECTILE:
pos[0] = MSG_ReadCoord( &buf );
pos[1] = MSG_ReadCoord( &buf );
pos[2] = MSG_ReadCoord( &buf );
pos2[0] = MSG_ReadCoord( &buf );
pos2[1] = MSG_ReadCoord( &buf );
pos2[2] = MSG_ReadCoord( &buf );
modelIndex = MSG_ReadShort( &buf );
life = MSG_ReadByte( &buf );
color = MSG_ReadByte( &buf ); // playernum
pos[0] = MSG_ReadCoord( pbuf );
pos[1] = MSG_ReadCoord( pbuf );
pos[2] = MSG_ReadCoord( pbuf );
pos2[0] = MSG_ReadCoord( pbuf );
pos2[1] = MSG_ReadCoord( pbuf );
pos2[2] = MSG_ReadCoord( pbuf );
modelIndex = MSG_ReadShort( pbuf );
life = MSG_ReadByte( pbuf );
color = MSG_ReadByte( pbuf ); // playernum
R_Projectile( pos, pos2, modelIndex, life, color, NULL );
break;
case TE_PLAYERSPRITES:
color = MSG_ReadShort( &buf ); // entitynum
modelIndex = MSG_ReadShort( &buf );
count = MSG_ReadByte( &buf );
random = (float)MSG_ReadByte( &buf );
color = MSG_ReadShort( pbuf ); // entitynum
modelIndex = MSG_ReadShort( pbuf );
count = MSG_ReadByte( pbuf );
random = (float)MSG_ReadByte( pbuf );
R_PlayerSprites( color, modelIndex, count, random );
break;
case TE_PARTICLEBURST:
pos[0] = MSG_ReadCoord( &buf );
pos[1] = MSG_ReadCoord( &buf );
pos[2] = MSG_ReadCoord( &buf );
scale = (float)MSG_ReadShort( &buf );
color = MSG_ReadByte( &buf );
life = (float)(MSG_ReadByte( &buf ) * 0.1f);
pos[0] = MSG_ReadCoord( pbuf );
pos[1] = MSG_ReadCoord( pbuf );
pos[2] = MSG_ReadCoord( pbuf );
scale = (float)MSG_ReadShort( pbuf );
color = MSG_ReadByte( pbuf );
life = (float)(MSG_ReadByte( pbuf ) * 0.1f);
R_ParticleBurst( pos, scale, color, life );
break;
case TE_FIREFIELD:
pos[0] = MSG_ReadCoord( &buf );
pos[1] = MSG_ReadCoord( &buf );
pos[2] = MSG_ReadCoord( &buf );
scale = (float)MSG_ReadShort( &buf );
modelIndex = MSG_ReadShort( &buf );
count = MSG_ReadByte( &buf );
flags = MSG_ReadByte( &buf );
life = (float)(MSG_ReadByte( &buf ) * 0.1f);
pos[0] = MSG_ReadCoord( pbuf );
pos[1] = MSG_ReadCoord( pbuf );
pos[2] = MSG_ReadCoord( pbuf );
scale = (float)MSG_ReadShort( pbuf );
modelIndex = MSG_ReadShort( pbuf );
count = MSG_ReadByte( pbuf );
flags = MSG_ReadByte( pbuf );
life = (float)(MSG_ReadByte( pbuf ) * 0.1f);
R_FireField( pos, scale, modelIndex, count, flags, life );
break;
case TE_PLAYERATTACHMENT:
color = MSG_ReadByte( &buf ); // playernum
scale = MSG_ReadCoord( &buf ); // height
modelIndex = MSG_ReadShort( &buf );
life = (float)(MSG_ReadShort( &buf ) * 0.1f);
color = MSG_ReadByte( pbuf ); // playernum
scale = MSG_ReadCoord( pbuf ); // height
modelIndex = MSG_ReadShort( pbuf );
life = (float)(MSG_ReadShort( pbuf ) * 0.1f);
R_AttachTentToPlayer( color, modelIndex, scale, life );
break;
case TE_KILLPLAYERATTACHMENTS:
color = MSG_ReadByte( &buf ); // playernum
color = MSG_ReadByte( pbuf ); // playernum
R_KillAttachedTents( color );
break;
case TE_MULTIGUNSHOT:
pos[0] = MSG_ReadCoord( &buf );
pos[1] = MSG_ReadCoord( &buf );
pos[2] = MSG_ReadCoord( &buf );
pos2[0] = MSG_ReadCoord( &buf ) * 0.1f;
pos2[1] = MSG_ReadCoord( &buf ) * 0.1f;
pos2[2] = MSG_ReadCoord( &buf ) * 0.1f;
ang[0] = MSG_ReadCoord( &buf ) * 0.01f;
ang[1] = MSG_ReadCoord( &buf ) * 0.01f;
pos[0] = MSG_ReadCoord( pbuf );
pos[1] = MSG_ReadCoord( pbuf );
pos[2] = MSG_ReadCoord( pbuf );
pos2[0] = MSG_ReadCoord( pbuf ) * 0.1f;
pos2[1] = MSG_ReadCoord( pbuf ) * 0.1f;
pos2[2] = MSG_ReadCoord( pbuf ) * 0.1f;
ang[0] = MSG_ReadCoord( pbuf ) * 0.01f;
ang[1] = MSG_ReadCoord( pbuf ) * 0.01f;
ang[2] = 0.0f;
count = MSG_ReadByte( &buf );
decalIndices[0] = MSG_ReadByte( &buf );
count = MSG_ReadByte( pbuf );
decalIndices[0] = MSG_ReadByte( pbuf );
R_MultiGunshot( pos, pos2, ang, count, 1, decalIndices );
break;
case TE_USERTRACER:
pos[0] = MSG_ReadCoord( &buf );
pos[1] = MSG_ReadCoord( &buf );
pos[2] = MSG_ReadCoord( &buf );
pos2[0] = MSG_ReadCoord( &buf );
pos2[1] = MSG_ReadCoord( &buf );
pos2[2] = MSG_ReadCoord( &buf );
life = (float)(MSG_ReadByte( &buf ) * 0.1f);
color = MSG_ReadByte( &buf );
scale = (float)(MSG_ReadByte( &buf ) * 0.1f);
pos[0] = MSG_ReadCoord( pbuf );
pos[1] = MSG_ReadCoord( pbuf );
pos[2] = MSG_ReadCoord( pbuf );
pos2[0] = MSG_ReadCoord( pbuf );
pos2[1] = MSG_ReadCoord( pbuf );
pos2[2] = MSG_ReadCoord( pbuf );
life = (float)(MSG_ReadByte( pbuf ) * 0.1f);
color = MSG_ReadByte( pbuf );
scale = (float)(MSG_ReadByte( pbuf ) * 0.1f);
R_UserTracerParticle( pos, pos2, life, color, scale, 0, NULL );
break;
default:
@@ -2389,7 +2409,7 @@ void CL_ParseTempEntity( sizebuf_t *msg )
}
// throw warning
if( MSG_CheckOverflow( &buf ))
if( MSG_CheckOverflow( pbuf ))
Con_DPrintf( S_WARN "%s: overflow TE message %i\n", __func__, type );
}
@@ -3113,4 +3133,3 @@ void CL_ClearEffects( void )
CL_ClearParticles ();
CL_ClearLightStyles ();
}

View File

@@ -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];
@@ -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 );
//
@@ -790,8 +784,8 @@ 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 );
@@ -868,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 );
@@ -890,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 );
@@ -911,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
//
@@ -975,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 );

View File

@@ -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 );
@@ -289,14 +305,14 @@ 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,11 +498,9 @@ 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;
}
@@ -495,19 +509,15 @@ static qboolean R_LoadProgs( const char *name )
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;
}
@@ -634,9 +644,6 @@ static void R_CollectRendererNames( void )
#endif
#if XASH_REF_SOFT_ENABLED
"soft",
#endif
#if XASH_REF_NULL_ENABLED
"null",
#endif
};
@@ -660,9 +667,6 @@ static void R_CollectRendererNames( void )
#endif
#if XASH_REF_SOFT_ENABLED
"Software",
#endif
#if XASH_REF_NULL_ENABLED
"Null Renderer",
#endif
};
@@ -674,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 );
@@ -724,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 )
@@ -742,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] );
@@ -751,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;
}

View File

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

View File

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

View File

@@ -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
@@ -359,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
@@ -397,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
@@ -431,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 );
@@ -489,14 +508,14 @@ 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, int channels, uint flags );
uint Sound_GetApproxWavePlayLen( const char *filepath );
qboolean Sound_SupportedFileFormat( const char *fileext );
@@ -561,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 );
@@ -651,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;
@@ -661,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 );
@@ -749,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( ))
@@ -798,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
//

View File

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

View File

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

View File

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

View File

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

View File

@@ -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[] =

View File

@@ -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,7 +76,7 @@ typedef struct
int infotableofs;
} hpak_header_t;
STATIC_ASSERT( sizeof( hpak_header_t ) == 12, "invalid hpak_header_t size" );
STATIC_CHECK_SIZEOF( hpak_header_t, 12, 12 );
typedef struct
{
@@ -85,7 +85,7 @@ typedef struct
int disksize;
} hpak_lump_t;
STATIC_ASSERT( sizeof( hpak_lump_t ) == 144, "invalid hpak_lump_t size" );
STATIC_CHECK_SIZEOF( hpak_lump_t, 144, 144 );
typedef struct
{

View File

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

View File

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

View File

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

View File

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

161
engine/common/munge.c Normal file
View File

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

View File

@@ -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 );
}
}
@@ -544,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;
}
@@ -580,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 )
@@ -590,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 )
@@ -622,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 )

View File

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

View File

@@ -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 ));
}
@@ -687,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 );
@@ -695,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 );
}
@@ -1098,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];
@@ -1135,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;
@@ -1158,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 ))
{
@@ -1228,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 );
@@ -1593,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 );
}
@@ -1606,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
{
@@ -1664,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 );
}
@@ -1712,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 );
@@ -1729,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 );
}
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -49,7 +49,8 @@ void Test_RunBuffer( void );
Test_RunCvar(); \
Test_RunIPFilter(); \
Test_RunBuffer(); \
Test_RunDelta();
Test_RunDelta(); \
Test_RunMunge();
#define TEST_LIST_0_CLIENT \
Test_RunCon(); \

View File

@@ -95,12 +95,7 @@ typedef struct customization_s
#define FCUST_WIPEDATA ( 1<<1 )
#define FCUST_IGNOREINIT ( 1<<2 )
#if !XASH_64BIT
STATIC_ASSERT( sizeof( customization_t ) == 164, "invalid customization_t size, broken API" );
STATIC_ASSERT( sizeof( resource_t ) == 136, "invalid resource_t size, broken API" );
#else
STATIC_ASSERT( sizeof( customization_t ) == 192, "invalid customization_t size, broken API" );
STATIC_ASSERT( sizeof( resource_t ) == 144, "invalid resource_t size, broken API" );
#endif
STATIC_CHECK_SIZEOF( customization_t, 164, 192 );
STATIC_CHECK_SIZEOF( resource_t, 136, 144 );
#endif // CUSTOM_H

View File

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

View File

@@ -1015,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;
@@ -1095,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;
}
@@ -1239,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

View File

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

View File

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

View File

@@ -643,12 +643,16 @@ Write ambient sounds into demo
*/
void SV_RestartAmbientSounds( void )
{
// TODO: we don't know sounds state on remote server
// as it's used only for demos, maybe this could be implemented on client side?
#if !XASH_DEDICATED
soundlist_t soundInfo[256];
string curtrack, looptrack;
int i, nSounds;
int position;
if( !SV_Active( )) return;
if( !SV_Active( ) || Host_IsDedicated( ))
return;
nSounds = S_GetCurrentStaticSounds( soundInfo, 256 );
@@ -663,13 +667,12 @@ void SV_RestartAmbientSounds( void )
SV_StartSound( SV_PEntityOfEntIndex( si->entnum, true ), CHAN_STATIC, si->name, si->volume, si->attenuation, 0, si->pitch );
}
#if !XASH_DEDICATED // TODO: ???
// restart soundtrack
if( S_StreamGetCurrentState( curtrack, sizeof( curtrack ), looptrack, sizeof( looptrack ), &position ))
{
SV_StartMusic( curtrack, looptrack, position );
}
#endif
#endif // !XASH_DEDICATED
}
/*
@@ -681,31 +684,25 @@ Write all the decals into demo
*/
void SV_RestartDecals( void )
{
// TODO: similar to SV_RestartAmbientSounds, this is only used for demo recording
// and better be reimplemented on client side
#if !XASH_DEDICATED
decallist_t *list;
int decalIndex;
int modelIndex;
sizebuf_t *msg;
int i, numdecals;
if( !SV_Active( )) return;
if( !SV_Active( ) || Host_IsDedicated( ))
return;
// g-cont. add space for studiodecals if present
list = (decallist_t *)Z_Calloc( sizeof( decallist_t ) * MAX_RENDER_DECALS * 2 );
#if !XASH_DEDICATED
if( !Host_IsDedicated() )
{
numdecals = ref.dllFuncs.R_CreateDecalList( list );
numdecals = ref.dllFuncs.R_CreateDecalList( list );
// remove decals from map
ref.dllFuncs.R_ClearAllDecals();
}
else
#endif // XASH_DEDICATED
{
// we probably running a dedicated server
numdecals = 0;
}
// remove decals from map
ref.dllFuncs.R_ClearAllDecals();
// write decals into reliable datagram
msg = SV_GetReliableDatagram();
@@ -728,6 +725,7 @@ void SV_RestartDecals( void )
}
Z_Free( list );
#endif // !XASH_DEDICATED
}
/*
@@ -3064,7 +3062,7 @@ void SV_SetStringArrayMode( qboolean dynamic )
#endif
}
#if XASH_64BIT && !XASH_WIN32 && !XASH_APPLE && !XASH_NSWITCH && !XASH_ANDROID
#if XASH_AMD64 && XASH_LINUX && !XASH_ANDROID
#define USE_MMAP
#include <sys/mman.h>
#endif
@@ -5115,6 +5113,8 @@ void SV_SpawnEntities( const char *mapname )
void SV_UnloadProgs( void )
{
pending_cvar_t *pending_cvars_list;
if( !svgame.hInstance )
return;
@@ -5124,6 +5124,8 @@ void SV_UnloadProgs( void )
/// SV_UnloadProgs will be disabled
//Mod_ClearUserData ();
pending_cvars_list = Cvar_PrepareToUnlink( FCVAR_EXTDLL );
if( svgame.dllFuncs2.pfnGameShutdown != NULL )
svgame.dllFuncs2.pfnGameShutdown ();
@@ -5141,7 +5143,7 @@ void SV_UnloadProgs( void )
// must unlink all game cvars,
// before pointers on them will be lost...
Cvar_Unlink( FCVAR_EXTDLL );
Cvar_UnlinkPendingCvars( pending_cvars_list );
Cmd_Unlink( CMD_SERVERDLL );
SV_FreeStringPool();

View File

@@ -363,6 +363,7 @@ loads external resource list
static void SV_CreateGenericResources( void )
{
string filename;
int i;
Q_strncpy( filename, sv.model_precache[1], sizeof( filename ));
COM_ReplaceExtension( filename, ".res", sizeof( filename ));
@@ -370,6 +371,16 @@ static void SV_CreateGenericResources( void )
SV_ReadResourceList( filename );
SV_ReadResourceList( "reslist.txt" );
for( i = 0; i < world.wadlist.count; i++ )
{
if( world.wadlist.wadusage[i] > 0 )
{
string wadname;
Q_snprintf( wadname, sizeof( wadname ), "%s.wad", world.wadlist.wadnames[i] );
SV_GenericIndex( wadname );
}
}
}
/*

View File

@@ -92,9 +92,9 @@ static CVAR_DEFINE_AUTO( sv_waterfriction, "1", FCVAR_SERVER|FCVAR_MOVEVARS, "ho
static CVAR_DEFINE_AUTO( sv_bounce, "1", FCVAR_SERVER|FCVAR_MOVEVARS, "bounce factor for entities with MOVETYPE_BOUNCE" );
static CVAR_DEFINE_AUTO( sv_stepsize, "18", FCVAR_SERVER|FCVAR_MOVEVARS, "how high you and NPS's can step up" );
CVAR_DEFINE_AUTO( sv_maxvelocity, "2000", FCVAR_MOVEVARS|FCVAR_UNLOGGED, "max velocity for all things in the world" );
static CVAR_DEFINE_AUTO( sv_zmax, "4096", FCVAR_SERVER|FCVAR_MOVEVARS|FCVAR_SPONLY, "maximum viewable distance" );
static CVAR_DEFINE_AUTO( sv_zmax, "4096", FCVAR_MOVEVARS|FCVAR_SPONLY, "maximum viewable distance" );
CVAR_DEFINE_AUTO( sv_wateramp, "0", FCVAR_MOVEVARS|FCVAR_UNLOGGED, "world waveheight factor" );
static CVAR_DEFINE( sv_footsteps, "mp_footsteps", "1", FCVAR_SERVER|FCVAR_MOVEVARS, "world gravity value" );
static CVAR_DEFINE( sv_footsteps, "mp_footsteps", "1", FCVAR_SERVER|FCVAR_MOVEVARS, "play foot steps for players" );
CVAR_DEFINE_AUTO( sv_skyname, "desert", FCVAR_MOVEVARS|FCVAR_UNLOGGED, "skybox name (can be dynamically changed in-game)" );
static CVAR_DEFINE_AUTO( sv_rollangle, "0", FCVAR_MOVEVARS|FCVAR_UNLOGGED|FCVAR_ARCHIVE, "how much to tilt the view when strafing" );
static CVAR_DEFINE_AUTO( sv_rollspeed, "200", FCVAR_MOVEVARS|FCVAR_UNLOGGED, "how much strafing is necessary to tilt the view" );
@@ -189,6 +189,9 @@ void SV_UpdateMovevars( qboolean initialize )
if( !initialize && !host.movevars_changed )
return;
// NOTE: this breaks Natural Selection mod on ns_machina map that uses model as sky
// it sets the value to 4000000 that even exceeds the coord limit
#if 0
// check range
if( sv_zmax.value < 256.0f ) Cvar_SetValue( "sv_zmax", 256.0f );
@@ -203,6 +206,7 @@ void SV_UpdateMovevars( qboolean initialize )
if( sv_zmax.value > 32767.0f )
Cvar_SetValue( "sv_zmax", 32767.0f );
}
#endif
svgame.movevars.gravity = sv_gravity.value;
svgame.movevars.stopspeed = sv_stopspeed.value;

View File

@@ -1170,41 +1170,36 @@ static void SaveClientState( SAVERESTOREDATA *pSaveData, const char *level, int
char name[MAX_QPATH];
int i, id, version;
char *pTokenData;
decallist_t *decalList;
SAVE_CLIENT header;
decallist_t *decalList = NULL;
SAVE_CLIENT header = { 0 };
file_t *pFile;
// clearing the saving buffer to reuse
SaveClear( pSaveData );
memset( &header, 0, sizeof( header ));
// g-cont. add space for studiodecals if present
decalList = (decallist_t *)Z_Calloc( sizeof( decallist_t ) * MAX_RENDER_DECALS * 2 );
header.entityCount = sv.num_static_entities;
// initialize client header
#if !XASH_DEDICATED
if( !Host_IsDedicated() )
if( !Host_IsDedicated( ))
{
header.decalCount = ref.dllFuncs.R_CreateDecalList( decalList );
}
else
#endif // XASH_DEDICATED
{
// we probably running a dedicated server
header.decalCount = 0;
}
header.entityCount = sv.num_static_entities;
// g-cont. add space for studiodecals if present
decalList = (decallist_t *)Mem_Calloc( host.mempool, sizeof( decallist_t ) * MAX_RENDER_DECALS * 2 );
if( !changelevel )
{
// sounds won't going across transition
header.soundCount = S_GetCurrentDynamicSounds( soundInfo, MAX_CHANNELS );
#if !XASH_DEDICATED
// music not reqiured to save position: it's just continue playing on a next level
S_StreamGetCurrentState( header.introTrack, sizeof( header.introTrack ), header.mainTrack, sizeof( header.mainTrack ), &header.trackPosition );
#endif
header.decalCount = ref.dllFuncs.R_CreateDecalList( decalList );
if( !changelevel ) // sounds won't going across transition
{
header.soundCount = S_GetCurrentDynamicSounds( soundInfo, MAX_CHANNELS );
// music not reqiured to save position: it's just continue playing on a next level
S_StreamGetCurrentState(
header.introTrack, sizeof( header.introTrack ),
header.mainTrack, sizeof( header.mainTrack ),
&header.trackPosition );
}
}
#endif // XASH_DEDICATED
// save viewentity to allow camera works after save\restore
if( SV_IsValidEdict( cl->pViewEntity ) && cl->pViewEntity != cl->edict )
@@ -1217,7 +1212,7 @@ static void SaveClientState( SAVERESTOREDATA *pSaveData, const char *level, int
svgame.dllFuncs.pfnSaveWriteFields( pSaveData, "ClientHeader", &header, gSaveClient, ARRAYSIZE( gSaveClient ));
// store decals
for( i = 0; i < header.decalCount; i++ )
for( i = 0; decalList != NULL && i < header.decalCount; i++ )
{
// NOTE: apply landmark offset only for brush entities without origin brushes
if( pSaveData->fUseLandmark && FBitSet( decalList[i].flags, FDECAL_USE_LANDMARK ))
@@ -1225,7 +1220,9 @@ static void SaveClientState( SAVERESTOREDATA *pSaveData, const char *level, int
svgame.dllFuncs.pfnSaveWriteFields( pSaveData, "DECALLIST", &decalList[i], gDecalEntry, ARRAYSIZE( gDecalEntry ));
}
Z_Free( decalList );
if( decalList )
Mem_Free( decalList );
// write client entities
for( i = 0; i < header.entityCount; i++ )

View File

@@ -72,7 +72,7 @@ typedef struct
int32_t version; // current version 2
} dsprite_t;
STATIC_ASSERT( sizeof( dsprite_t ) == 8, "invalid dsprite_t size" );
STATIC_CHECK_SIZEOF( dsprite_t, 8, 8 );
typedef struct
{
@@ -86,7 +86,7 @@ typedef struct
uint32_t synctype; // animation synctype, was synctype_t
} dsprite_q1_t;
STATIC_ASSERT( sizeof( dsprite_q1_t ) == 36, "invalid dsprite_q1_t size" );
STATIC_CHECK_SIZEOF( dsprite_q1_t, 36, 36 );
typedef struct
{
@@ -101,7 +101,7 @@ typedef struct
uint32_t synctype; // animation synctype, was synctype_t
} dsprite_hl_t;
STATIC_ASSERT( sizeof( dsprite_hl_t ) == 40, "invalid dsprite_hl_t size" );
STATIC_CHECK_SIZEOF( dsprite_hl_t, 40, 40 );
typedef struct
{
@@ -110,27 +110,27 @@ typedef struct
int32_t height;
} dspriteframe_t;
STATIC_ASSERT( sizeof( dspriteframe_t ) == 16, "invalid dspriteframe_t size" );
STATIC_CHECK_SIZEOF( dspriteframe_t, 16, 16 );
typedef struct
{
int32_t numframes;
} dspritegroup_t;
STATIC_ASSERT( sizeof( dspritegroup_t ) == 4, "invalid dspritegroup_t size" );
STATIC_CHECK_SIZEOF( dspritegroup_t, 4, 4 );
typedef struct
{
float interval;
} dspriteinterval_t;
STATIC_ASSERT( sizeof( dspriteinterval_t ) == 4, "invalid dspriteinterval_t size" );
STATIC_CHECK_SIZEOF( dspriteinterval_t, 4, 4 );
typedef struct
{
uint32_t type; // was frametype_t
} dframetype_t;
STATIC_ASSERT( sizeof( dframetype_t ) == 4, "invalid dframetype_t size" );
STATIC_CHECK_SIZEOF( dframetype_t, 4, 4 );
#endif//SPRITE_H

View File

@@ -110,6 +110,8 @@ def configure(conf):
conf.env.append_unique('CFLAGS', '-fsanitize=fuzzer-no-link')
conf.env.append_unique('LINKFLAGS', '-fsanitize=fuzzer')
conf.define('ENGINE_DLL', 1)
conf.define_cond('XASH_ENGINE_TESTS', conf.env.ENGINE_TESTS)
conf.define_cond('XASH_STATIC_LIBS', conf.env.STATIC_LINKING)
conf.define_cond('XASH_CUSTOM_SWAP', conf.options.CUSTOM_SWAP)
@@ -220,7 +222,7 @@ def build(bld):
'client/*.c',
'client/vgui/*.c',
'client/avi/*.c'])
libs += ['opus']
libs += ['opus', 'bzip2']
includes = ['server', 'client', 'client/vgui' ]

View File

@@ -125,6 +125,16 @@ static void FS_BackupFileName( file_t *file, const char *path, uint options ) {}
static void FS_InitMemory( void );
static void FS_Purge( file_t* file );
void _Mem_Free( void *data, const char *filename, int fileline )
{
g_engfuncs._Mem_Free( data, filename, fileline );
}
void *_Mem_Alloc( poolhandle_t poolptr, size_t size, qboolean clear, const char *filename, int fileline )
{
return g_engfuncs._Mem_Alloc( poolptr, size, clear, filename, fileline );
}
/*
=============================================================================
@@ -1412,34 +1422,34 @@ static qboolean FS_FindLibrary( const char *dllname, qboolean directpath, fs_dll
return true;
}
static poolhandle_t _Mem_AllocPool( const char *name, const char *filename, int fileline )
static poolhandle_t Mem_AllocPoolStub( const char *name, const char *filename, int fileline )
{
return (poolhandle_t)0xDEADC0DE;
}
static void _Mem_FreePool( poolhandle_t *poolptr, const char *filename, int fileline )
static void Mem_FreePoolStub( poolhandle_t *poolptr, const char *filename, int fileline )
{
// stub
}
static void *_Mem_Alloc( poolhandle_t poolptr, size_t size, qboolean clear, const char *filename, int fileline )
static void *Mem_AllocStub( poolhandle_t poolptr, size_t size, qboolean clear, const char *filename, int fileline )
{
void *ptr = malloc( size );
if( clear ) memset( ptr, 0, size );
return ptr;
}
static void *_Mem_Realloc( poolhandle_t poolptr, void *memptr, size_t size, qboolean clear, const char *filename, int fileline )
static void *Mem_ReallocStub( poolhandle_t poolptr, void *memptr, size_t size, qboolean clear, const char *filename, int fileline )
{
return realloc( memptr, size );
}
static void _Mem_Free( void *data, const char *filename, int fileline )
static void Mem_FreeStub( void *data, const char *filename, int fileline )
{
free( data );
}
static void _Con_Printf( const char *fmt, ... )
static void Con_PrintfStub( const char *fmt, ... )
{
va_list ap;
@@ -1448,7 +1458,7 @@ static void _Con_Printf( const char *fmt, ... )
va_end( ap );
}
static void _Sys_Error( const char *fmt, ... )
static void Sys_ErrorStub( const char *fmt, ... )
{
va_list ap;
@@ -1459,7 +1469,7 @@ static void _Sys_Error( const char *fmt, ... )
exit( 1 );
}
static void *Sys_GetNativeObject_stub( const char *object )
static void *Sys_GetNativeObjectStub( const char *object )
{
return NULL;
}
@@ -2524,7 +2534,7 @@ byte *FS_LoadFileMalloc( const char *path, fs_offset_t *filesizeptr, qboolean ga
byte *FS_LoadFile( const char *path, fs_offset_t *filesizeptr, qboolean gamedironly )
{
return FS_LoadFile_( path, filesizeptr, gamedironly, g_engfuncs._Mem_Alloc != _Mem_Alloc );
return FS_LoadFile_( path, filesizeptr, gamedironly, true );
}
qboolean CRC32_File( dword *crcvalue, const char *filename )
@@ -2936,14 +2946,6 @@ search_t *FS_Search( const char *pattern, int caseinsensitive, int gamedironly )
return search;
}
static const char *FS_ArchivePath( file_t *f )
{
if( f->searchpath )
return f->searchpath->filename;
return "plain";
}
static qboolean FS_IsArchiveExtensionSupported( const char *ext, uint flags )
{
int i;
@@ -2971,16 +2973,16 @@ void FS_InitMemory( void )
fs_interface_t g_engfuncs =
{
_Con_Printf,
_Con_Printf,
_Con_Printf,
_Sys_Error,
_Mem_AllocPool,
_Mem_FreePool,
_Mem_Alloc,
_Mem_Realloc,
_Mem_Free,
Sys_GetNativeObject_stub
Con_PrintfStub,
Con_PrintfStub,
Con_PrintfStub,
Sys_ErrorStub,
Mem_AllocPoolStub,
Mem_FreePoolStub,
Mem_AllocStub,
Mem_ReallocStub,
Mem_FreeStub,
Sys_GetNativeObjectStub,
};
static qboolean FS_InitInterface( int version, const fs_interface_t *engfuncs )

View File

@@ -217,8 +217,10 @@ typedef struct fs_interface_t
// memory
poolhandle_t (*_Mem_AllocPool)( const char *name, const char *filename, int fileline );
void (*_Mem_FreePool)( poolhandle_t *poolptr, const char *filename, int fileline );
void *(*_Mem_Alloc)( poolhandle_t poolptr, size_t size, qboolean clear, const char *filename, int fileline ) 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 );
// platform

View File

@@ -19,6 +19,7 @@ GNU General Public License for more details.
#ifndef FILESYSTEM_INTERNAL_H
#define FILESYSTEM_INTERNAL_H
#include <stdlib.h>
#include "xash3d_types.h"
#include "filesystem.h"
@@ -129,10 +130,10 @@ extern const fs_archive_t g_archives[];
#define GI FI.GameInfo
#define Mem_Malloc( pool, size ) g_engfuncs._Mem_Alloc( pool, size, false, __FILE__, __LINE__ )
#define Mem_Calloc( pool, size ) g_engfuncs._Mem_Alloc( pool, size, true, __FILE__, __LINE__ )
#define Mem_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 ) g_engfuncs._Mem_Realloc( pool, ptr, size, true, __FILE__, __LINE__ )
#define Mem_Free( mem ) g_engfuncs._Mem_Free( mem, __FILE__, __LINE__ )
#define Mem_Free( mem ) _Mem_Free( mem, __FILE__, __LINE__ )
#define Mem_AllocPool( name ) g_engfuncs._Mem_AllocPool( name, __FILE__, __LINE__ )
#define Mem_FreePool( pool ) g_engfuncs._Mem_FreePool( pool, __FILE__, __LINE__ )
@@ -148,6 +149,9 @@ extern const fs_archive_t g_archives[];
qboolean FS_InitStdio( qboolean caseinsensitive, const char *rootdir, const char *basedir, const char *gamedir, const char *rodir );
void FS_ShutdownStdio( void );
searchpath_t *FS_AddArchive_Fullpath( const fs_archive_t *archive, const char *file, int flags );
void _Mem_Free( void *data, const char *filename, int fileline );
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;
// search path utils
void FS_Rescan( void );
@@ -155,7 +159,8 @@ void FS_ClearSearchPath( void );
void FS_AllowDirectPaths( qboolean enable );
void FS_AddGameDirectory( const char *dir, uint flags );
void FS_AddGameHierarchy( const char *dir, uint flags );
search_t *FS_Search( const char *pattern, int caseinsensitive, int gamedironly );
search_t *FS_Search( const char *pattern, int caseinsensitive, int gamedironly )
MALLOC_LIKE( _Mem_Free, 1 ) WARN_UNUSED_RESULT;
int FS_SetCurrentDirectory( const char *path );
void FS_Path_f( void );
@@ -163,14 +168,15 @@ void FS_Path_f( void );
void FS_LoadGameInfo( const char *rootfolder );
// file ops
file_t *FS_Open( const char *filepath, const char *mode, qboolean gamedironly );
int FS_Close( file_t *file );
file_t *FS_Open( const char *filepath, const char *mode, qboolean gamedironly )
MALLOC_LIKE( FS_Close, 1 ) WARN_UNUSED_RESULT;
fs_offset_t FS_Write( file_t *file, const void *data, size_t datasize );
fs_offset_t FS_Read( file_t *file, void *buffer, size_t buffersize );
int FS_Seek( file_t *file, fs_offset_t offset, int whence );
fs_offset_t FS_Tell( file_t *file );
qboolean FS_Eof( file_t *file );
int FS_Flush( file_t *file );
int FS_Close( file_t *file );
int FS_Gets( file_t *file, char *string, size_t bufsize );
int FS_UnGetc( file_t *file, char c );
int FS_Getc( file_t *file );
@@ -181,9 +187,12 @@ fs_offset_t FS_FileLength( file_t *f );
qboolean FS_FileCopy( file_t *pOutput, file_t *pInput, int fileSize );
// file buffer ops
byte *FS_LoadFile( const char *path, fs_offset_t *filesizeptr, qboolean gamedironly );
byte *FS_LoadFileMalloc( const char *path, fs_offset_t *filesizeptr, qboolean gamedironly );
byte *FS_LoadDirectFile( const char *path, fs_offset_t *filesizeptr );
byte *FS_LoadFile( const char *path, fs_offset_t *filesizeptr, qboolean gamedironly )
MALLOC_LIKE( _Mem_Free, 1 ) WARN_UNUSED_RESULT;
byte *FS_LoadFileMalloc( const char *path, fs_offset_t *filesizeptr, qboolean gamedironly )
MALLOC_LIKE( free, 1 ) WARN_UNUSED_RESULT;
byte *FS_LoadDirectFile( const char *path, fs_offset_t *filesizeptr )
MALLOC_LIKE( _Mem_Free, 1 ) WARN_UNUSED_RESULT;
qboolean FS_WriteFile( const char *filename, const void *data, fs_offset_t len );
// file hashing

View File

@@ -36,7 +36,9 @@ extern fs_globals_t *FI;
#define FS_AllowDirectPaths (*g_fsapi.AllowDirectPaths)
#define FS_AddGameDirectory (*g_fsapi.AddGameDirectory)
#define FS_AddGameHierarchy (*g_fsapi.AddGameHierarchy)
#ifndef FSCALLBACK_OVERRIDE_MALLOC_LIKE
#define FS_Search (*g_fsapi.Search)
#endif
#define FS_SetCurrentDirectory (*g_fsapi.SetCurrentDirectory)
#define FS_Path_f (*g_fsapi.Path_f)
@@ -44,14 +46,16 @@ extern fs_globals_t *FI;
#define FS_LoadGameInfo (*g_fsapi.LoadGameInfo)
// file ops
#ifndef FSCALLBACK_OVERRIDE_MALLOC_LIKE
#define FS_Open (*g_fsapi.Open)
#define FS_Close (*g_fsapi.Close)
#endif
#define FS_Write (*g_fsapi.Write)
#define FS_Read (*g_fsapi.Read)
#define FS_Seek (*g_fsapi.Seek)
#define FS_Tell (*g_fsapi.Tell)
#define FS_Eof (*g_fsapi.Eof)
#define FS_Flush (*g_fsapi.Flush)
#define FS_Close (*g_fsapi.Close)
#define FS_Gets (*g_fsapi.Gets)
#define FS_UnGetc (*g_fsapi.UnGetc)
#define FS_Getc (*g_fsapi.Getc)
@@ -62,8 +66,10 @@ extern fs_globals_t *FI;
#define FS_FileCopy (*g_fsapi.FileCopy)
// file buffer ops
#ifndef FSCALLBACK_OVERRIDE_MALLOC_LIKE
#define FS_LoadFile (*g_fsapi.LoadFile)
#define FS_LoadDirectFile (*g_fsapi.LoadDirectFile)
#endif
#define FS_WriteFile (*g_fsapi.WriteFile)
// file hashing

View File

@@ -299,7 +299,6 @@ static zip_t *FS_LoadZip( const char *zipfile, int *error )
if( error )
*error = ZIP_LOAD_BAD_HEADER;
Mem_Free( info );
FS_CloseZIP( zip );
return NULL;
}
@@ -316,7 +315,6 @@ static zip_t *FS_LoadZip( const char *zipfile, int *error )
if( error )
*error = ZIP_LOAD_CORRUPTED;
Mem_Free( info );
FS_CloseZIP( zip );
return NULL;
}
@@ -364,7 +362,6 @@ static zip_t *FS_LoadZip( const char *zipfile, int *error )
if( error )
*error = ZIP_LOAD_CORRUPTED;
Mem_Free( info );
FS_CloseZIP( zip );
return NULL;
}

View File

@@ -288,7 +288,6 @@ const char* Q_timestamp( int format )
static string timestamp;
time_t crt_time;
const struct tm *crt_tm;
string timestring;
time( &crt_time );
crt_tm = localtime( &crt_time );
@@ -297,33 +296,31 @@ const char* Q_timestamp( int format )
{
case TIME_FULL:
// Build the full timestamp (ex: "Apr03 2007 [23:31.55]");
strftime( timestring, sizeof( timestring ), "%b%d %Y [%H:%M.%S]", crt_tm );
strftime( timestamp, sizeof( timestamp ), "%b%d %Y [%H:%M.%S]", crt_tm );
break;
case TIME_DATE_ONLY:
// Build the date stamp only (ex: "Apr03 2007");
strftime( timestring, sizeof( timestring ), "%b%d %Y", crt_tm );
strftime( timestamp, sizeof( timestamp ), "%b%d %Y", crt_tm );
break;
case TIME_TIME_ONLY:
// Build the time stamp only (ex: "23:31.55");
strftime( timestring, sizeof( timestring ), "%H:%M.%S", crt_tm );
strftime( timestamp, sizeof( timestamp ), "%H:%M.%S", crt_tm );
break;
case TIME_NO_SECONDS:
// Build the time stamp exclude seconds (ex: "13:46");
strftime( timestring, sizeof( timestring ), "%H:%M", crt_tm );
strftime( timestamp, sizeof( timestamp ), "%H:%M", crt_tm );
break;
case TIME_YEAR_ONLY:
// Build the date stamp year only (ex: "2006");
strftime( timestring, sizeof( timestring ), "%Y", crt_tm );
strftime( timestamp, sizeof( timestamp ), "%Y", crt_tm );
break;
case TIME_FILENAME:
// Build a timestamp that can use for filename (ex: "Nov2006-26 (19.14.28)");
strftime( timestring, sizeof( timestring ), "%b%Y-%d_%H.%M.%S", crt_tm );
strftime( timestamp, sizeof( timestamp ), "%b%Y-%d_%H.%M.%S", crt_tm );
break;
default: return NULL;
}
Q_strncpy( timestamp, timestring, sizeof( timestamp ));
return timestamp;
}

View File

@@ -19,13 +19,6 @@ GNU General Public License for more details.
#include "com_model.h"
#include "xash3d_mathlib.h"
const matrix3x4 m_matrix3x4_identity =
{
{ 1, 0, 0, 0 }, // PITCH [forward], org[0]
{ 0, 1, 0, 0 }, // YAW [right] , org[1]
{ 0, 0, 1, 0 }, // ROLL [up] , org[2]
};
/*
========================================================================
@@ -225,14 +218,6 @@ void Matrix3x4_TransformAABB( const matrix3x4 world, const vec3_t mins, const ve
VectorAdd( worldCenter, worldExtents, absmax );
}
const matrix4x4 m_matrix4x4_identity =
{
{ 1, 0, 0, 0 }, // PITCH
{ 0, 1, 0, 0 }, // YAW
{ 0, 0, 1, 0 }, // ROLL
{ 0, 0, 0, 1 }, // ORIGIN
};
/*
========================================================================

View File

@@ -2,7 +2,7 @@
#include "crtlib.h"
#include <stdio.h>
int Test_ExtractFilePath( void )
static int Test_ExtractFilePath( void )
{
char dst[64];
const char *strings[] =

View File

@@ -18,15 +18,14 @@ GNU General Public License for more details.
#include "com_model.h"
#include "xash3d_mathlib.h"
#include "eiface.h"
#include "studio.h"
#define NUM_HULL_ROUNDS ARRAYSIZE( hull_table )
#define HULL_PRECISION 4
vec3_t vec3_origin = { 0, 0, 0 };
static const word hull_table[] = { 2, 4, 6, 8, 12, 16, 18, 24, 28, 32, 36, 40, 48, 54, 56, 60, 64, 72, 80, 112, 120, 128, 140, 176 };
static word hull_table[] = { 2, 4, 6, 8, 12, 16, 18, 24, 28, 32, 36, 40, 48, 54, 56, 60, 64, 72, 80, 112, 120, 128, 140, 176 };
int boxpnt[6][4] =
const int boxpnt[6][4] =
{
{ 0, 4, 6, 2 }, // +X
{ 0, 1, 5, 4 }, // +Y
@@ -42,18 +41,7 @@ const float m_bytenormals[NUMVERTEXNORMALS][3] =
#include "anorms.h"
};
/*
=================
anglemod
=================
*/
float anglemod( float a )
{
a = (360.0f / 65536) * ((int)(a*(65536/360.0f)) & 65535);
return a;
}
word FloatToHalf( float v )
uint16_t FloatToHalf( float v )
{
unsigned int i = FloatAsUint( v );
unsigned int e = (i >> 23) & 0x00ff;
@@ -69,7 +57,7 @@ word FloatToHalf( float v )
return h;
}
float HalfToFloat( word h )
float HalfToFloat( uint16_t h )
{
unsigned int f = (h << 16) & 0x80000000;
unsigned int em = h & 0x7fff;
@@ -151,57 +139,6 @@ void RoundUpHullSize( vec3_t size )
}
}
/*
=================
SignbitsForPlane
fast box on planeside test
=================
*/
int SignbitsForPlane( const vec3_t normal )
{
int bits, i;
for( bits = i = 0; i < 3; i++ )
if( normal[i] < 0.0f ) bits |= 1<<i;
return bits;
}
/*
=================
PlaneTypeForNormal
=================
*/
int PlaneTypeForNormal( const vec3_t normal )
{
if( normal[0] == 1.0f )
return PLANE_X;
if( normal[1] == 1.0f )
return PLANE_Y;
if( normal[2] == 1.0f )
return PLANE_Z;
return PLANE_NONAXIAL;
}
/*
=================
NearestPOW
=================
*/
int NearestPOW( int value, qboolean roundDown )
{
int n = 1;
if( value <= 0 ) return 1;
while( n < value ) n <<= 1;
if( roundDown )
{
if( n > value ) n >>= 1;
}
return n;
}
/*
=================
rsqrt
@@ -224,43 +161,6 @@ float rsqrt( float number )
return y;
}
/*
==============
VectorCompareEpsilon
==============
*/
qboolean VectorCompareEpsilon( const vec3_t vec1, const vec3_t vec2, vec_t epsilon )
{
vec_t ax, ay, az;
ax = fabs( vec1[0] - vec2[0] );
ay = fabs( vec1[1] - vec2[1] );
az = fabs( vec1[2] - vec2[2] );
if(( ax <= epsilon ) && ( ay <= epsilon ) && ( az <= epsilon ))
return true;
return false;
}
float VectorNormalizeLength2( const vec3_t v, vec3_t out )
{
float length, ilength;
length = v[0] * v[0] + v[1] * v[1] + v[2] * v[2];
length = sqrt( length );
if( length )
{
ilength = 1.0f / length;
out[0] = v[0] * ilength;
out[1] = v[1] * ilength;
out[2] = v[2] * ilength;
}
return length;
}
void VectorVectors( const vec3_t forward, vec3_t right, vec3_t up )
{
float d;
@@ -276,42 +176,6 @@ void VectorVectors( const vec3_t forward, vec3_t right, vec3_t up )
VectorNormalize( up );
}
/*
=================
AngleVectors
=================
*/
void GAME_EXPORT AngleVectors( const vec3_t angles, vec3_t forward, vec3_t right, vec3_t up )
{
float sr, sp, sy, cr, cp, cy;
SinCos( DEG2RAD( angles[YAW] ), &sy, &cy );
SinCos( DEG2RAD( angles[PITCH] ), &sp, &cp );
SinCos( DEG2RAD( angles[ROLL] ), &sr, &cr );
if( forward )
{
forward[0] = cp * cy;
forward[1] = cp * sy;
forward[2] = -sp;
}
if( right )
{
right[0] = (-1.0f * sr * sp * cy + -1.0f * cr * -sy );
right[1] = (-1.0f * sr * sp * sy + -1.0f * cr * cy );
right[2] = (-1.0f * sr * cp);
}
if( up )
{
up[0] = (cr * sp * cy + -sr * -sy );
up[1] = (cr * sp * sy + -sr * cy );
up[2] = (cr * cp);
}
}
/*
=================
VectorAngles
@@ -384,39 +248,6 @@ void VectorsAngles( const vec3_t forward, const vec3_t right, const vec3_t up, v
//
// bounds operations
//
/*
=================
AddPointToBounds
=================
*/
void AddPointToBounds( const vec3_t v, vec3_t mins, vec3_t maxs )
{
float val;
int i;
for( i = 0; i < 3; i++ )
{
val = v[i];
if( val < mins[i] ) mins[i] = val;
if( val > maxs[i] ) maxs[i] = val;
}
}
/*
=================
ExpandBounds (not used anywhere?)
=================
*/
void ExpandBounds( vec3_t mins, vec3_t maxs, float offset )
{
mins[0] -= offset;
mins[1] -= offset;
mins[2] -= offset;
maxs[0] += offset;
maxs[1] += offset;
maxs[2] += offset;
}
/*
=================
SphereIntersect
@@ -457,67 +288,9 @@ void PlaneIntersect( const mplane_t *plane, const vec3_t p0, const vec3_t p1, ve
VectorMA( p0, sect, p1, out );
}
/*
=================
RadiusFromBounds
=================
*/
float RadiusFromBounds( const vec3_t mins, const vec3_t maxs )
{
vec3_t corner;
int i;
for( i = 0; i < 3; i++ )
{
corner[i] = fabs( mins[i] ) > fabs( maxs[i] ) ? fabs( mins[i] ) : fabs( maxs[i] );
}
return VectorLength( corner );
}
//
// studio utils
//
/*
====================
AngleQuaternion
====================
*/
void AngleQuaternion( const vec3_t angles, vec4_t q, qboolean studio )
{
float sr, sp, sy, cr, cp, cy;
if( studio )
{
SinCos( angles[ROLL] * 0.5f, &sy, &cy );
SinCos( angles[YAW] * 0.5f, &sp, &cp );
SinCos( angles[PITCH] * 0.5f, &sr, &cr );
}
else
{
SinCos( DEG2RAD( angles[YAW] ) * 0.5f, &sy, &cy );
SinCos( DEG2RAD( angles[PITCH] ) * 0.5f, &sp, &cp );
SinCos( DEG2RAD( angles[ROLL] ) * 0.5f, &sr, &cr );
}
q[0] = sr * cp * cy - cr * sp * sy; // X
q[1] = cr * sp * cy + sr * cp * sy; // Y
q[2] = cr * cp * sy - sr * sp * cy; // Z
q[3] = cr * cp * cy + sr * sp * sy; // W
}
/*
====================
QuaternionAngle
====================
*/
void QuaternionAngle( const vec4_t q, vec3_t angles )
{
matrix3x4 mat;
Matrix3x4_FromOriginQuat( mat, q, vec3_origin );
Matrix3x4_AnglesFromMatrix( mat, angles );
}
/*
====================
@@ -680,25 +453,6 @@ int BoxOnPlaneSide( const vec3_t emins, const vec3_t emaxs, const mplane_t *p )
return sides;
}
/*
====================
StudioSlerpBones
====================
*/
void R_StudioSlerpBones( int numbones, vec4_t q1[], float pos1[][3], const vec4_t q2[], const float pos2[][3], float s )
{
int i;
s = bound( 0.0f, s, 1.0f );
for( i = 0; i < numbones; i++ )
{
QuaternionSlerp( q1[i], q2[i], s, q1[i] );
VectorLerp( pos1[i], s, pos2[i], pos1[i] );
}
}
/*
====================
StudioCalcBoneQuaternion

View File

@@ -23,74 +23,65 @@ GNU General Public License for more details.
#include "build.h"
#include "xash3d_types.h"
#include "const.h"
#include "com_model.h"
#include "studio.h"
/*
===========================
CONSTANTS AND HELPER MACROS
===========================
*/
// euler angle order
#define PITCH 0
#define YAW 1
#define ROLL 2
#define PITCH 0
#define YAW 1
#define ROLL 2
#ifndef M_PI
#define M_PI (double)3.14159265358979323846
#define M_PI (double)3.14159265358979323846
#endif
#ifndef M_PI2
#define M_PI2 ((double)(M_PI * 2))
#endif
#define M_PI2 ((double)(M_PI * 2))
#define M_PI_F ((float)(M_PI))
#define M_PI2_F ((float)(M_PI2))
#define M_PI_F ((float)(M_PI))
#define M_PI2_F ((float)(M_PI2))
#define RAD2DEG( x ) ((double)(x) * (double)(180.0 / M_PI))
#define DEG2RAD( x ) ((double)(x) * (double)(M_PI / 180.0))
#define RAD2DEG( x ) ((double)(x) * (double)(180.0 / M_PI))
#define DEG2RAD( x ) ((double)(x) * (double)(M_PI / 180.0))
#define NUMVERTEXNORMALS 162
#define NUMVERTEXNORMALS 162
#define BOGUS_RANGE ((vec_t)114032.64) // world.size * 1.74
#define BOGUS_RANGE ((vec_t)114032.64) // world.size * 1.74
#define SIDE_FRONT 0
#define SIDE_BACK 1
#define SIDE_ON 2
#define SIDE_CROSS -2
#define SIDE_FRONT 0
#define SIDE_BACK 1
#define SIDE_ON 2
#define SIDE_CROSS -2
#define PLANE_X 0 // 0 - 2 are axial planes
#define PLANE_Y 1 // 3 needs alternate calc
#define PLANE_Z 2
#define PLANE_NONAXIAL 3
#define PLANE_X 0 // 0 - 2 are axial planes
#define PLANE_Y 1 // 3 needs alternate calc
#define PLANE_Z 2
#define PLANE_NONAXIAL 3
#define EQUAL_EPSILON 0.001f
#define STOP_EPSILON 0.1f
#define ON_EPSILON 0.1f
#define EQUAL_EPSILON 0.001f
#define STOP_EPSILON 0.1f
#define ON_EPSILON 0.1f
#define RAD_TO_STUDIO (32768.0 / M_PI)
#define STUDIO_TO_RAD (M_PI / 32768.0)
#define RAD_TO_STUDIO (32768.0 / M_PI)
#define STUDIO_TO_RAD (M_PI / 32768.0)
#define INV127F ( 1.0f / 127.0f )
#define INV255F ( 1.0f / 255.0f )
#define MAKE_SIGNED( x ) ((( x ) * INV127F ) - 1.0f )
#define INV127F ( 1.0f / 127.0f )
#define INV255F ( 1.0f / 255.0f )
#define MAKE_SIGNED( x ) ((( x ) * INV127F ) - 1.0f )
#define Q_min( a, b ) (((a) < (b)) ? (a) : (b))
#define Q_max( a, b ) (((a) > (b)) ? (a) : (b))
#define Q_min( a, b ) (((a) < (b)) ? (a) : (b))
#define Q_max( a, b ) (((a) > (b)) ? (a) : (b))
#define Q_equal_e( a, b, e ) (((a) >= ((b) - (e))) && ((a) <= ((b) + (e))))
#define Q_equal( a, b ) Q_equal_e( a, b, EQUAL_EPSILON )
#define Q_recip( a ) ((float)(1.0f / (float)(a)))
#define Q_floor( a ) ((float)(int)(a))
#define Q_ceil( a ) ((float)(int)((a) + 1))
#define Q_round( x, y ) (floor( x / y + 0.5f ) * y )
#define Q_rint(x) ((x) < 0.0f ? ((int)((x)-0.5f)) : ((int)((x)+0.5f)))
#ifdef XASH_IRIX
#undef isnan
#endif
#ifdef isnan // check for C99 isnan
#define IS_NAN isnan
#else
#define IS_NAN(x) (((*(int *)&x) & (255<<23)) == (255<<23))
#endif
#define ALIGN( x, a ) ((( x ) + (( size_t )( a ) - 1 )) & ~(( size_t )( a ) - 1 ))
#define Q_floor( a ) ((float)(int)(a))
#define Q_ceil( a ) ((float)(int)((a) + 1))
#define Q_round( x, y ) (floor( x / y + 0.5f ) * y )
#define Q_rint(x) ((x) < 0.0f ? ((int)((x)-0.5f)) : ((int)((x)+0.5f)))
#define ALIGN( x, a ) ((( x ) + (( size_t )( a ) - 1 )) & ~(( size_t )( a ) - 1 ))
#define VectorIsNAN(v) (IS_NAN(v[0]) || IS_NAN(v[1]) || IS_NAN(v[2]))
#define DotProduct(x,y) ((x)[0]*(y)[0]+(x)[1]*(y)[1]+(x)[2]*(y)[2])
@@ -118,8 +109,11 @@ GNU General Public License for more details.
#define Vector2Average(a,b,o) ((o)[0]=((a)[0]+(b)[0])*0.5f,(o)[1]=((a)[1]+(b)[1])*0.5f)
#define VectorAverage(a,b,o) ((o)[0]=((a)[0]+(b)[0])*0.5f,(o)[1]=((a)[1]+(b)[1])*0.5f,(o)[2]=((a)[2]+(b)[2])*0.5f)
#define Vector2Set(v, x, y) ((v)[0]=(x),(v)[1]=(y))
#define Vector2Unpack(v, x, y) ((x)=(v)[0],(y)=(v)[1])
#define VectorSet(v, x, y, z) ((v)[0]=(x),(v)[1]=(y),(v)[2]=(z))
#define Vector4Set(v, a, b, c, d) ((v)[0]=(a),(v)[1]=(b),(v)[2]=(c),(v)[3] = (d))
#define VectorUnpack(v, x, y, z) ((x)=(v)[0],(y)=(v)[1],(z)=(v)[2])
#define Vector4Set(v, a, b, c, d) ((v)[0]=(a),(v)[1]=(b),(v)[2]=(c),(v)[3]=(d))
#define Vector4Unpack(v, a, b, c, d) ((a)=(v)[0],(b)=(v)[1],(c)=(v)[2],(d)=(v)[3])
#define VectorClear(x) ((x)[0]=(x)[1]=(x)[2]=0)
#define Vector2Lerp( v1, lerp, v2, c ) ((c)[0] = (v1)[0] + (lerp) * ((v2)[0] - (v1)[0]), (c)[1] = (v1)[1] + (lerp) * ((v2)[1] - (v1)[1]))
#define VectorLerp( v1, lerp, v2, c ) ((c)[0] = (v1)[0] + (lerp) * ((v2)[0] - (v1)[0]), (c)[1] = (v1)[1] + (lerp) * ((v2)[1] - (v1)[1]), (c)[2] = (v1)[2] + (lerp) * ((v2)[2] - (v1)[2]))
@@ -138,9 +132,95 @@ GNU General Public License for more details.
#define PlaneDiff(point,plane) (((plane)->type < 3 ? (point)[(plane)->type] : DotProduct((point), (plane)->normal)) - (plane)->dist)
#define bound( min, num, max ) ((num) >= (min) ? ((num) < (max) ? (num) : (max)) : (min))
/*
===========================
CONSTANTS GLOBALS
===========================
*/
// a1ba: we never return pointers to these globals
// so help compiler optimize constants away
#define vec3_origin ((vec3_t){ 0.0f, 0.0f, 0.0f })
#define m_matrix3x4_identity ((matrix3x4) { \
{ 1.0f, 0.0f, 0.0f, 0.0f }, \
{ 0.0f, 1.0f, 0.0f, 0.0f }, \
{ 0.0f, 0.0f, 1.0f, 0.0f }} )
#define m_matrix4x4_identity ((matrix4x4) { \
{ 1.0f, 0.0f, 0.0f, 0.0f }, \
{ 0.0f, 1.0f, 0.0f, 0.0f }, \
{ 0.0f, 0.0f, 1.0f, 0.0f }, \
{ 0.0f, 0.0f, 0.0f, 1.0f }} )
extern const int boxpnt[6][4];
extern const float m_bytenormals[NUMVERTEXNORMALS][3];
/*
===========================
MATH FUNCTIONS
===========================
*/
typedef struct mplane_s mplane_t;
typedef struct mstudiobone_s mstudiobone_t;
typedef struct mstudioanim_s mstudioanim_t;
float rsqrt( float number );
uint16_t FloatToHalf( float v );
float HalfToFloat( uint16_t h );
void RoundUpHullSize( vec3_t size );
void VectorVectors( const vec3_t forward, vec3_t right, vec3_t up );
void VectorAngles( const float *forward, float *angles );
void VectorsAngles( const vec3_t forward, const vec3_t right, const vec3_t up, vec3_t angles );
void PlaneIntersect( const mplane_t *plane, const vec3_t p0, const vec3_t p1, vec3_t out );
qboolean SphereIntersect( const vec3_t vSphereCenter, float fSphereRadiusSquared, const vec3_t vLinePt, const vec3_t vLineDir );
void QuaternionSlerp( const vec4_t p, const vec4_t q, float t, vec4_t qt );
void R_StudioCalcBoneQuaternion( int frame, float s, const mstudiobone_t *pbone, const mstudioanim_t *panim, const float *adj, vec4_t q );
void R_StudioCalcBonePosition( int frame, float s, const mstudiobone_t *pbone, const mstudioanim_t *panim, const vec3_t adj, vec3_t pos );
int BoxOnPlaneSide( const vec3_t emins, const vec3_t emaxs, const mplane_t *p );
#define BOX_ON_PLANE_SIDE( emins, emaxs, p ) \
((( p )->type < 3 ) ? \
( \
((p)->dist <= (emins)[(p)->type]) ? 1 : \
( \
((p)->dist >= (emaxs)[(p)->type] ) ? 2 : 3 \
) \
) : BoxOnPlaneSide(( emins ), ( emaxs ), ( p )))
//
// matrixlib.c
//
#define Matrix3x4_LoadIdentity( mat ) Matrix3x4_Copy( mat, m_matrix3x4_identity )
#define Matrix3x4_Copy( out, in ) memcpy( out, in, sizeof( matrix3x4 ))
void Matrix3x4_VectorTransform( const matrix3x4 in, const float v[3], float out[3] );
void Matrix3x4_VectorITransform( const matrix3x4 in, const float v[3], float out[3] );
void Matrix3x4_VectorRotate( const matrix3x4 in, const float v[3], float out[3] );
void Matrix3x4_VectorIRotate( const matrix3x4 in, const float v[3], float out[3] );
void Matrix3x4_ConcatTransforms( matrix3x4 out, const matrix3x4 in1, const matrix3x4 in2 );
void Matrix3x4_FromOriginQuat( matrix3x4 out, const vec4_t quaternion, const vec3_t origin );
void Matrix3x4_CreateFromEntity( matrix3x4 out, const vec3_t angles, const vec3_t origin, float scale );
void Matrix3x4_TransformAABB( const matrix3x4 world, const vec3_t mins, const vec3_t maxs, vec3_t absmin, vec3_t absmax );
void Matrix3x4_AnglesFromMatrix( const matrix3x4 in, vec3_t out );
#define Matrix4x4_LoadIdentity( mat ) Matrix4x4_Copy( mat, m_matrix4x4_identity )
#define Matrix4x4_Copy( out, in ) memcpy( out, in, sizeof( matrix4x4 ))
void Matrix4x4_VectorTransform( const matrix4x4 in, const float v[3], float out[3] );
void Matrix4x4_VectorITransform( const matrix4x4 in, const float v[3], float out[3] );
void Matrix4x4_VectorRotate( const matrix4x4 in, const float v[3], float out[3] );
void Matrix4x4_VectorIRotate( const matrix4x4 in, const float v[3], float out[3] );
void Matrix4x4_ConcatTransforms( matrix4x4 out, const matrix4x4 in1, const matrix4x4 in2 );
void Matrix4x4_CreateFromEntity( matrix4x4 out, const vec3_t angles, const vec3_t origin, float scale );
void Matrix4x4_TransformPositivePlane( const matrix4x4 in, const vec3_t normal, float d, vec3_t out, float *dist );
void Matrix4x4_ConvertToEntity( const matrix4x4 in, vec3_t angles, vec3_t origin );
void Matrix4x4_Invert_Simple( matrix4x4 out, const matrix4x4 in1 );
qboolean Matrix4x4_Invert_Full( matrix4x4 out, const matrix4x4 in1 );
// horrible cast but helps not breaking strict aliasing in mathlib
// as union type punning should be fine in C but not in C++
// so don't carry over this to C++ code
#ifndef __cplusplus
typedef union
{
float fl;
@@ -173,28 +253,98 @@ static inline float UintAsFloat( uint32_t u )
bits.u = u;
return bits.fl;
}
#endif // __cplusplus
// isnan implementation is broken on IRIX as reported in https://github.com/FWGS/xash3d-fwgs/pull/1211
#if defined( XASH_IRIX ) || !defined( isnan )
static inline int IS_NAN( float x )
{
int32_t i = FloatAsInt( x ); // only C
return i & ( 255 << 23 ) == ( 255 << 23 );
}
#else
#define IS_NAN isnan
#endif
static inline float anglemod( float a )
{
a = (360.0f / 65536) * ((int)(a*(65536/360.0f)) & 65535);
return a;
}
static inline void SinCos( float radians, float *sine, float *cosine )
{
*sine = sin(radians);
*cosine = cos(radians);
*sine = sin( radians );
*cosine = cos( radians );
}
float rsqrt( float number );
float anglemod( float a );
word FloatToHalf( float v );
float HalfToFloat( word h );
void RoundUpHullSize( vec3_t size );
int SignbitsForPlane( const vec3_t normal );
int PlaneTypeForNormal( const vec3_t normal );
int NearestPOW( int value, qboolean roundDown );
float VectorNormalizeLength2( const vec3_t v, vec3_t out );
qboolean VectorCompareEpsilon( const vec3_t vec1, const vec3_t vec2, vec_t epsilon );
void VectorVectors( const vec3_t forward, vec3_t right, vec3_t up );
void VectorAngles( const float *forward, float *angles );
void AngleVectors( const vec3_t angles, vec3_t forward, vec3_t right, vec3_t up );
void VectorsAngles( const vec3_t forward, const vec3_t right, const vec3_t up, vec3_t angles );
void PlaneIntersect( const struct mplane_s *plane, const vec3_t p0, const vec3_t p1, vec3_t out );
static inline int NearestPOW( int value, qboolean roundDown )
{
int n = 1;
if( value <= 0 ) return 1;
while( n < value ) n <<= 1;
if( roundDown )
{
if( n > value ) n >>= 1;
}
return n;
}
static inline qboolean VectorCompareEpsilon( const vec3_t vec1, const vec3_t vec2, vec_t epsilon )
{
vec_t ax = fabs( vec1[0] - vec2[0] );
vec_t ay = fabs( vec1[1] - vec2[1] );
vec_t az = fabs( vec1[2] - vec2[2] );
return ( ax <= epsilon ) && ( ay <= epsilon ) && ( az <= epsilon ) ? true : false;
}
static inline float VectorNormalizeLength2( const vec3_t v, vec3_t out )
{
float length = VectorLength( v );
if( length )
{
float ilength = 1.0f / length;
out[0] = v[0] * ilength;
out[1] = v[1] * ilength;
out[2] = v[2] * ilength;
}
return length;
}
static inline void GAME_EXPORT AngleVectors( const vec3_t angles, vec3_t forward, vec3_t right, vec3_t up )
{
float sr, sp, sy, cr, cp, cy;
SinCos( DEG2RAD( angles[YAW] ), &sy, &cy );
SinCos( DEG2RAD( angles[PITCH] ), &sp, &cp );
SinCos( DEG2RAD( angles[ROLL] ), &sr, &cr );
if( forward )
{
forward[0] = cp * cy;
forward[1] = cp * sy;
forward[2] = -sp;
}
if( right )
{
right[0] = (-1.0f * sr * sp * cy + -1.0f * cr * -sy );
right[1] = (-1.0f * sr * sp * sy + -1.0f * cr * cy );
right[2] = (-1.0f * sr * cp);
}
if( up )
{
up[0] = (cr * sp * cy + -sr * -sy );
up[1] = (cr * sp * sy + -sr * cy );
up[2] = (cr * cp);
}
}
static inline void ClearBounds( vec3_t mins, vec3_t maxs )
{
@@ -221,20 +371,85 @@ static inline qboolean BoundsAndSphereIntersect( const vec3_t mins, const vec3_t
return true;
}
void AddPointToBounds( const vec3_t v, vec3_t mins, vec3_t maxs );
qboolean SphereIntersect( const vec3_t vSphereCenter, float fSphereRadiusSquared, const vec3_t vLinePt, const vec3_t vLineDir );
float RadiusFromBounds( const vec3_t mins, const vec3_t maxs );
void ExpandBounds( vec3_t mins, vec3_t maxs, float offset );
static inline float RadiusFromBounds( const vec3_t mins, const vec3_t maxs )
{
vec3_t corner;
int i;
void AngleQuaternion( const vec3_t angles, vec4_t q, qboolean studio );
void QuaternionAngle( const vec4_t q, vec3_t angles );
void QuaternionSlerp( const vec4_t p, const vec4_t q, float t, vec4_t qt );
for( i = 0; i < 3; i++ )
{
float a = fabs( mins[i] );
float b = fabs( maxs[i] );
corner[i] = Q_max( a, b );
}
//
// matrixlib.c
//
#define Matrix3x4_LoadIdentity( mat ) Matrix3x4_Copy( mat, m_matrix3x4_identity )
#define Matrix3x4_Copy( out, in ) memcpy( out, in, sizeof( matrix3x4 ))
return VectorLength( corner );
}
static inline void AddPointToBounds( const vec3_t v, vec3_t mins, vec3_t maxs )
{
int i;
for( i = 0; i < 3; i++ )
{
float val = v[i];
if( val < mins[i] ) mins[i] = val;
if( val > maxs[i] ) maxs[i] = val;
}
}
static inline void ExpandBounds( vec3_t mins, vec3_t maxs, float offset )
{
mins[0] -= offset;
mins[1] -= offset;
mins[2] -= offset;
maxs[0] += offset;
maxs[1] += offset;
maxs[2] += offset;
}
static inline int SignbitsForPlane( const vec3_t normal )
{
int bits, i;
for( bits = i = 0; i < 3; i++ )
if( normal[i] < 0.0f ) bits |= 1<<i;
return bits;
}
static inline int PlaneTypeForNormal( const vec3_t normal )
{
if( normal[0] == 1.0f )
return PLANE_X;
if( normal[1] == 1.0f )
return PLANE_Y;
if( normal[2] == 1.0f )
return PLANE_Z;
return PLANE_NONAXIAL;
}
static inline void AngleQuaternion( const vec3_t angles, vec4_t q, qboolean studio )
{
float sr, sp, sy, cr, cp, cy;
if( studio )
{
SinCos( angles[ROLL] * 0.5f, &sy, &cy );
SinCos( angles[YAW] * 0.5f, &sp, &cp );
SinCos( angles[PITCH] * 0.5f, &sr, &cr );
}
else
{
SinCos( DEG2RAD( angles[YAW] ) * 0.5f, &sy, &cy );
SinCos( DEG2RAD( angles[PITCH] ) * 0.5f, &sp, &cp );
SinCos( DEG2RAD( angles[ROLL] ) * 0.5f, &sr, &cr );
}
q[0] = sr * cp * cy - cr * sp * sy; // X
q[1] = cr * sp * cy + sr * cp * sy; // Y
q[2] = cr * cp * sy - sr * sp * cy; // Z
q[3] = cr * cp * cy + sr * sp * sy; // W
}
static inline void Matrix3x4_SetOrigin( matrix3x4 out, float x, float y, float z )
{
@@ -250,56 +465,23 @@ static inline void Matrix3x4_OriginFromMatrix( const matrix3x4 in, float *out )
out[2] = in[2][3];
}
void Matrix3x4_VectorTransform( const matrix3x4 in, const float v[3], float out[3] );
void Matrix3x4_VectorITransform( const matrix3x4 in, const float v[3], float out[3] );
void Matrix3x4_VectorRotate( const matrix3x4 in, const float v[3], float out[3] );
void Matrix3x4_VectorIRotate( const matrix3x4 in, const float v[3], float out[3] );
void Matrix3x4_ConcatTransforms( matrix3x4 out, const matrix3x4 in1, const matrix3x4 in2 );
void Matrix3x4_FromOriginQuat( matrix3x4 out, const vec4_t quaternion, const vec3_t origin );
void Matrix3x4_CreateFromEntity( matrix3x4 out, const vec3_t angles, const vec3_t origin, float scale );
void Matrix3x4_TransformAABB( const matrix3x4 world, const vec3_t mins, const vec3_t maxs, vec3_t absmin, vec3_t absmax );
void Matrix3x4_AnglesFromMatrix( const matrix3x4 in, vec3_t out );
static inline void QuaternionAngle( const vec4_t q, vec3_t angles )
{
matrix3x4 mat;
Matrix3x4_FromOriginQuat( mat, q, vec3_origin );
Matrix3x4_AnglesFromMatrix( mat, angles );
}
#define Matrix4x4_LoadIdentity( mat ) Matrix4x4_Copy( mat, m_matrix4x4_identity )
#define Matrix4x4_Copy( out, in ) memcpy( out, in, sizeof( matrix4x4 ))
static inline void R_StudioSlerpBones( int numbones, vec4_t q1[], float pos1[][3], const vec4_t q2[], const float pos2[][3], float s )
{
int i;
s = bound( 0.0f, s, 1.0f );
void Matrix4x4_VectorTransform( const matrix4x4 in, const float v[3], float out[3] );
void Matrix4x4_VectorITransform( const matrix4x4 in, const float v[3], float out[3] );
void Matrix4x4_VectorRotate( const matrix4x4 in, const float v[3], float out[3] );
void Matrix4x4_VectorIRotate( const matrix4x4 in, const float v[3], float out[3] );
void Matrix4x4_ConcatTransforms( matrix4x4 out, const matrix4x4 in1, const matrix4x4 in2 );
void Matrix4x4_CreateFromEntity( matrix4x4 out, const vec3_t angles, const vec3_t origin, float scale );
void Matrix4x4_TransformPositivePlane( const matrix4x4 in, const vec3_t normal, float d, vec3_t out, float *dist );
void Matrix4x4_ConvertToEntity( const matrix4x4 in, vec3_t angles, vec3_t origin );
void Matrix4x4_Invert_Simple( matrix4x4 out, const matrix4x4 in1 );
qboolean Matrix4x4_Invert_Full( matrix4x4 out, const matrix4x4 in1 );
void R_StudioSlerpBones( int numbones, vec4_t q1[], float pos1[][3], const vec4_t q2[], const float pos2[][3], float s );
void R_StudioCalcBoneQuaternion( int frame, float s, const mstudiobone_t *pbone, const mstudioanim_t *panim, const float *adj, vec4_t q );
void R_StudioCalcBonePosition( int frame, float s, const mstudiobone_t *pbone, const mstudioanim_t *panim, const vec3_t adj, vec3_t pos );
int BoxOnPlaneSide( const vec3_t emins, const vec3_t emaxs, const mplane_t *p );
#define BOX_ON_PLANE_SIDE( emins, emaxs, p ) \
((( p )->type < 3 ) ? \
( \
((p)->dist <= (emins)[(p)->type]) ? \
1 \
: \
( \
((p)->dist >= (emaxs)[(p)->type]) ? \
2 \
: \
3 \
) \
) \
: \
BoxOnPlaneSide(( emins ), ( emaxs ), ( p )))
extern vec3_t vec3_origin;
extern int boxpnt[6][4];
extern const matrix3x4 m_matrix3x4_identity;
extern const matrix4x4 m_matrix4x4_identity;
extern const float m_bytenormals[NUMVERTEXNORMALS][3];
for( i = 0; i < numbones; i++ )
{
QuaternionSlerp( q1[i], q2[i], s, q1[i] );
VectorLerp( pos1[i], s, pos2[i], pos1[i] );
}
}
#endif // XASH3D_MATHLIB_H

View File

@@ -27,6 +27,16 @@ ref_globals_t *gpGlobals;
ref_client_t *gp_cl;
ref_host_t *gp_host;
void _Mem_Free( void *data, const char *filename, int fileline )
{
gEngfuncs._Mem_Free( data, filename, fileline );
}
void *_Mem_Alloc( poolhandle_t poolptr, size_t size, qboolean clear, const char *filename, int fileline )
{
return gEngfuncs._Mem_Alloc( poolptr, size, clear, filename, fileline );
}
static void R_ClearScreen( void )
{
pglClearColor( 0.0f, 0.0f, 0.0f, 0.0f );

View File

@@ -31,7 +31,7 @@ GNU General Public License for more details.
#include "enginefeatures.h"
#include "com_strings.h"
#include "pm_movevars.h"
#include "common/cvar.h"
#include "cvardef.h"
#include "gl_export.h"
#include "wadfile.h"
#include "common/mod_local.h"
@@ -445,6 +445,9 @@ void R_GenerateVBO( void );
void R_ClearVBO( void );
void R_AddDecalVBO( decal_t *pdecal, msurface_t *surf );
void R_LightmapCoord( const vec3_t v, const msurface_t *surf, const float sample_size, vec2_t coords );
qboolean R_HasGeneratedVBO( void );
void R_EnableVBO( qboolean enable );
qboolean R_HasEnabledVBO( void );
//
// gl_rpart.c
@@ -779,10 +782,14 @@ DECLARE_ENGINE_SHARED_CVAR_LIST()
//
#include "crtlib.h"
#define Mem_Malloc( pool, size ) gEngfuncs._Mem_Alloc( pool, size, false, __FILE__, __LINE__ )
#define Mem_Calloc( pool, size ) gEngfuncs._Mem_Alloc( pool, size, true, __FILE__, __LINE__ )
void _Mem_Free( void *data, const char *filename, int fileline );
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;
#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 ) gEngfuncs._Mem_Realloc( pool, ptr, size, true, __FILE__, __LINE__ )
#define Mem_Free( mem ) gEngfuncs._Mem_Free( mem, __FILE__, __LINE__ )
#define Mem_Free( mem ) _Mem_Free( mem, __FILE__, __LINE__ )
#define Mem_AllocPool( name ) gEngfuncs._Mem_AllocPool( name, __FILE__, __LINE__ )
#define Mem_FreePool( pool ) gEngfuncs._Mem_FreePool( pool, __FILE__, __LINE__ )
#define Mem_EmptyPool( pool ) gEngfuncs._Mem_EmptyPool( pool, __FILE__, __LINE__ )

View File

@@ -742,10 +742,8 @@ static void R_RenderInfo_f( void )
gEngfuncs.Con_Printf( "GL4ES_VERSION: %s\n", version );
if( extensions )
gEngfuncs.Con_Reportf( "GL4ES_EXTENSIONS: %s\n", extensions );
}
gEngfuncs.Con_Printf( "GL_MAX_TEXTURE_SIZE: %i\n", glConfig.max_2d_texture_size );
if( GL_Support( GL_ARB_MULTITEXTURE ))
@@ -1150,6 +1148,10 @@ void GL_InitExtensions( void )
gEngfuncs.Cvar_SetValue( "gl_finish", 1 );
#endif
// we do not want to write vbo code that does not use multitexture
if( !GL_Support( GL_ARB_VERTEX_BUFFER_OBJECT_EXT ) || !GL_Support( GL_ARB_MULTITEXTURE ) || glConfig.max_texture_units < 2 )
gEngfuncs.Cvar_FullSet( "gl_vbo", "0", FCVAR_READ_ONLY );
R_RenderInfo_f();
tr.framecount = tr.visframecount = 1;

View File

@@ -1010,21 +1010,32 @@ void R_GammaChanged( qboolean do_reset_gamma )
}
}
static void R_CheckGamma( void )
static void R_CheckCvars( void )
{
qboolean rebuild = false;
if( FBitSet( gl_overbright.flags, FCVAR_CHANGED ))
{
rebuild = true;
ClearBits( gl_overbright.flags, FCVAR_CHANGED );
rebuild = true;
}
if( gl_overbright.value && ( FBitSet( r_vbo.flags, FCVAR_CHANGED ) || FBitSet( r_vbo_overbrightmode.flags, FCVAR_CHANGED ) ) )
if( FBitSet( r_vbo.flags, FCVAR_CHANGED ))
{
rebuild = true;
ClearBits( r_vbo.flags, FCVAR_CHANGED );
R_EnableVBO( r_vbo.value ? true : false );
if( R_HasEnabledVBO( ))
R_GenerateVBO();
if( gl_overbright.value )
rebuild = true;
}
if( FBitSet( r_vbo_overbrightmode.flags, FCVAR_CHANGED ) && gl_overbright.value )
{
ClearBits( r_vbo_overbrightmode.flags, FCVAR_CHANGED );
rebuild = true;
}
if( rebuild )
@@ -1046,7 +1057,7 @@ void R_BeginFrame( qboolean clearScene )
pglClear( GL_COLOR_BUFFER_BIT );
}
R_CheckGamma();
R_CheckCvars();
R_Set2DMode( true );

View File

@@ -147,7 +147,10 @@ void R_NewMap( void )
}
GL_BuildLightmaps ();
R_GenerateVBO();
R_ClearVBO();
if( R_HasEnabledVBO( ))
R_GenerateVBO();
R_ResetRipples();
if( gEngfuncs.drawFuncs->R_NewMap != NULL )

View File

@@ -229,10 +229,9 @@ void CL_DrawTracers( double frametime, particle_t *cl_active_tracers )
VectorAdd( verts[0], delta, verts[2] );
VectorAdd( verts[1], delta, verts[3] );
if( p->color > sizeof( gTracerColors ) / sizeof( gTracerColors[0] ))
if( p->color < 0 || p->color > sizeof( gTracerColors ) / sizeof( gTracerColors[0] ))
{
gEngfuncs.Con_Printf( S_ERROR "UserTracer with color(%d) > %zu\n", p->color, sizeof( gTracerColors ) / sizeof( gTracerColors[0] ));
p->color = 0;
p->color = TRACER_COLORINDEX_DEFAULT;
}
color = gTracerColors[p->color];

View File

@@ -718,7 +718,7 @@ static void R_BuildLightMap( msurface_t *surf, byte *dest, int stride, qboolean
tmax = ( info->lightextents[1] / sample_size ) + 1;
size = smax * tmax;
if( gl_overbright.value )
lightscale = (r_vbo.value && !r_vbo_overbrightmode.value) ? 171 : 256;
lightscale = ( R_HasEnabledVBO() && !r_vbo_overbrightmode.value) ? 171 : 256;
else lightscale = ( pow( 2.0f, 1.0f / v_lightgamma->value ) * 256 ) + 0.5;
lm = surf->samples;
@@ -927,7 +927,7 @@ static void R_BlendLightmaps( void )
if( gl_overbright.value )
{
pglBlendFunc( GL_DST_COLOR, GL_SRC_COLOR );
if(!( r_vbo.value && !r_vbo_overbrightmode.value ))
if(!( R_HasEnabledVBO() && !r_vbo_overbrightmode.value ))
pglColor4f( 128.0f / 192.0f, 128.0f / 192.0f, 128.0f / 192.0f, 1.0f );
}
else
@@ -1135,6 +1135,148 @@ static void R_RenderDetails( int passes )
GL_ResetFogColor();
}
static void R_RenderFullbrightForSurface( msurface_t *fa, texture_t *t )
{
if( !t->fb_texturenum )
return;
fa->info->lumachain = fullbright_surfaces[t->fb_texturenum];
fullbright_surfaces[t->fb_texturenum] = fa->info;
draw_fullbrights = true;
}
static void R_RenderDetailsForSurface( msurface_t *fa, texture_t *t )
{
if( !r_detailtextures.value )
return;
if( glState.isFogEnabled )
{
// don't apply detail textures for windows in the fog
if( RI.currententity->curstate.rendermode != kRenderTransTexture )
{
if( t->dt_texturenum )
{
fa->info->detailchain = detail_surfaces[t->dt_texturenum];
detail_surfaces[t->dt_texturenum] = fa->info;
}
else
{
// draw stub detail texture for underwater surfaces
fa->info->detailchain = detail_surfaces[tr.grayTexture];
detail_surfaces[tr.grayTexture] = fa->info;
}
draw_details = true;
}
}
else if( t->dt_texturenum )
{
fa->info->detailchain = detail_surfaces[t->dt_texturenum];
detail_surfaces[t->dt_texturenum] = fa->info;
draw_details = true;
}
}
static void R_RenderDecalsForSurface( msurface_t *fa, int cull_type )
{
if( RI.currententity->curstate.rendermode == kRenderNormal )
{
// batch decals to draw later
if( tr.num_draw_decals < MAX_DECAL_SURFS && fa->pdecals )
tr.draw_decals[tr.num_draw_decals++] = fa;
}
else
{
// if rendermode != kRenderNormal draw decals sequentially
DrawSurfaceDecals( fa, true, (cull_type == CULL_BACKSIDE));
}
}
static qboolean R_CheckLightMap( msurface_t *fa )
{
qboolean is_dynamic = false;
int maps;
// check for lightmap modification
for( maps = 0; maps < MAXLIGHTMAPS && fa->styles[maps] != 255; maps++ )
{
if( tr.lightstylevalue[fa->styles[maps]] != fa->cached_light[maps] )
goto dynamic;
}
// dynamic this frame or dynamic previously
if( fa->dlightframe == tr.framecount )
{
dynamic:
// NOTE: at this point we have only valid textures
if( r_dynamic->value )
is_dynamic = true;
}
if( is_dynamic )
{
const int style = fa->styles[maps];
if( maps < MAXLIGHTMAPS && ( style >= 32 || style == 0 || style == 20 ) && fa->dlightframe != tr.framecount )
{
byte temp[132*132*4];
mextrasurf_t *info = fa->info;
int sample_size;
int smax, tmax;
sample_size = gEngfuncs.Mod_SampleSizeForFace( fa );
smax = ( info->lightextents[0] / sample_size ) + 1;
tmax = ( info->lightextents[1] / sample_size ) + 1;
if( smax < 132 && tmax < 132 )
R_BuildLightMap( fa, temp, smax * 4, true );
else
{
smax = Q_min( smax, 132 );
tmax = Q_min( tmax, 132 );
memset( temp, 255, sizeof( temp ));
//Host_MapDesignError( "%s: bad surface extents: %d %d", __func__, fa->extents[0], fa->extents[1] );
}
R_SetCacheState( fa );
#ifdef XASH_WES
GL_Bind( XASH_TEXTURE1, tr.lightmapTextures[fa->lightmaptexturenum] );
pglTexParameteri( GL_TEXTURE_2D, GL_GENERATE_MIPMAP_SGIS, GL_TRUE );
#else
GL_Bind( XASH_TEXTURE0, tr.lightmapTextures[fa->lightmaptexturenum] );
#endif
pglTexSubImage2D( GL_TEXTURE_2D, 0, fa->light_s, fa->light_t, smax, tmax, GL_RGBA, GL_UNSIGNED_BYTE, temp );
#ifdef XASH_WES
GL_SelectTexture( XASH_TEXTURE0 );
#endif
}
else
return true; // add to dynamic chain
}
return false; // updated
}
static void R_RenderLightmapForSurface( msurface_t *fa )
{
if( !fa->polys || FBitSet( fa->flags, SURF_DRAWTILED ))
return;
if( R_CheckLightMap( fa ))
{
fa->info->lightmapchain = gl_lms.dynamic_surfaces;
gl_lms.dynamic_surfaces = fa;
}
else
{
fa->info->lightmapchain = gl_lms.lightmap_surfaces[fa->lightmaptexturenum];
gl_lms.lightmap_surfaces[fa->lightmaptexturenum] = fa;
}
}
/*
================
R_RenderBrushPoly
@@ -1142,8 +1284,6 @@ R_RenderBrushPoly
*/
static void R_RenderBrushPoly( msurface_t *fa, int cull_type )
{
qboolean is_dynamic = false;
int maps;
texture_t *t;
r_stats.c_world_polys++;
@@ -1163,109 +1303,11 @@ static void R_RenderBrushPoly( msurface_t *fa, int cull_type )
}
else GL_Bind( XASH_TEXTURE0, t->gl_texturenum );
if( t->fb_texturenum )
{
fa->info->lumachain = fullbright_surfaces[t->fb_texturenum];
fullbright_surfaces[t->fb_texturenum] = fa->info;
draw_fullbrights = true;
}
if( r_detailtextures.value )
{
if( glState.isFogEnabled )
{
// don't apply detail textures for windows in the fog
if( RI.currententity->curstate.rendermode != kRenderTransTexture )
{
if( t->dt_texturenum )
{
fa->info->detailchain = detail_surfaces[t->dt_texturenum];
detail_surfaces[t->dt_texturenum] = fa->info;
}
else
{
// draw stub detail texture for underwater surfaces
fa->info->detailchain = detail_surfaces[tr.grayTexture];
detail_surfaces[tr.grayTexture] = fa->info;
}
draw_details = true;
}
}
else if( t->dt_texturenum )
{
fa->info->detailchain = detail_surfaces[t->dt_texturenum];
detail_surfaces[t->dt_texturenum] = fa->info;
draw_details = true;
}
}
R_RenderFullbrightForSurface( fa, t );
R_RenderDetailsForSurface( fa, t );
DrawGLPoly( fa->polys, 0.0f, 0.0f );
if( RI.currententity->curstate.rendermode == kRenderNormal )
{
// batch decals to draw later
if( tr.num_draw_decals < MAX_DECAL_SURFS && fa->pdecals )
tr.draw_decals[tr.num_draw_decals++] = fa;
}
else
{
// if rendermode != kRenderNormal draw decals sequentially
DrawSurfaceDecals( fa, true, (cull_type == CULL_BACKSIDE));
}
if( FBitSet( fa->flags, SURF_DRAWTILED ))
return; // no lightmaps anyway
// check for lightmap modification
for( maps = 0; maps < MAXLIGHTMAPS && fa->styles[maps] != 255; maps++ )
{
if( tr.lightstylevalue[fa->styles[maps]] != fa->cached_light[maps] )
goto dynamic;
}
// dynamic this frame or dynamic previously
if( fa->dlightframe == tr.framecount )
{
dynamic:
// NOTE: at this point we have only valid textures
if( r_dynamic->value ) is_dynamic = true;
}
if( is_dynamic )
{
if(( maps < MAXLIGHTMAPS ) && ( fa->styles[maps] >= 32 || fa->styles[maps] == 0 || fa->styles[maps] == 20 ) && ( fa->dlightframe != tr.framecount ))
{
byte temp[132*132*4];
mextrasurf_t *info = fa->info;
int sample_size;
int smax, tmax;
sample_size = gEngfuncs.Mod_SampleSizeForFace( fa );
smax = ( info->lightextents[0] / sample_size ) + 1;
tmax = ( info->lightextents[1] / sample_size ) + 1;
R_BuildLightMap( fa, temp, smax * 4, true );
R_SetCacheState( fa );
GL_Bind( XASH_TEXTURE0, tr.lightmapTextures[fa->lightmaptexturenum] );
pglTexSubImage2D( GL_TEXTURE_2D, 0, fa->light_s, fa->light_t, smax, tmax,
GL_RGBA, GL_UNSIGNED_BYTE, temp );
fa->info->lightmapchain = gl_lms.lightmap_surfaces[fa->lightmaptexturenum];
gl_lms.lightmap_surfaces[fa->lightmaptexturenum] = fa;
}
else
{
fa->info->lightmapchain = gl_lms.dynamic_surfaces;
gl_lms.dynamic_surfaces = fa;
}
}
else
{
fa->info->lightmapchain = gl_lms.lightmap_surfaces[fa->lightmaptexturenum];
gl_lms.lightmap_surfaces[fa->lightmaptexturenum] = fa;
}
R_RenderDecalsForSurface( fa, cull_type );
R_RenderLightmapForSurface( fa );
}
/*
@@ -1541,7 +1583,7 @@ void R_DrawBrushModel( cl_entity_t *e )
model_t *clmodel;
qboolean rotated;
dlight_t *l;
qboolean allow_vbo = r_vbo.value;
qboolean allow_vbo = R_HasEnabledVBO();
if( !RI.drawWorld ) return;
@@ -1791,6 +1833,10 @@ struct vbo_static_s
int maxarraysplit_tex;
int minarraysplit_lm;
int maxarraysplit_lm;
// cvar state potentially might be changed during frame
// so only enable VBO at the beginning of frame
qboolean enabled;
} vbos;
struct multitexturestate_s
@@ -1827,7 +1873,6 @@ enum lightmap_state_e
VBO_LIGHTMAP_DYNAMIC
};
static struct arraystate_s
{
enum array_state_e astate;
@@ -1837,6 +1882,20 @@ static struct arraystate_s
qboolean decal_mode;
} vboarray;
qboolean R_HasGeneratedVBO( void )
{
return vbos.mempool != 0;
}
void R_EnableVBO( qboolean enable )
{
vbos.enabled = enable;
}
qboolean R_HasEnabledVBO( void )
{
return vbos.enabled;
}
/*
===================
@@ -1848,29 +1907,23 @@ Allocate memory for arrays, fill it with vertex attribs and upload to GPU
void R_GenerateVBO( void )
{
model_t *world = WORLDMODEL;
msurface_t *surfaces = world->surfaces;
int numsurfaces = world->numsurfaces;
int numtextures = world->numtextures;
int numlightmaps = gl_lms.current_lightmap_texture;
msurface_t *surfaces;
int numsurfaces;
int numtextures;
const int numlightmaps = gl_lms.current_lightmap_texture;
int k, len = 0;
vboarray_t *vbo;
uint maxindex = 0;
double t1, t2, t3;
R_ClearVBO();
// we do not want to write vbo code that does not use multitexture
if( !GL_Support( GL_ARB_VERTEX_BUFFER_OBJECT_EXT ) || !GL_Support( GL_ARB_MULTITEXTURE ) || glConfig.max_texture_units < 2 )
{
gEngfuncs.Cvar_FullSet( "gl_vbo", "0", FCVAR_READ_ONLY );
if( R_HasGeneratedVBO() || !world || !world->surfaces )
return;
}
t1 = gEngfuncs.pfnTime();
// save in config if enabled manually
if( r_vbo.value )
r_vbo.flags |= FCVAR_ARCHIVE;
surfaces = world->surfaces;
numsurfaces = world->numsurfaces;
numtextures = world->numtextures;
vbos.mempool = Mem_AllocPool("Render VBO Zone");
@@ -3021,14 +3074,14 @@ void R_DrawVBO( qboolean drawlightmap, qboolean drawtextures )
int k;
vboarray_t *vbo = vbos.arraylist;
if( !r_vbo.value )
if( !R_HasGeneratedVBO() || !R_HasEnabledVBO() )
return;
GL_SetupFogColorForSurfacesEx( 1, 0.5f, false );
R_SetupVBOArrayStatic( vbo, drawlightmap, drawtextures );
mtst.skiptexture = !drawtextures;
mtst.tmu_dt = glConfig.max_texture_units > 2 && r_vbo_detail.value == 2? XASH_TEXTURE2:-1;
mtst.tmu_dt = glConfig.max_texture_units > 2 && r_vbo_detail.value == 2 ? XASH_TEXTURE2 : -1;
// setup limits
if( vbos.minlightmap > vbos.minarraysplit_lm )
@@ -3122,171 +3175,71 @@ void R_DrawVBO( qboolean drawlightmap, qboolean drawtextures )
vbos.maxtexture = 0;
}
/*
================
R_CheckLightMap
update surface's lightmap if needed and return true if it is dynamic
================
*/
static qboolean R_CheckLightMap( msurface_t *fa )
{
int maps;
qboolean is_dynamic = false;
// check for lightmap modification
for( maps = 0; maps < MAXLIGHTMAPS && fa->styles[maps] != 255; maps++ )
{
if( tr.lightstylevalue[fa->styles[maps]] != fa->cached_light[maps] )
{
is_dynamic = true;
break;
}
}
// already up to date
if( !is_dynamic && ( fa->dlightframe != tr.framecount ))
return false;
// build lightmap
if(( maps < MAXLIGHTMAPS ) && ( fa->styles[maps] >= 32 || fa->styles[maps] == 0 ) && ( fa->dlightframe != tr.framecount ))
{
byte temp[132*132*4];
int smax, tmax;
int sample_size;
mextrasurf_t *info;
info = fa->info;
sample_size = gEngfuncs.Mod_SampleSizeForFace( fa );
smax = ( info->lightextents[0] / sample_size ) + 1;
tmax = ( info->lightextents[1] / sample_size ) + 1;
if( smax < 132 && tmax < 132 )
{
R_BuildLightMap( fa, temp, smax * 4, true );
}
else
{
smax = Q_min( smax, 132 );
tmax = Q_min( tmax, 132 );
//Host_MapDesignError( "R_RenderBrushPoly: bad surface extents: %d %d", fa->extents[0], fa->extents[1] );
memset( temp, 255, sizeof( temp ) );
}
R_SetCacheState( fa );
#ifdef XASH_WES
GL_Bind( XASH_TEXTURE1, tr.lightmapTextures[fa->lightmaptexturenum] );
pglTexParameteri( GL_TEXTURE_2D, GL_GENERATE_MIPMAP_SGIS, GL_TRUE );
#else
GL_Bind( XASH_TEXTURE0, tr.lightmapTextures[fa->lightmaptexturenum] );
#endif
pglTexSubImage2D( GL_TEXTURE_2D, 0, fa->light_s, fa->light_t, smax, tmax,
GL_RGBA, GL_UNSIGNED_BYTE, temp );
#ifdef XASH_WES
GL_SelectTexture( XASH_TEXTURE0 );
#endif
}
// add to dynamic chain
else
return true;
// updated
return false;
}
qboolean R_AddSurfToVBO( msurface_t *surf, qboolean buildlightmap )
{
if( r_vbo.value && vbos.surfdata[surf - WORLDMODEL->surfaces].vbotexture )
{
// find vbotexture_t assotiated with this surface
int idx = surf - WORLDMODEL->surfaces;
vbotexture_t *vbotex = vbos.surfdata[idx].vbotexture;
int texturenum = vbos.surfdata[idx].texturenum;
const int idx = surf - WORLDMODEL->surfaces;
vbotexture_t *vbotex;
int texturenum;
if( !surf->polys )
return true;
if( !R_HasGeneratedVBO() || !R_HasEnabledVBO( ))
return false;
if( vbos.maxlightmap < surf->lightmaptexturenum + 1 )
vbos.maxlightmap = surf->lightmaptexturenum + 1;
if( vbos.minlightmap > surf->lightmaptexturenum )
vbos.minlightmap = surf->lightmaptexturenum;
if( vbos.maxtexture < texturenum + 1 )
vbos.maxtexture = texturenum + 1;
if( vbos.mintexture > texturenum )
vbos.mintexture = texturenum;
// find vbotexture_t assotiated with this surface
vbotex = vbos.surfdata[idx].vbotexture;
texturenum = vbos.surfdata[idx].texturenum;
buildlightmap &= !r_fullbright->value && !!WORLDMODEL->lightdata;
/* draw details in regular way */
if( r_vbo_detail.value == 0 )
{
if( r_detailtextures.value && surf->texinfo && surf->texinfo )
{
texture_t *t = surf->texinfo->texture;
if( glState.isFogEnabled )
{
// don't apply detail textures for windows in the fog
if( RI.currententity->curstate.rendermode != kRenderTransTexture )
{
if( t->dt_texturenum )
{
surf->info->detailchain = detail_surfaces[t->dt_texturenum];
detail_surfaces[t->dt_texturenum] = surf->info;
}
else
{
// draw stub detail texture for underwater surfaces
surf->info->detailchain = detail_surfaces[tr.grayTexture];
detail_surfaces[tr.grayTexture] = surf->info;
}
draw_details = true;
}
}
else if( t->dt_texturenum )
{
surf->info->detailchain = detail_surfaces[t->dt_texturenum];
detail_surfaces[t->dt_texturenum] = surf->info;
draw_details = true;
}
}
}
if( buildlightmap && R_CheckLightMap( surf ) )
{
// every vbotex has own lightmap chain (as we sorted if by textures to use multitexture)
surf->info->lightmapchain = vbotex->dlightchain;
vbotex->dlightchain = surf;
}
else
{
uint indexbase = vbos.surfdata[idx].startindex;
uint index;
// GL_TRIANGLE_FAN: 0 1 2 0 2 3 0 3 4 ...
for( index = indexbase + 2; index < indexbase + surf->polys->numverts; index++ )
{
vbotex->indexarray[vbotex->curindex++] = indexbase;
vbotex->indexarray[vbotex->curindex++] = index - 1;
vbotex->indexarray[vbotex->curindex++] = index;
}
// if surface has decals, add it to decal lightmapchain
if( surf->pdecals )
{
surf->info->lightmapchain = vbos.decaldata->lm[vbotex->lightmaptexturenum];
vbos.decaldata->lm[vbotex->lightmaptexturenum] = surf;
}
}
// now this path does not draw wapred surfaces, so count it as one poly
r_stats.c_world_polys++;
if( !vbotex )
return false;
if( !surf->polys )
return true;
if( vbos.maxlightmap < surf->lightmaptexturenum + 1 )
vbos.maxlightmap = surf->lightmaptexturenum + 1;
if( vbos.minlightmap > surf->lightmaptexturenum )
vbos.minlightmap = surf->lightmaptexturenum;
if( vbos.maxtexture < texturenum + 1 )
vbos.maxtexture = texturenum + 1;
if( vbos.mintexture > texturenum )
vbos.mintexture = texturenum;
buildlightmap &= !r_fullbright->value && !!WORLDMODEL->lightdata;
// draw details in regular way
if( r_vbo_detail.value == 0 && surf->texinfo )
R_RenderDetailsForSurface( surf, surf->texinfo->texture );
if( buildlightmap && R_CheckLightMap( surf ))
{
// every vbotex has own lightmap chain (as we sorted if by textures to use multitexture)
surf->info->lightmapchain = vbotex->dlightchain;
vbotex->dlightchain = surf;
}
return false;
else
{
uint indexbase = vbos.surfdata[idx].startindex;
uint index;
// GL_TRIANGLE_FAN: 0 1 2 0 2 3 0 3 4 ...
for( index = indexbase + 2; index < indexbase + surf->polys->numverts; index++ )
{
vbotex->indexarray[vbotex->curindex++] = indexbase;
vbotex->indexarray[vbotex->curindex++] = index - 1;
vbotex->indexarray[vbotex->curindex++] = index;
}
// if surface has decals, add it to decal lightmapchain
if( surf->pdecals )
{
surf->info->lightmapchain = vbos.decaldata->lm[vbotex->lightmaptexturenum];
vbos.decaldata->lm[vbotex->lightmaptexturenum] = surf;
}
}
// now this path does not draw wapred surfaces, so count it as one poly
r_stats.c_world_polys++;
return true;
}
/*
@@ -3624,7 +3577,7 @@ void R_DrawWorld( void )
GL_ResetFogColor();
R_BlendLightmaps();
R_RenderFullbrights();
R_RenderDetails( r_vbo.value? 2 : 3 );
R_RenderDetails( R_HasEnabledVBO() ? 2 : 3 );
if( skychain )
R_DrawSkyBox();

View File

@@ -23,6 +23,17 @@ gl_globals_t tr;
ref_speeds_t r_stats;
poolhandle_t r_temppool;
viddef_t vid;
void _Mem_Free( void *data, const char *filename, int fileline )
{
gEngfuncs._Mem_Free( data, filename, fileline );
}
void *_Mem_Alloc( poolhandle_t poolptr, size_t size, qboolean clear, const char *filename, int fileline )
{
return gEngfuncs._Mem_Alloc( poolptr, size, clear, filename, fileline );
}
static void GAME_EXPORT R_ClearScreen( void )
{

View File

@@ -30,7 +30,7 @@ GNU General Public License for more details.
#include "enginefeatures.h"
#include "com_strings.h"
#include "pm_movevars.h"
#include "common/cvar.h"
#include "cvardef.h"
typedef struct mip_s mip_t;
typedef int fixed8_t;
@@ -1237,10 +1237,14 @@ void R_SetUpWorldTransform (void);
#include "crtlib.h"
#include "crclib.h"
#if 1
#define Mem_Malloc( pool, size ) gEngfuncs._Mem_Alloc( pool, size, false, __FILE__, __LINE__ )
#define Mem_Calloc( pool, size ) gEngfuncs._Mem_Alloc( pool, size, true, __FILE__, __LINE__ )
void _Mem_Free( void *data, const char *filename, int fileline );
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;
#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 ) gEngfuncs._Mem_Realloc( pool, ptr, size, true, __FILE__, __LINE__ )
#define Mem_Free( mem ) gEngfuncs._Mem_Free( mem, __FILE__, __LINE__ )
#define Mem_Free( mem ) _Mem_Free( mem, __FILE__, __LINE__ )
#define Mem_AllocPool( name ) gEngfuncs._Mem_AllocPool( name, __FILE__, __LINE__ )
#define Mem_FreePool( pool ) gEngfuncs._Mem_FreePool( pool, __FILE__, __LINE__ )
#define Mem_EmptyPool( pool ) gEngfuncs._Mem_EmptyPool( pool, __FILE__, __LINE__ )

View File

@@ -236,10 +236,9 @@ void GAME_EXPORT CL_DrawTracers( double frametime, particle_t *cl_active_tracers
VectorAdd( verts[0], delta, verts[2] );
VectorAdd( verts[1], delta, verts[3] );
if( p->color > sizeof( gTracerColors ) / sizeof( gTracerColors[0] ))
if( p->color < 0 || p->color > sizeof( gTracerColors ) / sizeof( gTracerColors[0] ))
{
gEngfuncs.Con_Printf( S_ERROR "UserTracer with color(%d) > %zu\n", p->color, sizeof( gTracerColors ) / sizeof( gTracerColors[0] ));
p->color = 0;
p->color = TRACER_COLORINDEX_DEFAULT;
}
color = gTracerColors[p->color];

View File

@@ -17,13 +17,22 @@ fi
if [ "$ARCH" = "i386" ]; then
cp SDL2_VC/lib/x86/SDL2.dll . # Install SDL2
cp 3rdparty/vgui_support/vgui-dev/lib/win32_vc6/vgui.dll .
elif [ "$ARCH" = "amd64" ]; then
cp SDL2_VC/lib/x64/SDL2.dll .
else
die
fi
WINSDK_LATEST=$(ls -1 "C:/Program Files (x86)/Windows Kits/10/bin" | grep -E '^10' | sort -rV | head -n1)
echo "Latest installed Windows SDK is $WINSDK_LATEST"
"C:/Program Files (x86)/Windows Kits/10/bin/$WINSDK_LATEST/x64/signtool.exe" \
sign //f scripts/fwgs.pfx //fd SHA256 //p "$FWGS_PFX_PASSWORD" *.dll *.exe
if [ "$ARCH" = "i386" ]; then # VGUI is already signed
cp 3rdparty/vgui_support/vgui-dev/lib/win32_vc6/vgui.dll .
fi
mkdir -p artifacts/
7z a -t7z artifacts/xash3d-fwgs-win32-$ARCH.7z -m0=lzma2 -mx=9 -mfb=64 -md=32m -ms=on \
*.dll *.exe *.pdb activities.txt \

22
wscript
View File

@@ -79,8 +79,10 @@ SUBDIRS = [
Subproject('ref/gl', lambda x: not x.env.DEDICATED and (x.env.GL or x.env.NANOGL or x.env.GLWES or x.env.GL4ES)),
Subproject('ref/soft', lambda x: not x.env.DEDICATED and not x.env.SUPPORT_BSP2_FORMAT and x.env.SOFT),
Subproject('ref/null', lambda x: not x.env.DEDICATED and x.env.NULL),
Subproject('3rdparty/bzip2', lambda x: not x.env.DEDICATED and not x.env.HAVE_SYSTEM_BZ2),
Subproject('3rdparty/mainui', lambda x: not x.env.DEDICATED),
Subproject('3rdparty/vgui_support', lambda x: not x.env.DEDICATED),
# Subproject('3rdparty/freevgui', lambda x: not x.env.DEDICATED),
Subproject('stub/client', lambda x: not x.env.DEDICATED),
Subproject('game_launch', lambda x: not x.env.DISABLE_LAUNCHER),
@@ -172,7 +174,12 @@ def options(opt):
def configure(conf):
conf.load('fwgslib reconfigure compiler_optimizations')
conf.env.MSVC_TARGETS = ['x86' if not conf.options.ALLOW64 else 'x64']
if conf.options.ALLOW64:
conf.env.MSVC_TARGETS = ['x64']
elif sys.maxsize > 2 ** 32:
conf.env.MSVC_TARGETS = ['amd64_x86', 'x86']
else:
conf.env.MSVC_TARGETS = ['x86']
# Load compilers early
conf.load('xshlib xcompile compiler_c compiler_cxx cmake gccdeps')
@@ -222,12 +229,10 @@ def configure(conf):
elif conf.env.DEST_OS == 'nswitch':
conf.options.NO_VGUI = True
conf.options.GL = True
conf.options.NO_ASYNC_RESOLVE = True
conf.options.USE_STBTT = True
elif conf.env.DEST_OS == 'psvita':
conf.options.NO_VGUI = True
conf.options.GL = True
conf.options.NO_ASYNC_RESOLVE = True
conf.options.USE_STBTT = True
# we'll specify -fPIC by hand for shared libraries only
enforce_pic = False
@@ -302,9 +307,10 @@ def configure(conf):
'-Werror=alloc-size',
'-Werror=bool-compare',
'-Werror=bool-operation',
'-Werror=cast-align=strict',
# '-Werror=cast-align=strict',
'-Werror=duplicated-cond',
'-Werror=format-extra-args',
'-Werror=free-nonheap-object',
'-Werror=implicit-fallthrough=2',
'-Werror=logical-op',
'-Werror=nonnull',
@@ -329,6 +335,7 @@ def configure(conf):
'-Wformat=2',
'-Winit-self',
'-Wmisleading-indentation',
'-Wmismatched-dealloc',
'-Wstringop-overflow',
'-Wunintialized',
@@ -453,6 +460,13 @@ int main(void) { return !opus_custom_encoder_init((OpusCustomEncoder *)1, (const
if conf.check_cc(msg='Checking if opus supports custom modes', defines='CUSTOM_MODES=1', use='opus werror', fragment=frag, mandatory=False):
conf.env.HAVE_SYSTEM_OPUS = True
# search for bzip2
BZIP2_CHECK='''#include <bzlib.h>
int main(void) { return (int)BZ2_bzlibVersion(); }'''
if conf.check_cc(lib='bz2', fragment=BZIP2_CHECK, uselib_store='bzip2', mandatory=False):
conf.env.HAVE_SYSTEM_BZ2 = True
conf.define('XASH_LOW_MEMORY', conf.options.LOW_MEMORY)
for i in SUBDIRS: