Merge upstream master

This commit is contained in:
Alibek Omarov 2023-04-28 17:15:31 +03:00
commit c4757058e1
210 changed files with 5345 additions and 3837 deletions

View File

@ -24,22 +24,23 @@ jobs:
# targetos: linux
# targetarch: aarch64
# - os: ubuntu-18.04
# - os: ubuntu-20.04
# targetos: android
# targetarch: 32
# - os: ubuntu-18.04
# - os: ubuntu-20.04
# targetos: android
# targetarch: 64
# - os: ubuntu-18.04
# - os: ubuntu-20.04
# targetos: motomagx
# targetarch: armv6
# FIXME suddenly started failing, disable temporarily as irrelevant for ref_vk effort
# - os: ubuntu-20.04
# targetos: nswitch
# targetarch: arm64
- os: ubuntu-20.04
targetos: nswitch
targetarch: arm64
- os: ubuntu-20.04
targetos: psvita
targetarch: armv7hf
- os: windows-latest
targetos: win32
targetarch: amd64
@ -50,9 +51,7 @@ jobs:
SDL_VERSION: 2.26.2
VULKAN_SDK_VERSION: 1.3.239
GH_CPU_ARCH: ${{ matrix.targetarch }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
ANDROID_SDK_TOOLS_VER: 4333796
UPLOADTOOL_ISPRERELEASE: true
steps:
- name: Checkout
uses: actions/checkout@v3
@ -62,8 +61,6 @@ jobs:
run: bash scripts/gha/deps_${{ matrix.targetos }}.sh
- name: Build engine
run: bash scripts/gha/build_${{ matrix.targetos }}.sh
- name: Upload engine (prereleases)
run: bash scripts/continious_upload.sh artifacts/*
- name: Upload engine (artifacts)
uses: actions/upload-artifact@v3
with:
@ -95,3 +92,38 @@ jobs:
# manifest-path: scripts/flatpak/${{ matrix.app }}.yml
# - name: Upload engine (prereleases)
# run: bash scripts/continious_upload.sh ${{ matrix.app }}.flatpak
release:
name: "Upload releases"
runs-on: ubuntu-latest
needs: [build, flatpak]
if: ${{ github.event_name == 'push' }}
steps:
- name: Remove old release
uses: FWGS/delete-tag-and-release@v0.2.1-dev
with:
tag_name: ${{ github.ref_name == 'master' && 'continuous' || format('continuous-{0}', github.ref_name) }}
delete_release: true
github_token: ${{ secrets.GITHUB_TOKEN }}
- name: Fetch artifacts
uses: actions/download-artifact@v3.0.1
with:
path: artifacts/
- name: Repackage binaries and allow GitHub to process removed release for few seconds
run: |
cd artifacts/
for i in artifact-* su.xash.Engine.*; do
mv "$i"/* .
rm -rf "$i"
done
ls -R .
cd ../
sleep 20s
- name: Upload new release
uses: FWGS/action-gh-release@v0.1.15
with:
name: Xash3D FWGS Continuous ${{ github.ref_name }} Build
tag_name: ${{ github.ref_name == 'master' && 'continuous' || format('continuous-{0}', github.ref_name) }}
prerelease: true
token: ${{ secrets.GITHUB_TOKEN }}
files: artifacts/*
draft: false

@ -1 +1 @@
Subproject commit 9aba4527435b1beda97ca8d8a5f1937cd0088c57
Subproject commit 853f633be18892499a86e7f57fecf34640bd64f2

2
3rdparty/mainui vendored

@ -1 +1 @@
Subproject commit 2f615a74802e665014cddaf766e4edc2bac24a55
Subproject commit 262128c0d1368177d85072d1642521f738942f9a

2
3rdparty/opus/opus vendored

@ -1 +1 @@
Subproject commit 997fdf54e781ae1c04dee42018f35388a04fe483
Subproject commit 8cf872a186b96085b1bb3a547afd598354ebeb87

@ -1 +1 @@
Subproject commit 63c134f188e7c0891927f5a4149f4444b43b0be8
Subproject commit e7b56e7b26b240f811a8a192f6e2880f0d3898d3

View File

@ -0,0 +1,10 @@
# Debugging your mod using minidump files (Windows only)
Minidump files is awesome instrument for debugging your mod after it's being released, or for catch specific crashes which are presented only in one specific configuration, but doesn't happens in other configurations or even on developer machine. It contains a lot of information useful for debugging, and therefore it size is not so small: around hundreds or even thousands of megabytes. But this is not a problem, since minidump files compresses very effectively using common algorithms.
There are short algorithm, explaining how to use this debugging instrument:
1. User starts your mod with `-minidumps` startup parameter
2. Finally, crash happened on user's machine, and minidump file being written. This file has `.mdmp` extension and located in same folder, where mod folder located
3. User packs this minidump file to .zip/.7z archive, and somehow sends it to developer
4. Developer just opens minidump file in Visual Studio, then a virtual debugging session is opened and now reasons of crash is pretty easy to detect: you can see call stack, local function variables and global variables, information about exception and a lot of other information
You can find more information about minidumps in this [awesome article](https://learn.microsoft.com/en-us/windows/win32/dxtecharts/crash-dump-analysis?source=recommendations#writing-a-minidump).

View File

@ -0,0 +1,22 @@
## Looping MP3 extension
It is now possible to loop MP3 file in Xash3D FWGS by adding a custom text tag with `LOOP_START` or `LOOPSTART` in description and time point (in raw samples) in value.
### Example with foobar2000
1. Open Foobar2000
2. Add your .mp3 file to playlist
3. Right click to newly added file and select Properties
4. In Metadata tab, at the bottom of the table, select "+add new"
5. In newly added line replace `«input field name»` with `LOOP_START` (without any symbols).
6. Press Tab and enter loop time point in raw samples. For example, `0` will replay sound file from beginning to end indefinitely.
### Possible alternatives
1. Classic WAV files looping. HQ WAV files can take too much disk space, and recommended software supporting cue points is paid, outdated and can't run on modern systems. (Although there is alternative that's proven to work with idTech-based engines called LoopAuditioneer.)
2. Vorbis looping through comment. Engine doesn't support Vorbis but this extension was highly inspired by this hack.
### Known bugs and limitations
1. At this time using MP3 as SFX requires complete decoding. This can cause noticeable stutters, so keep MP3 file length in mind.
2. We deliberately only support modern ID3v2.3 and ID3v2.4 tags. Using ID3v1 is not possible.

View File

@ -1,7 +1,40 @@
# Server porting
# Self-made port
## Compatibility with RISC architectures
### Unaligned access
Unaligned access on **i386** causes only performance penalty, but on **RISC** it can cause unstable work.
For HLSDK at least you need such patches in util.cpp:
- https://github.com/FWGS/halflife/commit/7bfefe86e35d67867ae7af830ac1fc38f2908360
- https://github.com/FWGS/hlsdk-portable/commit/617d75545f2ecb9b2d46cc30728dc37c9eb6d35e
### Signed chars
`char` type defined as **signed** for **x86** and as **unsigned** for **arm**.
And sometimes such difference can break logic.
As a solution you can use `signed char` type in code directly or use `-fsigned-char` option for gcc/clang compilers.
For HLSDK at least you need such [fix](https://github.com/FWGS/hlsdk-portable/commit/1ca34fcb4381682bd517612b530db22a1354a795) in nodes.cpp/.h.
## Compatibility with 64bit architectures
You need list of patches for Studio Model Render, MAKE_STRING macro and nodes:
- https://github.com/FWGS/hlsdk-portable/commit/d287ed446332e615ab5fb25ca81b99fa14d18a73
- https://github.com/FWGS/hlsdk-portable/commit/3bce17e3a04f8af10a927a07ceb8ab0f09152ec4
- https://github.com/FWGS/hlsdk-portable/commit/9ebfc981773ec4c7a89ffe52d9c249e1fbef9634
- https://github.com/FWGS/hlsdk-portable/commit/00833188dab87ef5746286479ba5aeb9d83b4a0c
- https://github.com/FWGS/hlsdk-portable/commit/4661b5c1a5245b27a5532745c11e44b5540e4172
- https://github.com/FWGS/hlsdk-portable/commit/2b61380146b1d58a8c465f0e312c061b12bda115
- https://github.com/FWGS/hlsdk-portable/commit/8ef6cb2427ee16a763103bd3f315f38e2f01cfe2
## Mobility API
Xash3D FWGS has special extended interface in `mobility_int.h` which adds some new features like vibration on mobile platforms.
## Porting server-side code
Original valve's server code was compatible with linux and gcc 2.x.
Newer gcc versions have restriction which breaks build.
Now, to make it building with gcc 4.x, you need do following:
Now, to make it building with gcc 4.x+ or clang, you need to do following:
* Go to cbase.h and redefine macros as following
```
#define SetThink( a ) m_pfnThink = static_cast <void (CBaseEntity::*)(void)> (&a)
@ -18,58 +51,60 @@ Now, to make it building with gcc 4.x, you need do following:
* Replace all SetThink(NULL), SetTouch(NULL), setUse(NULL) and SetBlocked(NULL) by ResetThink(), ResetTouch(), ResetUse() and ResetBlocked()
* Sometimes you may need to add #include <ctype.h> if functions tolower or isspace are missing
# Client porting
## Porting client-side code
## VGUI library
Valve's client uses vgui library which is available only on x86 systems and has big amount of mistakes in headers. The best and simplest way of porting is removing VGUI dependency at all.
Most singleplayer mods don't really use VGUI at all. It is used in multiplayer only to show score table and MOTD window
## Porting
### First strategy: full port
#### Basic port (Stage 1)
* First, remove all files and headers which use vgui (contains "vgui" in file name).
* After that, try to build it and remove vgui includes.
* Remove all gViewPort usings.
* Remove all CVoiceManager usings (xash3d does not support voice)
* Redefine all DLLEXPORT defines as empty field (Place it under _WIN32 macro if you want to keep windows compatibility).
* Remove hud_servers.cpp and Servers_Init/Servers_Shutdown from hud.cpp
* Remove hud_servers.cpp and Servers_Init/Servers_Shutdown from hud.cpp.
* Fix CAPS filenames in includes (like STDIO.H, replace by stdio.h).
* Replace broken macros as DECLARE_MESSAGE, DECLARE_COMMAND by fixed examples from our hlsdk-xash3d port (cl_util.h)
* Add ctype.h where it is need (tolower, isspace functions)
* Add string.h where it is need (memcpy, strcpy, etc)
* Use in_defs.h from hlsdk_client
* Add scoreboard_stub.cpp and input_stub.cpp from hlsdk-xash3d to fix linking.
Now your client should be able to build and work correctly. Add input_xash3d.cpp from hlsdk-xash3d project to fix input.
* Replace broken macros as DECLARE_MESSAGE, DECLARE_COMMAND by fixed examples from our hlsdk-portable port (cl_util.h).
* Add ctype.h where is needed (tolower, isspace functions).
* Add string.h where is needed (memcpy, strcpy, etc).
* Use in_defs.h from hlsdk-portable.
* Add input_xash3d.cpp from hlsdk-portable project to fix input.
#### Multiplayer fix (Stage 2)
Look at hlsdk-xash3d project.
Now your client should be able to build and work correctly.
Main changes are:
* Add MOTD.cpp, scoreboard.cpp and input_xash3d.cpp
* Add missing functions to hud_redraw.cpp, hud.cpp and tri.cpp, fix class defination in hud.h
* Remove duplicate functions from hud.cpp and HOOK_MESSAGE's for it
* Remove +showscores/-showscores hooks from input.h
* Fix cl_util.h
# Porting mod to hlsdk-portable
Look at changes which was made.
### Second way: move mod to hlsdk-xash3d
Look at changes you made in client.
If there are not too much changes (for example, only some weapons was added), add these changes in hlsdk-portable.
If there are not much changes (for example, only some weapons was add), add these changes in hlsdk-xash3d.
You may use diff with original HLSDK you used and apply it as patch to hlsdk-xash3d.
You can use diff with original HLSDK and apply it as patch to hlsdk-portable.
```
NOTE: Many an old mods was made on HLSDK 2.0-2.1 and some rare mods on HLSDK 1.0.
So you need to have different versions of HLSDK to make diffs.
Plus different Spirit of Half-Life versions if mod was made on it.
Also, weapons in old HLSDK versions does not use client weapon prediction system and you may be need to port standart half-life weapons to server side.
```
Files must have same line endings (use dos2unix on all files).
I recommend to enable ignoring space changes in diff.
### Writing Makefiles
We recommend to enable ignoring space changes in diff.
Use Makefile from hlsdk-xash3d as Makefile example.
Move all new files to separate directories.
Get .c and .cpp file lists from Visual Studio project and fill SRCS and SRCS_C variables to Makefile.
# Possible replacements for non-portable external dependencies
1. If mod uses **fmod.dll** or **base.dll** to play mp3/ogg on client-side or to precache sounds on server-side, you can replace it with:
- [pfnPrimeMusicStream](https://github.com/FWGS/hlsdk-portable/blob/master/engine/cdll_int.h#L293=) engine callback;
- [miniaudio](https://github.com/mackron/miniaudio);
- [phonon](https://community.kde.org/Phonon).
Remove all files containing vgui in name from list, add missing include dirs.
2. If mod uses **OpenGL**, porting code to Xash3D render interface is recommended.
3. If mod uses **cg.dll**, you can try to port code to [NVFX](https://github.com/tlorach/nvFX).
4. If mod uses detours, comment code or try to find replacement somehow by yourself.
# Additional recommendations
1. If mod uses STL, you can replace it with [MiniUTL](https://github.com/FWGS/MiniUTL).
2. Avoid to use dynamic casts to make small size binaries.
3. Avoid to use exceptions to make small size binaries.
# Writing build scripts
Use wscript/CMakeLists.txt files from hlsdk-portable as build scripts example.
Get .c and .cpp file lists from Visual Studio project.
Add missing include dirs.
Do same for Android.mk if you are building for android.

View File

@ -26,7 +26,8 @@ Table is sorted by status.
| Haiku | Supported | not maintained | Was added by #478 and #483
| DOS4GW | Supported | @mittorn |
| GNU/Linux(mipsel) | Supported | @mittorn |
| Switch | In progress | @fgsfdsfgs | [GitHub Repository](https://github.com/fgsfdsfgs/xash3d-fwgs/tree/switch_new)
| PSVita | Supported | @fgsfdsfgs |
| Switch | Supported | @fgsfdsfgs |
| Wii | In progress | Collaborative effort | [GitHub Repository](https://github.com/saucesaft/xash3d-wii)
| PSP | In progress | @Crow_bar, @Velaron | [GitHub Repository](https://github.com/Crow-bar/xash3d-fwgs)
| Emscripten | Old Engine | not maintained |

49
Documentation/psvita.md Normal file
View File

@ -0,0 +1,49 @@
## PlayStation Vita port
### Prerequisites
1. Make sure your PSVita is [set up to run homebrew applications](https://vita.hacks.guide/).
2. Install [kubridge](https://github.com/TheOfficialFloW/kubridge/releases/) by copying `kubridge.suprx` to your taiHEN plugins folder (usually `ux0:/tai`) and add it to your `config.txt`, for example:
```
*KERNEL
ux0:tai/kubridge.skprx
```
3. Install `libshacccg.suprx` by following [this guide](https://cimmerian.gitbook.io/vita-troubleshooting-guide/shader-compiler/extract-libshacccg.suprx).
### Installation
1. If you have an old vitaXash3D install, remove it.
2. Get `xash3d-fwgs-psvita.7z` from the latest [automatic build](https://github.com/FWGS/xash3d-fwgs/releases/tag/continuous).
3. Install `xash.vpk` from the 7z archive onto your PSVita.
4. Copy the `data` directory from the 7z archive to the root of your PSVita's SD card.
5. Copy the valve folder and any other mod folders from your Half-Life install to `ux0:/data/xash3d/` (you can use other mountpoints instead of `ux0`). **Do not overwrite anything.**
### Build instructions
1. Install [VitaSDK](https://vitasdk.org/).
2. Build and install [vitaGL](https://github.com/Rinnegatamante/vitaGL):
```
git clone https://github.com/Rinnegatamante/vitaGL.git
make -C vitaGL NO_TEX_COMBINER=1 HAVE_UNFLIPPED_FBOS=1 HAVE_PTHREAD=1 SINGLE_THREADED_GC=1 MATH_SPEEDHACK=1 DRAW_SPEEDHACK=1 HAVE_CUSTOM_HEAP=1 -j2 install
```
3. Build and install [vita-rtld](https://github.com/fgsfdsfgs/vita-rtld):
```
git clone https://github.com/fgsfdsfgs/vita-rtld.git && cd vita-rtld
mkdir build && cd build
cmake -DCMAKE_BUILD_TYPE=Release ..
make -j2 install
```
4. Build and install [this SDL2 fork](https://github.com/Northfear/SDL) with vitaGL integration:
```
git clone https://github.com/Northfear/SDL.git && cd SDL
mkdir build && cd build
cmake -DCMAKE_TOOLCHAIN_FILE=${VITASDK}/share/vita.toolchain.cmake -DCMAKE_BUILD_TYPE=Release -DVIDEO_VITA_VGL=ON ..
make -j2 install
```
5. Use `waf`:
```
./waf configure -T release --psvita
./waf build
```
6. Copy all the resulting `.so` files into a single folder:
```
./waf install --destdir=xash3d
```
7. `xash.vpk` is located in `build/engine/`.

View File

@ -70,7 +70,7 @@ SETUP BACKENDS DEFINITIONS
#define XASH_MESSAGEBOX MSGBOX_ANDROID
#endif // XASH_MESSAGEBOX
#define XASH_USE_EVDEV
#define XASH_USE_EVDEV 1
#define XASH_DYNAMIC_DLADDR
#elif XASH_LINUX
// we are building for Linux without SDL2, can draw only to framebuffer yet
@ -86,7 +86,7 @@ SETUP BACKENDS DEFINITIONS
#define XASH_SOUND SOUND_ALSA
#endif // XASH_SOUND
#define XASH_USE_EVDEV
#define XASH_USE_EVDEV 1
#elif XASH_DOS4GW
#ifndef XASH_VIDEO
#define XASH_VIDEO VIDEO_DOS
@ -165,6 +165,12 @@ Default build-depended cvar and constant values
#define DEFAULT_MODE_WIDTH 1280
#define DEFAULT_MODE_HEIGHT 720
#define DEFAULT_ALLOWCONSOLE 1
#elif XASH_PSVITA
#define DEFAULT_TOUCH_ENABLE "0"
#define DEFAULT_M_IGNORE "1"
#define DEFAULT_MODE_WIDTH 960
#define DEFAULT_MODE_HEIGHT 544
#define DEFAULT_ALLOWCONSOLE 1
#elif XASH_MOBILE_PLATFORM
#define DEFAULT_TOUCH_ENABLE "1"
#define DEFAULT_M_IGNORE "1"
@ -185,6 +191,10 @@ Default build-depended cvar and constant values
#define DEFAULT_M_IGNORE "0"
#endif // DEFAULT_M_IGNORE
#ifndef DEFAULT_JOY_DEADZONE
#define DEFAULT_JOY_DEADZONE "4096"
#endif // DEFAULT_JOY_DEADZONE
#ifndef DEFAULT_DEV
#define DEFAULT_DEV 0
#endif // DEFAULT_DEV

View File

@ -42,6 +42,10 @@ GNU General Public License for more details.
#if XASH_NSWITCH
#define SOLDER_LIBDL_COMPAT
#include <solder.h>
#elif XASH_PSVITA
#define VRTLD_LIBDL_COMPAT
#include <vrtld.h>
#define O_BINARY 0
#else
#include <dlfcn.h>
#define HAVE_DUP

View File

@ -50,6 +50,7 @@ typedef uint64_t longtime_t;
#define MAX_SERVERINFO_STRING 512 // server handles too many settings. expand to 1024?
#define MAX_LOCALINFO_STRING 32768 // localinfo used on server and not sended to the clients
#define MAX_SYSPATH 1024 // system filepath
#define MAX_VA_STRING 1024 // string length returned by va()
#define MAX_PRINT_MSG 8192 // how many symbols can handle single call of Con_Printf or Con_DPrintf
#define MAX_TOKEN 2048 // parse token length
#define MAX_MODS 512 // environment games that engine can keep visible

View File

@ -27,7 +27,6 @@ int AVI_GetAudioChunk( movie_state_t *Avi, char *audiodata, int offset, int leng
void AVI_OpenVideo( movie_state_t *Avi, const char *filename, qboolean load_audio, int quiet );
movie_state_t *AVI_LoadVideo( const char *filename, qboolean load_audio );
int AVI_TimeToSoundPosition( movie_state_t *Avi, int time );
int AVI_GetVideoFrameCount( movie_state_t *Avi );
void AVI_CloseVideo( movie_state_t *Avi );
qboolean AVI_IsActive( movie_state_t *Avi );
void AVI_FreeVideo( movie_state_t *Avi );

View File

@ -57,11 +57,6 @@ int AVI_TimeToSoundPosition( movie_state_t *Avi, int time )
return 0;
}
int AVI_GetVideoFrameCount( movie_state_t *Avi )
{
return 0;
}
void AVI_CloseVideo( movie_state_t *Avi )
{
;

View File

@ -1,5 +1,6 @@
/*
avi_win.c - playing AVI files (based on original AVIKit code, Win32 version)
Copyright (c) 2003-2004, Ruari O'Sullivan
Copyright (C) 2010 Uncle Mike
This program is free software: you can redistribute it and/or modify
@ -63,7 +64,7 @@ static int (_stdcall *pAVIStreamTimeToSample)( PAVISTREAM pavi, LONG lTime );
static void* (_stdcall *pAVIStreamGetFrame)( PGETFRAME pg, LONG lPos );
static int (_stdcall *pAVIStreamGetFrameClose)( PGETFRAME pg );
static dword (_stdcall *pAVIStreamRelease)( PAVISTREAM pavi );
static int (_stdcall *pAVIFileOpen)( PAVIFILE *ppfile, LPCSTR szFile, UINT uMode, LPCLSID lpHandler );
static int (_stdcall *pAVIFileOpenW)( PAVIFILE *ppfile, LPCWSTR szFile, UINT uMode, LPCLSID lpHandler );
static int (_stdcall *pAVIFileGetStream)( PAVIFILE pfile, PAVISTREAM *ppavi, DWORD fccType, LONG lParam );
static int (_stdcall *pAVIStreamReadFormat)( PAVISTREAM pavi, LONG lPos,LPVOID lpFormat, LONG *lpcbFormat );
static int (_stdcall *pAVIStreamStart)( PAVISTREAM pavi );
@ -76,7 +77,7 @@ static dllfunc_t avifile_funcs[] =
{ "AVIFileExit", (void **) &pAVIFileExit },
{ "AVIFileGetStream", (void **) &pAVIFileGetStream },
{ "AVIFileInit", (void **) &pAVIFileInit },
{ "AVIFileOpenA", (void **) &pAVIFileOpen },
{ "AVIFileOpenW", (void **) &pAVIFileOpenW },
{ "AVIFileRelease", (void **) &pAVIFileRelease },
{ "AVIStreamGetFrame", (void **) &pAVIStreamGetFrame },
{ "AVIStreamGetFrameClose", (void **) &pAVIStreamGetFrameClose },
@ -278,14 +279,6 @@ int AVI_GetVideoFrameNumber( movie_state_t *Avi, float time )
return (time * Avi->video_fps);
}
int AVI_GetVideoFrameCount( movie_state_t *Avi )
{
if( !Avi->active )
return 0;
return Avi->video_frames;
}
int AVI_TimeToSoundPosition( movie_state_t *Avi, int time )
{
if( !Avi->active || !Avi->audio_stream )
@ -493,6 +486,7 @@ void AVI_OpenVideo( movie_state_t *Avi, const char *filename, qboolean load_audi
AVISTREAMINFO stream_info;
int opened_streams = 0;
LONG hr;
wchar_t pathBuffer[MAX_PATH];
// default state: non-working.
Avi->active = false;
@ -501,8 +495,15 @@ void AVI_OpenVideo( movie_state_t *Avi, const char *filename, qboolean load_audi
// can't load Video For Windows :-(
if( !avi_initialized ) return;
// convert to wide char
if( MultiByteToWideChar( CP_UTF8, 0, filename, -1, pathBuffer, ARRAYSIZE( pathBuffer )) <= 0 )
{
Con_DPrintf( S_ERROR "filename buffer limit exceeded\n" );
return;
}
// load the AVI
hr = pAVIFileOpen( &Avi->pfile, filename, OF_SHARE_DENY_WRITE, 0L );
hr = pAVIFileOpenW( &Avi->pfile, pathBuffer, OF_SHARE_DENY_WRITE, 0L );
if( hr != 0 ) // error opening AVI:
{
@ -657,7 +658,7 @@ movie_state_t *AVI_LoadVideo( const char *filename, qboolean load_audio )
// open cinematic
Q_snprintf( path, sizeof( path ), "media/%s", filename );
COM_DefaultExtension( path, ".avi" );
COM_DefaultExtension( path, ".avi", sizeof( path ));
fullpath = FS_GetDiskPath( path, false );
if( FS_FileExists( path, false ) && !fullpath )

View File

@ -145,7 +145,7 @@ void CL_PlayCDTrack_f( void )
CL_ScreenshotGetName
==================
*/
qboolean CL_ScreenshotGetName( int lastnum, char *filename )
static qboolean CL_ScreenshotGetName( int lastnum, char *filename, size_t size )
{
if( lastnum < 0 || lastnum > 9999 )
{
@ -153,9 +153,7 @@ qboolean CL_ScreenshotGetName( int lastnum, char *filename )
return false;
}
Q_sprintf( filename, "scrshots/%s_shot%04d.png", clgame.mapname, lastnum );
return true;
return Q_snprintf( filename, size, "scrshots/%s_shot%04d.png", clgame.mapname, lastnum ) > 0;
}
/*
@ -163,7 +161,7 @@ qboolean CL_ScreenshotGetName( int lastnum, char *filename )
CL_SnapshotGetName
==================
*/
qboolean CL_SnapshotGetName( int lastnum, char *filename )
static qboolean CL_SnapshotGetName( int lastnum, char *filename, size_t size )
{
if( lastnum < 0 || lastnum > 9999 )
{
@ -172,9 +170,7 @@ qboolean CL_SnapshotGetName( int lastnum, char *filename )
return false;
}
Q_sprintf( filename, "../%s_%04d.png", clgame.mapname, lastnum );
return true;
return Q_snprintf( filename, size, "../%s_%04d.png", clgame.mapname, lastnum ) > 0;
}
/*
@ -207,7 +203,7 @@ void CL_ScreenShot_f( void )
// scan for a free filename
for( i = 0; i < 9999; i++ )
{
if( !CL_ScreenshotGetName( i, checkname ))
if( !CL_ScreenshotGetName( i, checkname, sizeof( checkname )))
return; // no namespace
if( !FS_FileExists( checkname, false ))
@ -247,7 +243,7 @@ void CL_SnapShot_f( void )
// scan for a free filename
for( i = 0; i < 9999; i++ )
{
if( !CL_SnapshotGetName( i, checkname ))
if( !CL_SnapshotGetName( i, checkname, sizeof( checkname )))
return; // no namespace
if( !FS_FileExists( checkname, false ))
@ -278,7 +274,7 @@ void CL_EnvShot_f( void )
return;
}
Q_sprintf( cls.shotname, "gfx/env/%s", Cmd_Argv( 1 ));
Q_snprintf( cls.shotname, sizeof( cls.shotname ), "gfx/env/%s", Cmd_Argv( 1 ));
cls.scrshot_action = scrshot_envshot; // build new frame for envshot
cls.envshot_vieworg = NULL; // no custom view
cls.envshot_viewsize = 0;
@ -299,7 +295,7 @@ void CL_SkyShot_f( void )
return;
}
Q_sprintf( cls.shotname, "gfx/env/%s", Cmd_Argv( 1 ));
Q_snprintf( cls.shotname, sizeof( cls.shotname ),"gfx/env/%s", Cmd_Argv( 1 ));
cls.scrshot_action = scrshot_skyshot; // build new frame for skyshot
cls.envshot_vieworg = NULL; // no custom view
cls.envshot_viewsize = 0;
@ -323,7 +319,8 @@ void CL_LevelShot_f( void )
// check for exist
if( cls.demoplayback && ( cls.demonum != -1 ))
{
Q_sprintf( cls.shotname, "levelshots/%s_%s.bmp", cls.demoname, refState.wideScreen ? "16x9" : "4x3" );
Q_snprintf( cls.shotname, sizeof( cls.shotname ),
"levelshots/%s_%s.bmp", cls.demoname, refState.wideScreen ? "16x9" : "4x3" );
Q_snprintf( filename, sizeof( filename ), "%s.dem", cls.demoname );
// make sure what levelshot is newer than demo
@ -332,7 +329,8 @@ void CL_LevelShot_f( void )
}
else
{
Q_sprintf( cls.shotname, "levelshots/%s_%s.bmp", clgame.mapname, refState.wideScreen ? "16x9" : "4x3" );
Q_snprintf( cls.shotname, sizeof( cls.shotname ),
"levelshots/%s_%s.bmp", clgame.mapname, refState.wideScreen ? "16x9" : "4x3" );
// make sure what levelshot is newer than bsp
ft1 = FS_FileTime( cl.worldmodel->name, false );
@ -360,7 +358,7 @@ void CL_SaveShot_f( void )
return;
}
Q_sprintf( cls.shotname, DEFAULT_SAVE_DIRECTORY "%s.bmp", Cmd_Argv( 1 ));
Q_snprintf( cls.shotname, sizeof( cls.shotname ), DEFAULT_SAVE_DIRECTORY "%s.bmp", Cmd_Argv( 1 ));
cls.scrshot_action = scrshot_savegame; // build new frame for saveshot
}

View File

@ -78,7 +78,7 @@ qboolean CL_CheckFile( sizebuf_t *msg, resource_t *pResource )
}
MSG_BeginClientCmd( msg, clc_stringcmd );
MSG_WriteString( msg, va( "dlfile %s", filepath ));
MSG_WriteStringf( msg, "dlfile %s", filepath );
host.downloadcount++;
return false;

View File

@ -45,7 +45,7 @@ const char *CL_MsgInfo( int cmd )
{
static string sz;
Q_strcpy( sz, "???" );
Q_strncpy( sz, "???", sizeof( sz ));
if( cmd >= 0 && cmd <= svc_lastmsg )
{

View File

@ -1317,16 +1317,16 @@ void CL_CheckStartupDemos( void )
CL_DemoGetName
==================
*/
static void CL_DemoGetName( int lastnum, char *filename )
static void CL_DemoGetName( int lastnum, char *filename, size_t size )
{
if( lastnum < 0 || lastnum > 9999 )
{
// bound
Q_strcpy( filename, "demo9999" );
Q_strncpy( filename, "demo9999.dem", size );
return;
}
Q_sprintf( filename, "demo%04d", lastnum );
Q_snprintf( filename, size, "demo%04d.dem", lastnum );
}
/*
@ -1380,8 +1380,8 @@ void CL_Record_f( void )
// scan for a free filename
for( n = 0; n < 10000; n++ )
{
CL_DemoGetName( n, demoname );
if( !FS_FileExists( va( "%s.dem", demoname ), true ))
CL_DemoGetName( n, demoname, sizeof( demoname ));
if( !FS_FileExists( demoname, true ))
break;
}
@ -1394,7 +1394,7 @@ void CL_Record_f( void )
else Q_strncpy( demoname, name, sizeof( demoname ));
// open the demo file
Q_sprintf( demopath, "%s.dem", demoname );
Q_snprintf( demopath, sizeof( demopath ), "%s.dem", demoname );
// make sure that old demo is removed
if( FS_FileExists( demopath, false ))

View File

@ -33,46 +33,6 @@ static mnode_t *r_pefragtopnode;
static vec3_t r_emins, r_emaxs;
static cl_entity_t *r_addent;
/*
================
R_RemoveEfrags
Call when removing an object from the world or moving it to another position
================
*/
void R_RemoveEfrags( cl_entity_t *ent )
{
efrag_t *ef, *old, *walk, **prev;
ef = ent->efrag;
while( ef )
{
prev = &ef->leaf->efrags;
while( 1 )
{
walk = *prev;
if( !walk ) break;
if( walk == ef )
{
// remove this fragment
*prev = ef->leafnext;
break;
}
else prev = &walk->leafnext;
}
old = ef;
ef = ef->entnext;
// put it on the free list
old->entnext = clgame.free_efrags;
clgame.free_efrags = old;
}
ent->efrag = NULL;
}
/*
===================
R_SplitEntityOnNode

View File

@ -140,26 +140,6 @@ void CL_FreeParticles( void )
cl_particles = NULL;
}
/*
================
CL_FreeParticle
move particle to freelist
================
*/
void CL_FreeParticle( particle_t *p )
{
if( p->deathfunc )
{
// call right the deathfunc before die
p->deathfunc( p );
p->deathfunc = NULL;
}
p->next = cl_free_particles;
cl_free_particles = p;
}
/*
================
CL_AllocParticleFast

View File

@ -260,6 +260,18 @@ int CL_DrawString( float x, float y, const char *s, rgba_t color, cl_font_t *fon
return draw_len;
}
int CL_DrawStringf( cl_font_t *font, float x, float y, rgba_t color, int flags, const char *fmt, ... )
{
va_list va;
char buf[MAX_VA_STRING];
va_start( va, fmt );
Q_vsnprintf( buf, sizeof( buf ), fmt, va );
va_end( va );
return CL_DrawString( x, y, buf, color, font, flags );
}
void CL_DrawCharacterLen( cl_font_t *font, int number, int *width, int *height )
{
if( !font || !font->valid ) return;

View File

@ -241,7 +241,7 @@ CL_GetStudioEstimatedFrame
====================
*/
float CL_GetStudioEstimatedFrame( cl_entity_t *ent )
static float CL_GetStudioEstimatedFrame( cl_entity_t *ent )
{
studiohdr_t *pstudiohdr;
mstudioseqdesc_t *pseqdesc;
@ -255,7 +255,7 @@ float CL_GetStudioEstimatedFrame( cl_entity_t *ent )
{
sequence = bound( 0, ent->curstate.sequence, pstudiohdr->numseq - 1 );
pseqdesc = (mstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex) + sequence;
return ref.dllFuncs.R_StudioEstimateFrame( ent, pseqdesc );
return ref.dllFuncs.R_StudioEstimateFrame( ent, pseqdesc, cl.time );
}
}
@ -654,6 +654,24 @@ FRAME PARSING
=========================================================================
*/
static qboolean CL_ParseEntityNumFromPacket( sizebuf_t *msg, int *newnum )
{
if( cls.legacymode )
{
*newnum = MSG_ReadWord( msg );
if( *newnum == 0 )
return false;
}
else
{
*newnum = MSG_ReadUBitLong( msg, MAX_ENTITY_BITS );
if( *newnum == LAST_EDICT )
return false;
}
return true;
}
/*
=================
CL_FlushEntityPacket
@ -674,8 +692,8 @@ void CL_FlushEntityPacket( sizebuf_t *msg )
// read it all, but ignore it
while( 1 )
{
newnum = MSG_ReadUBitLong( msg, MAX_ENTITY_BITS );
if( newnum == LAST_EDICT ) break; // done
if( !CL_ParseEntityNumFromPacket( msg, &newnum ))
break; // done
if( MSG_CheckOverflow( msg ))
Host_Error( "CL_FlushEntityPacket: overflow\n" );
@ -847,21 +865,12 @@ int CL_ParsePacketEntities( sizebuf_t *msg, qboolean delta )
while( 1 )
{
int lastedict;
if( cls.legacymode )
{
newnum = MSG_ReadWord( msg );
lastedict = 0;
}
else
{
newnum = MSG_ReadUBitLong( msg, MAX_ENTITY_BITS );
lastedict = LAST_EDICT;
}
if( !CL_ParseEntityNumFromPacket( msg, &newnum ))
break; // done
if( newnum == lastedict ) break; // end of packet entities
if( MSG_CheckOverflow( msg ))
Host_Error( "CL_ParsePacketEntities: overflow\n" );
player = CL_IsPlayerIndex( newnum );
while( oldnum < newnum )
@ -970,9 +979,25 @@ all the visible entities should pass this filter
*/
qboolean CL_AddVisibleEntity( cl_entity_t *ent, int entityType )
{
qboolean draw_player = true;
if( !ent || !ent->model )
return false;
// don't add the player in firstperson mode
if( RP_LOCALCLIENT( ent ))
{
cl.local.apply_effects = true;
if( !CL_IsThirdPerson( ) && ( ent->index == cl.viewentity ))
{
// we don't draw player in default renderer in firstperson mode
// but let the client.dll know about player entity anyway
// for use in custom renderers
draw_player = false;
}
}
// check for adding this entity
if( !clgame.dllFuncs.pfnAddEntity( entityType, ent, ent->model->name ))
{
@ -982,14 +1007,8 @@ qboolean CL_AddVisibleEntity( cl_entity_t *ent, int entityType )
return false;
}
// don't add the player in firstperson mode
if( RP_LOCALCLIENT( ent ))
{
cl.local.apply_effects = true;
if( !CL_IsThirdPerson( ) && ( ent->index == cl.viewentity ))
return false;
}
if( !draw_player )
return false;
if( entityType == ET_BEAM )
{

View File

@ -200,7 +200,7 @@ CL_InitCDAudio
Initialize CD playlist
====================
*/
void CL_InitCDAudio( const char *filename )
static void CL_InitCDAudio( const char *filename )
{
byte *afile;
char *pfile;
@ -221,8 +221,13 @@ void CL_InitCDAudio( const char *filename )
// format: trackname\n [num]
while(( pfile = COM_ParseFile( pfile, token, sizeof( token ))) != NULL )
{
if( !Q_stricmp( token, "blank" )) token[0] = '\0';
Q_strncpy( clgame.cdtracks[c], token, sizeof( clgame.cdtracks[0] ));
if( !Q_stricmp( token, "blank" ))
clgame.cdtracks[c][0] = '\0';
else
{
Q_snprintf( clgame.cdtracks[c], sizeof( clgame.cdtracks[c] ),
"media/%s", token );
}
if( ++c > MAX_CDTRACKS - 1 )
{
@ -590,7 +595,11 @@ static void CL_InitTitles( const char *filename )
// initialize text messages (game_text)
for( i = 0; i < MAX_TEXTCHANNELS; i++ )
{
cl_textmessage[i].pName = _copystring( clgame.mempool, va( TEXT_MSGNAME, i ), __FILE__, __LINE__ );
char name[MAX_VA_STRING];
Q_snprintf( name, sizeof( name ), TEXT_MSGNAME, i );
cl_textmessage[i].pName = _copystring( clgame.mempool, name, __FILE__, __LINE__ );
cl_textmessage[i].pMessage = cl_textbuffer[i];
}
@ -1060,23 +1069,18 @@ void CL_LinkUserMessage( char *pszName, const int svc_num, int iSize )
CL_ClearUserMessage( pszName, svc_num );
}
void CL_FreeEntity( cl_entity_t *pEdict )
{
Assert( pEdict != NULL );
R_RemoveEfrags( pEdict );
CL_KillDeadBeams( pEdict );
}
void CL_ClearWorld( void )
{
cl_entity_t *worldmodel;
if( clgame.entities ) // check if we have entities, legacy protocol support kinda breaks this logic
{
cl_entity_t *worldmodel = clgame.entities;
worldmodel = clgame.entities;
worldmodel->curstate.modelindex = 1; // world model
worldmodel->curstate.solid = SOLID_BSP;
worldmodel->curstate.movetype = MOVETYPE_PUSH;
worldmodel->model = cl.worldmodel;
worldmodel->index = 0;
worldmodel->curstate.modelindex = 1; // world model
worldmodel->curstate.solid = SOLID_BSP;
worldmodel->curstate.movetype = MOVETYPE_PUSH;
worldmodel->model = cl.worldmodel;
worldmodel->index = 0;
}
world.max_recursion = 0;
@ -1368,7 +1372,7 @@ pfnSPR_Frames
*/
int EXPORT pfnSPR_Frames( HSPRITE hPic )
{
int numFrames;
int numFrames = 0;
ref.dllFuncs.R_GetSpriteParms( NULL, NULL, &numFrames, 0, CL_GetSpritePointer( hPic ));
@ -1383,7 +1387,7 @@ pfnSPR_Height
*/
static int GAME_EXPORT pfnSPR_Height( HSPRITE hPic, int frame )
{
int sprHeight;
int sprHeight = 0;
ref.dllFuncs.R_GetSpriteParms( NULL, &sprHeight, NULL, frame, CL_GetSpritePointer( hPic ));
@ -1398,7 +1402,7 @@ pfnSPR_Width
*/
static int GAME_EXPORT pfnSPR_Width( HSPRITE hPic, int frame )
{
int sprWidth;
int sprWidth = 0;
ref.dllFuncs.R_GetSpriteParms( &sprWidth, NULL, NULL, frame, CL_GetSpritePointer( hPic ));
@ -1413,7 +1417,13 @@ pfnSPR_Set
*/
static void GAME_EXPORT pfnSPR_Set( HSPRITE hPic, int r, int g, int b )
{
clgame.ds.pSprite = CL_GetSpritePointer( hPic );
const model_t *sprite = CL_GetSpritePointer( hPic );
// a1ba: do not alter the state if invalid HSPRITE was passed
if( !sprite )
return;
clgame.ds.pSprite = sprite;
clgame.ds.spriteColor[0] = bound( 0, r, 255 );
clgame.ds.spriteColor[1] = bound( 0, g, 255 );
clgame.ds.spriteColor[2] = bound( 0, b, 255 );
@ -1717,14 +1727,12 @@ pfnServerCmd
*/
static int GAME_EXPORT pfnServerCmd( const char *szCmdString )
{
string buf;
if( !COM_CheckString( szCmdString ))
return 0;
// just like the client typed "cmd xxxxx" at the console
Q_snprintf( buf, sizeof( buf ) - 1, "cmd %s\n", szCmdString );
Cbuf_AddText( buf );
MSG_BeginClientCmd( &cls.netchan.message, clc_stringcmd );
MSG_WriteString( &cls.netchan.message, szCmdString );
return 1;
}
@ -1852,7 +1860,11 @@ client_textmessage_t *CL_TextMessageGet( const char *pName )
// first check internal messages
for( i = 0; i < MAX_TEXTCHANNELS; i++ )
{
if( !Q_strcmp( pName, va( TEXT_MSGNAME, i )))
char name[MAX_VA_STRING];
Q_snprintf( name, sizeof( name ), TEXT_MSGNAME, i );
if( !Q_strcmp( pName, name ))
return cl_textmessage + i;
}
@ -2112,58 +2124,52 @@ pfnCalcShake
*/
void GAME_EXPORT pfnCalcShake( void )
{
int i;
float fraction, freq;
float localAmp;
screen_shake_t *const shake = &clgame.shake;
float frametime, fraction, freq;
int i;
if( clgame.shake.time == 0 )
return;
if(( cl.time > clgame.shake.time ) || clgame.shake.amplitude <= 0 || clgame.shake.frequency <= 0 )
if( cl.time > shake->time || shake->amplitude <= 0 || shake->frequency <= 0 || shake->duration <= 0 )
{
memset( &clgame.shake, 0, sizeof( clgame.shake ));
// reset shake
if( shake->time != 0 )
{
shake->time = 0;
shake->applied_angle = 0;
VectorClear( shake->applied_offset );
}
return;
}
if( cl.time > clgame.shake.next_shake )
{
// higher frequency means we recalc the extents more often and perturb the display again
clgame.shake.next_shake = cl.time + ( 1.0f / clgame.shake.frequency );
frametime = cl_clientframetime();
// compute random shake extents (the shake will settle down from this)
if( cl.time > shake->next_shake )
{
// get next shake time based on frequency over duration
shake->next_shake = (float)cl.time + shake->frequency / shake->duration;
// randomize each shake
for( i = 0; i < 3; i++ )
clgame.shake.offset[i] = COM_RandomFloat( -clgame.shake.amplitude, clgame.shake.amplitude );
clgame.shake.angle = COM_RandomFloat( -clgame.shake.amplitude * 0.25f, clgame.shake.amplitude * 0.25f );
shake->offset[i] = COM_RandomFloat( -shake->amplitude, shake->amplitude );
shake->angle = COM_RandomFloat( -shake->amplitude * 0.25f, shake->amplitude * 0.25f );
}
// ramp down amplitude over duration (fraction goes from 1 to 0 linearly with slope 1/duration)
fraction = ( clgame.shake.time - cl.time ) / clgame.shake.duration;
// get initial fraction and frequency values over the duration
fraction = ((float)cl.time - shake->time ) / shake->duration;
freq = fraction != 0.0f ? ( shake->frequency / fraction ) * shake->frequency : 0.0f;
// ramp up frequency over duration
if( fraction )
{
freq = ( clgame.shake.frequency / fraction );
}
else
{
freq = 0;
}
// quickly approach zero but apply time over sine wave
fraction *= fraction * sin( cl.time * freq );
// square fraction to approach zero more quickly
fraction *= fraction;
// apply shake offset
for( i = 0; i < 3; i++ )
shake->applied_offset[i] = shake->offset[i] * fraction;
// Sine wave that slowly settles to zero
fraction = fraction * sin( cl.time * freq );
// apply roll angle
shake->applied_angle = shake->angle * fraction;
// add to view origin
VectorScale( clgame.shake.offset, fraction, clgame.shake.applied_offset );
// add to roll
clgame.shake.applied_angle = clgame.shake.angle * fraction;
// drop amplitude a bit, less for higher frequency shakes
localAmp = clgame.shake.amplitude * ( host.frametime / ( clgame.shake.duration * clgame.shake.frequency ));
clgame.shake.amplitude -= localAmp;
// decrease amplitude, but slower on longer shakes or higher frequency
shake->amplitude -= shake->amplitude * ( frametime / ( shake->frequency * shake->duration ));
}
/*
@ -2174,8 +2180,11 @@ pfnApplyShake
*/
void GAME_EXPORT pfnApplyShake( float *origin, float *angles, float factor )
{
if( origin ) VectorMA( origin, factor, clgame.shake.applied_offset, origin );
if( angles ) angles[ROLL] += clgame.shake.applied_angle * factor;
if( origin )
VectorMA( origin, factor, clgame.shake.applied_offset, origin );
if( angles )
angles[ROLL] += clgame.shake.applied_angle * factor;
}
/*
@ -2560,7 +2569,7 @@ const char *pfnGetGameDirectory( void )
{
static char szGetGameDir[MAX_SYSPATH];
Q_strcpy( szGetGameDir, GI->gamefolder );
Q_strncpy( szGetGameDir, GI->gamefolder, sizeof( szGetGameDir ));
return szGetGameDir;
}
@ -3359,8 +3368,7 @@ void GAME_EXPORT NetAPI_SendRequest( int context, int request, int flags, double
nr->resp.remote_address.port = MSG_BigShort( PORT_MASTER );
// grab the list from the master server
Q_strcpy( &fullquery[22], GI->gamefolder );
NET_SendPacket( NS_CLIENT, Q_strlen( GI->gamefolder ) + 23, fullquery, nr->resp.remote_address );
NET_SendPacket( NS_CLIENT, len, fullquery, nr->resp.remote_address );
clgame.request_type = NET_REQUEST_CLIENT;
clgame.master_request = nr; // holds the master request unitl the master acking
}

View File

@ -310,7 +310,7 @@ static void GAME_EXPORT UI_DrawLogo( const char *filename, float x, float y, flo
// run cinematic if not
Q_snprintf( path, sizeof( path ), "media/%s", filename );
COM_DefaultExtension( path, ".avi" );
COM_DefaultExtension( path, ".avi", sizeof( path ));
fullpath = FS_GetDiskPath( path, false );
if( FS_FileExists( path, false ) && !fullpath )
@ -839,7 +839,7 @@ send client connect
*/
static void GAME_EXPORT pfnClientJoin( const netadr_t adr )
{
Cbuf_AddText( va( "connect %s\n", NET_AdrToString( adr )));
Cbuf_AddTextf( "connect %s\n", NET_AdrToString( adr ));
}
/*

View File

@ -23,6 +23,7 @@ GNU General Public License for more details.
#include "library.h"
#include "vid_common.h"
#include "pm_local.h"
#include "sequence.h"
#define MAX_TOTAL_CMDS 32
#define MAX_CMD_BUFFER 8000
@ -149,16 +150,6 @@ qboolean CL_DisableVisibility( void )
return cls.envshot_disable_vis;
}
qboolean CL_IsBackgroundDemo( void )
{
return ( cls.demoplayback && cls.demonum != -1 );
}
qboolean CL_IsBackgroundMap( void )
{
return ( cl.background && !cls.demoplayback );
}
char *CL_Userinfo( void )
{
return cls.userinfo;
@ -239,6 +230,9 @@ void CL_SignonReply( void )
if( cl.proxy_redirect && !cls.spectator )
CL_Disconnect();
cl.proxy_redirect = false;
if( cls.demoplayback )
Sequence_OnLevelLoad( clgame.mapname );
break;
}
}
@ -1029,9 +1023,9 @@ void CL_SendConnectPacket( void )
Cvar_SetCheatState();
Cvar_FullSet( "sv_cheats", "0", FCVAR_READ_ONLY | FCVAR_SERVER );
Info_SetValueForKey( protinfo, "d", va( "%d", input_devices ), sizeof( protinfo ) );
Info_SetValueForKeyf( protinfo, "d", sizeof( protinfo ), "%d", input_devices );
Info_SetValueForKey( protinfo, "v", XASH_VERSION, sizeof( protinfo ) );
Info_SetValueForKey( protinfo, "b", va( "%d", Q_buildnum() ), sizeof( protinfo ) );
Info_SetValueForKeyf( protinfo, "b", sizeof( protinfo ), "%d", Q_buildnum( ));
Info_SetValueForKey( protinfo, "o", Q_buildos(), sizeof( protinfo ) );
Info_SetValueForKey( protinfo, "a", Q_buildarch(), sizeof( protinfo ) );
}
@ -1065,7 +1059,7 @@ void CL_SendConnectPacket( void )
Info_SetValueForKey( protinfo, "uuid", key, sizeof( protinfo ));
Info_SetValueForKey( protinfo, "qport", qport, sizeof( protinfo ));
Info_SetValueForKey( protinfo, "ext", va("%d", extensions), sizeof( protinfo ));
Info_SetValueForKeyf( protinfo, "ext", sizeof( protinfo ), "%d", extensions);
Netchan_OutOfBandPrint( NS_CLIENT, adr, "connect %i %i \"%s\" \"%s\"\n", PROTOCOL_VERSION, cls.challenge, protinfo, cls.userinfo );
Con_Printf( "Trying to connect by modern protocol\n" );
@ -1084,7 +1078,7 @@ Resend a connect message if the last one has timed out
void CL_CheckForResend( void )
{
netadr_t adr;
int res;
net_gai_state_t res;
qboolean bandwidthTest;
if( cls.internetservers_wait )
@ -1117,13 +1111,13 @@ void CL_CheckForResend( void )
res = NET_StringToAdrNB( cls.servername, &adr );
if( !res )
if( res == NET_EAI_NONAME )
{
CL_Disconnect();
return;
}
if( res == 2 )
if( res == NET_EAI_AGAIN )
{
cls.connect_time = MAX_HEARTBEAT;
return;
@ -1300,15 +1294,15 @@ void CL_Rcon_f( void )
NET_Config( true, false ); // allow remote
Q_strcat( message, "rcon " );
Q_strcat( message, rcon_password.string );
Q_strcat( message, " " );
Q_strncat( message, "rcon ", sizeof( message ));
Q_strncat( message, rcon_password.string, sizeof( message ));
Q_strncat( message, " ", sizeof( message ) );
for( i = 1; i < Cmd_Argc(); i++ )
{
Cmd_Escape( command, Cmd_Argv( i ), sizeof( command ));
Q_strcat( message, command );
Q_strcat( message, " " );
Q_strncat( message, command, sizeof( message ));
Q_strncat( message, " ", sizeof( message ));
}
if( cls.state >= ca_connected )
@ -2086,7 +2080,7 @@ void CL_ConnectionlessPacket( netadr_t from, sizebuf_t *msg )
if( NET_CompareAdr( from, cls.legacyserver ))
{
Cbuf_AddText( va( "connect %s legacy\n", NET_AdrToString( from )));
Cbuf_AddTextf( "connect %s legacy\n", NET_AdrToString( from ));
memset( &cls.legacyserver, 0, sizeof( cls.legacyserver ));
}
}
@ -2589,7 +2583,7 @@ void CL_ServerCommand( qboolean reliable, const char *fmt, ... )
return;
va_start( argptr, fmt );
Q_vsprintf( string, fmt, argptr );
Q_vsnprintf( string, sizeof( string ), fmt, argptr );
va_end( argptr );
if( reliable )
@ -2862,6 +2856,7 @@ void CL_InitLocal( void )
Cvar_RegisterVariable( &cl_test_bandwidth );
Voice_RegisterCvars();
VGui_RegisterCvars();
// register our variables
cl_crosshair = Cvar_Get( "crosshair", "1", FCVAR_ARCHIVE, "show weapon chrosshair" );
@ -3123,6 +3118,7 @@ void CL_Init( void )
VID_Init(); // init video
S_Init(); // init sound
Voice_Init( VOICE_DEFAULT_CODEC, 3 ); // init voice
Sequence_Init();
// unreliable buffer. unsed for unreliable commands and voice stream
MSG_Init( &cls.datagram, "cls.datagram", cls.datagram_buf, sizeof( cls.datagram_buf ));

View File

@ -393,10 +393,10 @@ static void NetGraph_DrawTextFields( int x, int y, int w, wrect_t rect, int coun
{
y -= net_graphheight->value;
CL_DrawString( x, y, va( "%.1f fps" , 1.0f / framerate ), colors, font, FONT_DRAW_NORENDERMODE );
CL_DrawStringf( font, x, y, colors, FONT_DRAW_NORENDERMODE, "%.1f fps" , 1.0f / framerate);
if( avg > 1.0f )
CL_DrawString( x + 75, y, va( "%i ms" , (int)avg ), colors, font, FONT_DRAW_NORENDERMODE );
CL_DrawStringf( font, x + 75, y, colors, FONT_DRAW_NORENDERMODE, "%i ms" , (int)avg );
y += 15;
@ -404,10 +404,12 @@ static void NetGraph_DrawTextFields( int x, int y, int w, wrect_t rect, int coun
if( !out ) out = lastout;
else lastout = out;
CL_DrawString( x, y, va( "in : %i %.2f kb/s", netstat_graph[j].msgbytes, cls.netchan.flow[FLOW_INCOMING].avgkbytespersec ), colors, font, FONT_DRAW_NORENDERMODE );
CL_DrawStringf( font, x, y, colors, FONT_DRAW_NORENDERMODE,
"in : %i %.2f kb/s", netstat_graph[j].msgbytes, cls.netchan.flow[FLOW_INCOMING].avgkbytespersec );
y += 15;
CL_DrawString( x, y, va( "out: %i %.2f kb/s", out, cls.netchan.flow[FLOW_OUTGOING].avgkbytespersec ), colors, font, FONT_DRAW_NORENDERMODE );
CL_DrawStringf( font, x, y, colors, FONT_DRAW_NORENDERMODE,
"out: %i %.2f kb/s", out, cls.netchan.flow[FLOW_OUTGOING].avgkbytespersec );
y += 15;
if( graphtype > 2 )
@ -415,14 +417,14 @@ static void NetGraph_DrawTextFields( int x, int y, int w, wrect_t rect, int coun
int loss = (int)(( packet_loss + PACKETLOSS_AVG_FRAC ) - 0.01f );
int choke = (int)(( packet_choke + PACKETCHOKE_AVG_FRAC ) - 0.01f );
CL_DrawString( x, y, va( "loss: %i choke: %i", loss, choke ), colors, font, FONT_DRAW_NORENDERMODE );
CL_DrawStringf( font, x, y, colors, FONT_DRAW_NORENDERMODE, "loss: %i choke: %i", loss, choke );
}
}
if( graphtype < 3 )
CL_DrawString( ptx, pty, va( "%i/s", (int)cl_cmdrate->value ), colors, font, FONT_DRAW_NORENDERMODE );
CL_DrawStringf( font, ptx, pty, colors, FONT_DRAW_NORENDERMODE, "%i/s", (int)cl_cmdrate->value );
CL_DrawString( ptx, last_y, va( "%i/s" , (int)cl_updaterate->value ), colors, font, FONT_DRAW_NORENDERMODE );
CL_DrawStringf( font, ptx, last_y, colors, FONT_DRAW_NORENDERMODE, "%i/s" , (int)cl_updaterate->value );
}
/*

View File

@ -499,7 +499,7 @@ void CL_BatchResourceRequest( qboolean initialize )
if( !FBitSet( p->ucFlags, RES_REQUESTED ))
{
MSG_BeginClientCmd( &msg, clc_stringcmd );
MSG_WriteString( &msg, va( "dlfile !MD5%s", MD5_Print( p->rgucMD5_hash ) ) );
MSG_WriteStringf( &msg, "dlfile !MD5%s", MD5_Print( p->rgucMD5_hash ));;
SetBits( p->ucFlags, RES_REQUESTED );
}
break;
@ -587,7 +587,7 @@ int CL_EstimateNeededResources( void )
return nTotalSize;
}
void CL_StartResourceDownloading( const char *pszMessage, qboolean bCustom )
static void CL_StartResourceDownloading( const char *pszMessage, qboolean bCustom )
{
resourceinfo_t ri;
@ -603,6 +603,8 @@ void CL_StartResourceDownloading( const char *pszMessage, qboolean bCustom )
}
else
{
HTTP_ResetProcessState();
cls.state = ca_validate;
cls.dl.custom = false;
}
@ -849,6 +851,8 @@ void CL_ParseServerData( sizebuf_t *msg, qboolean legacy )
qboolean background;
int i;
HPAK_CheckSize( CUSTOM_RES_PATH );
Con_Reportf( "%s packet received.\n", legacy ? "Legacy serverdata" : "Serverdata" );
cls.timestart = Sys_DoubleTime();
@ -1236,11 +1240,9 @@ CL_ParseSetAngle
set the view angle to this absolute value
================
*/
void CL_ParseSetAngle( sizebuf_t *msg )
static void CL_ParseSetAngle( sizebuf_t *msg )
{
cl.viewangles[0] = MSG_ReadBitAngle( msg, 16 );
cl.viewangles[1] = MSG_ReadBitAngle( msg, 16 );
cl.viewangles[2] = MSG_ReadBitAngle( msg, 16 );
MSG_ReadVec3Angles( msg, cl.viewangles );
}
/*
@ -1541,6 +1543,42 @@ void CL_SendConsistencyInfo( sizebuf_t *msg )
MSG_WriteOneBit( msg, 0 );
}
/*
==================
CL_StartDark
==================
*/
static void CL_StartDark( void )
{
if( Cvar_VariableValue( "v_dark" ))
{
screenfade_t *sf = &clgame.fade;
float fadetime = 5.0f;
client_textmessage_t *title;
title = CL_TextMessageGet( "GAMETITLE" );
if( Host_IsQuakeCompatible( ))
fadetime = 1.0f;
if( title )
{
// get settings from titles.txt
sf->fadeEnd = title->holdtime + title->fadeout;
sf->fadeReset = title->fadeout;
}
else sf->fadeEnd = sf->fadeReset = fadetime;
sf->fadeFlags = FFADE_IN;
sf->fader = sf->fadeg = sf->fadeb = 0;
sf->fadealpha = 255;
sf->fadeSpeed = (float)sf->fadealpha / sf->fadeReset;
sf->fadeReset += cl.time;
sf->fadeEnd += sf->fadeReset;
Cvar_SetValue( "v_dark", 0.0f );
}
}
/*
==================
CL_RegisterResources
@ -1590,6 +1628,9 @@ void CL_RegisterResources( sizebuf_t *msg )
// tell rendering system we have a new set of models.
ref.dllFuncs.R_NewMap ();
// check if this map must start from dark screen
CL_StartDark ();
CL_SetupOverviewParams();
// release unused SpriteTextures
@ -1607,7 +1648,7 @@ 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_WriteString( msg, va( "spawn %i", cl.servercount ));
MSG_WriteStringf( msg, "spawn %i", cl.servercount );
}
}
else
@ -1852,10 +1893,17 @@ Set screen shake
*/
void CL_ParseScreenShake( sizebuf_t *msg )
{
clgame.shake.amplitude = (float)(word)MSG_ReadShort( msg ) * (1.0f / (float)(1<<12));
clgame.shake.duration = (float)(word)MSG_ReadShort( msg ) * (1.0f / (float)(1<<12));
clgame.shake.frequency = (float)(word)MSG_ReadShort( msg ) * (1.0f / (float)(1<<8));
clgame.shake.time = cl.time + Q_max( clgame.shake.duration, 0.01f );
float amplitude = (float)(word)MSG_ReadShort( msg ) * ( 1.0f / (float)( 1 << 12 ));
float duration = (float)(word)MSG_ReadShort( msg ) * ( 1.0f / (float)( 1 << 12 ));
float frequency = (float)(word)MSG_ReadShort( msg ) * ( 1.0f / (float)( 1 << 8 ));
// don't overwrite larger existing shake
if( amplitude > clgame.shake.amplitude )
clgame.shake.amplitude = amplitude;
clgame.shake.duration = duration;
clgame.shake.time = cl.time + clgame.shake.duration;
clgame.shake.frequency = frequency;
clgame.shake.next_shake = 0.0f; // apply immediately
}
@ -1998,10 +2046,10 @@ void CL_ParseExec( sizebuf_t *msg )
{
Cbuf_AddText( "exec mapdefault.cfg\n" );
COM_FileBase( clgame.mapname, mapname );
COM_FileBase( clgame.mapname, mapname, sizeof( mapname ));
if ( COM_CheckString( mapname ) )
Cbuf_AddText( va( "exec %s.cfg\n", mapname ) );
Cbuf_AddTextf( "exec %s.cfg\n", mapname );
}
}
@ -2241,6 +2289,7 @@ void CL_ParseServerMessage( sizebuf_t *msg, qboolean normal_message )
else cls.state = ca_connecting;
cl.background = old_background;
cls.connect_time = MAX_HEARTBEAT;
cls.connect_retry = 0;
}
break;
case svc_setview:
@ -2665,15 +2714,14 @@ CL_ParseResourceList
void CL_LegacyParseResourceList( sizebuf_t *msg )
{
int i = 0;
static struct
{
int rescount;
int restype[MAX_LEGACY_RESOURCES];
char resnames[MAX_LEGACY_RESOURCES][MAX_QPATH];
} reslist;
memset( &reslist, 0, sizeof( reslist ));
memset( &reslist, 0, sizeof( reslist ));
reslist.rescount = MSG_ReadWord( msg ) - 1;
if( reslist.rescount > MAX_LEGACY_RESOURCES )
@ -2690,14 +2738,21 @@ void CL_LegacyParseResourceList( sizebuf_t *msg )
return;
}
HTTP_ResetProcessState();
host.downloadcount = 0;
for( i = 0; i < reslist.rescount; i++ )
{
char soundpath[MAX_VA_STRING];
const char *path;
if( reslist.restype[i] == t_sound )
path = va( DEFAULT_SOUNDPATH "%s", reslist.resnames[i] );
{
Q_snprintf( soundpath, sizeof( soundpath ), DEFAULT_SOUNDPATH "%s", reslist.resnames[i] );
path = soundpath;
}
else path = reslist.resnames[i];
if( FS_FileExists( path, false ))
@ -2816,6 +2871,7 @@ void CL_ParseLegacyServerMessage( sizebuf_t *msg, qboolean normal_message )
else cls.state = ca_connecting;
cl.background = old_background;
cls.connect_time = MAX_HEARTBEAT;
cls.connect_retry = 0;
}
break;
case svc_setview:
@ -2881,7 +2937,7 @@ void CL_ParseLegacyServerMessage( sizebuf_t *msg, qboolean normal_message )
cl.frames[cl.parsecountmod].graphdata.sound += MSG_GetNumBytesRead( msg ) - bufStart;
break;
case svc_spawnstatic:
CL_ParseStaticEntity( msg );
CL_LegacyParseStaticEntity( msg );
break;
case svc_event_reliable:
CL_ParseReliableEvent( msg );
@ -3078,7 +3134,7 @@ void CL_LegacyPrecache_f( void )
// done with all resources, issue prespawn command.
// Include server count in case server disconnects and changes level during d/l
MSG_BeginClientCmd( &cls.netchan.message, clc_stringcmd );
MSG_WriteString( &cls.netchan.message, va( "begin %i", spawncount ));
MSG_WriteStringf( &cls.netchan.message, "begin %i", spawncount );
cls.signon = SIGNONS;
}

View File

@ -157,7 +157,7 @@ void CL_UpdateStudioTexture( cl_entity_t *entity, mstudiotexture_t *ptexture, in
// build name of original texture
Q_strncpy( mdlname, entity->model->name, sizeof( mdlname ));
COM_FileBase( ptexture->name, name );
COM_FileBase( ptexture->name, name, sizeof( name ));
COM_StripExtension( mdlname );
Q_snprintf( texname, sizeof( texname ), "#%s/%s.mdl", mdlname, name );

View File

@ -405,12 +405,15 @@ static cldll_func_dst_t cldllFuncDst =
void CL_GetSecuredClientAPI( CL_EXPORT_FUNCS F )
{
cldll_func_src_t cldllFuncSrc = { 0 };
modfuncs_t modFuncs = { 0 };
// secured client dlls need these
*(cldll_func_dst_t **)&cldllFuncSrc.pfnVidInit = &cldllFuncDst;
*(modfuncs_t **)&cldllFuncSrc.pfnInitialize = &modFuncs;
cldll_func_src_t cldllFuncSrc =
{
(void *)&modFuncs,
NULL,
(void *)&cldllFuncDst
};
// trying to fill interface now
F( &cldllFuncSrc );

View File

@ -1245,37 +1245,28 @@ apply params for exploding sprite
*/
void GAME_EXPORT R_Sprite_Explode( TEMPENTITY *pTemp, float scale, int flags )
{
if( !pTemp ) return;
qboolean noadditive, drawalpha, rotate;
if( FBitSet( flags, TE_EXPLFLAG_NOADDITIVE ))
{
// solid sprite
pTemp->entity.curstate.rendermode = kRenderNormal;
pTemp->entity.curstate.renderamt = 255;
}
else if( FBitSet( flags, TE_EXPLFLAG_DRAWALPHA ))
{
// alpha sprite (came from hl2)
pTemp->entity.curstate.rendermode = kRenderTransAlpha;
pTemp->entity.curstate.renderamt = 180;
}
else
{
// additive sprite
pTemp->entity.curstate.rendermode = kRenderTransAdd;
pTemp->entity.curstate.renderamt = 180;
}
if( !pTemp )
return;
if( FBitSet( flags, TE_EXPLFLAG_ROTATE ))
{
// came from hl2
pTemp->entity.angles[2] = COM_RandomLong( 0, 360 );
}
noadditive = FBitSet( flags, TE_EXPLFLAG_NOADDITIVE );
drawalpha = FBitSet( flags, TE_EXPLFLAG_DRAWALPHA );
rotate = FBitSet( flags, TE_EXPLFLAG_ROTATE );
pTemp->entity.curstate.renderfx = kRenderFxNone;
pTemp->entity.baseline.origin[2] = 8;
pTemp->entity.origin[2] += 10;
pTemp->entity.curstate.scale = scale;
pTemp->entity.baseline.origin[2] = 8.0f;
pTemp->entity.origin[2] = pTemp->entity.origin[2] + 10.0f;
if( rotate )
pTemp->entity.angles[2] = COM_RandomFloat( 0.0, 360.0f );
pTemp->entity.curstate.rendermode = noadditive ? kRenderNormal :
drawalpha ? kRenderTransAlpha : kRenderTransAdd;
pTemp->entity.curstate.renderamt = noadditive ? 0xff : 0xb4;
pTemp->entity.curstate.renderfx = 0;
pTemp->entity.curstate.rendercolor.r = 0;
pTemp->entity.curstate.rendercolor.g = 0;
pTemp->entity.curstate.rendercolor.b = 0;
}
/*
@ -2932,7 +2923,9 @@ void CL_PlayerDecal( int playernum, int customIndex, int entityIndex, float *pos
if( !pCust->nUserData1 )
{
int sprayTextureIndex;
const char *decalname = va( "player%dlogo%d", playernum, customIndex );
char decalname[MAX_VA_STRING];
Q_snprintf( decalname, sizeof( decalname ), "player%dlogo%d", playernum, customIndex );
sprayTextureIndex = ref.dllFuncs.GL_FindTexture( decalname );
if( sprayTextureIndex != 0 )
{

View File

@ -229,6 +229,53 @@ void V_RefApplyOverview( ref_viewpass_t *rvp )
ref.dllFuncs.GL_OrthoBounds( mins, maxs );
}
/*
====================
V_CalcFov
====================
*/
static float V_CalcFov( float *fov_x, float width, float height )
{
float x, half_fov_y;
if( *fov_x < 1.0f || *fov_x > 179.0f )
*fov_x = 90.0f; // default value
x = width / tan( DEG2RAD( *fov_x ) * 0.5f );
half_fov_y = atan( height / x );
return RAD2DEG( half_fov_y ) * 2;
}
/*
====================
V_AdjustFov
====================
*/
static void V_AdjustFov( float *fov_x, float *fov_y, float width, float height, qboolean lock_x )
{
float x, y;
if( width * 3 == 4 * height || width * 4 == height * 5 )
{
// 4:3 or 5:4 ratio
return;
}
if( lock_x )
{
*fov_y = 2 * atan((width * 3) / (height * 4) * tan( *fov_y * M_PI_F / 360.0f * 0.5f )) * 360 / M_PI_F;
return;
}
y = V_CalcFov( fov_x, 640, 480 );
x = *fov_x;
*fov_x = V_CalcFov( &y, height, width );
if( *fov_x < x ) *fov_x = x;
else *fov_y = y;
}
/*
=============
V_GetRefParams

View File

@ -817,6 +817,7 @@ int CL_DrawCharacter( float x, float y, int number, rgba_t color, cl_font_t *fon
int CL_DrawString( float x, float y, const char *s, rgba_t color, cl_font_t *font, int flags );
void CL_DrawCharacterLen( cl_font_t *font, int number, int *width, int *height );
void CL_DrawStringLen( cl_font_t *font, const char *s, int *width, int *height, int flags );
int CL_DrawStringf( cl_font_t *font, float x, float y, rgba_t color, int flags, const char *fmt, ... ) _format( 6 );
//
@ -834,7 +835,6 @@ void CL_FreeEdicts( void );
void CL_ClearWorld( void );
void CL_DrawCenterPrint( void );
void CL_ClearSpriteTextures( void );
void CL_FreeEntity( cl_entity_t *pEdict );
void CL_CenterPrint( const char *text, float y );
void CL_TextMessageParse( byte *pMemFile, int fileSize );
client_textmessage_t *CL_TextMessageGet( const char *pName );
@ -891,7 +891,6 @@ void CL_ParseLegacyServerMessage( sizebuf_t *msg, qboolean normal_message );
void CL_LegacyPrecache_f( void );
void CL_ParseTempEntity( sizebuf_t *msg );
void CL_StartResourceDownloading( const char *pszMessage, qboolean bCustom );
qboolean CL_DispatchUserMessage( const char *pszName, int iSize, void *pbuf );
qboolean CL_RequestMissingResources( void );
void CL_RegisterResources ( sizebuf_t *msg );
@ -1002,7 +1001,6 @@ const ref_overview_t *GL_GetOverviewParms( void );
//
void R_StoreEfrags( efrag_t **ppefrag, int framecount );
void R_AddEfrags( cl_entity_t *ent );
void R_RemoveEfrags( cl_entity_t *ent );
//
// cl_tent.c
//
@ -1157,7 +1155,6 @@ void CL_PlayVideo_f( void );
// keys.c
//
int Key_IsDown( int keynum );
const char *Key_IsBind( int keynum );
void Key_Event( int key, int down );
void Key_Init( void );
void Key_WriteBindings( file_t *f );

View File

@ -213,37 +213,6 @@ void Con_ClearTyping( void )
Cmd_AutoCompleteClear();
}
/*
============
Con_StringLength
skipped color prefixes
============
*/
int Con_StringLength( const char *string )
{
int len;
const char *p;
if( !string ) return 0;
len = 0;
p = string;
while( *p )
{
if( IsColorString( p ))
{
p += 2;
continue;
}
len++;
p++;
}
return len;
}
/*
================
Con_MessageMode_f
@ -1596,13 +1565,13 @@ void Key_Console( int key )
}
// console scrolling
if( key == K_PGUP )
if( key == K_PGUP || key == K_DPAD_UP )
{
Con_PageUp( 1 );
return;
}
if( key == K_PGDN )
if( key == K_PGDN || key == K_DPAD_DOWN )
{
Con_PageDown( 1 );
return;
@ -2098,7 +2067,6 @@ void Con_DrawVersion( void )
Con_DrawStringLen( curbuild, &stringLen, &charH );
start = refState.width - stringLen * 1.05f;
stringLen = Con_StringLength( curbuild );
height -= charH * 1.05f;
Con_DrawString( start, height, curbuild, color );

View File

@ -393,10 +393,10 @@ void Joy_Init( void )
joy_forward_key_threshold = Cvar_Get( "joy_forward_key_threshold", "24576", FCVAR_ARCHIVE | FCVAR_FILTERABLE, "forward axis key event emit threshold. Value from 0 to 32767");
// by default, we rely on deadzone detection come from system, but some glitchy devices report false deadzones
joy_side_deadzone = Cvar_Get( "joy_side_deadzone", "0", FCVAR_ARCHIVE | FCVAR_FILTERABLE, "side axis deadzone. Value from 0 to 32767" );
joy_forward_deadzone = Cvar_Get( "joy_forward_deadzone", "0", FCVAR_ARCHIVE | FCVAR_FILTERABLE, "forward axis deadzone. Value from 0 to 32767");
joy_pitch_deadzone = Cvar_Get( "joy_pitch_deadzone", "0", FCVAR_ARCHIVE | FCVAR_FILTERABLE, "pitch axis deadzone. Value from 0 to 32767");
joy_yaw_deadzone = Cvar_Get( "joy_yaw_deadzone", "0", FCVAR_ARCHIVE | FCVAR_FILTERABLE, "yaw axis deadzone. Value from 0 to 32767" );
joy_side_deadzone = Cvar_Get( "joy_side_deadzone", DEFAULT_JOY_DEADZONE, FCVAR_ARCHIVE | FCVAR_FILTERABLE, "side axis deadzone. Value from 0 to 32767" );
joy_forward_deadzone = Cvar_Get( "joy_forward_deadzone", DEFAULT_JOY_DEADZONE, FCVAR_ARCHIVE | FCVAR_FILTERABLE, "forward axis deadzone. Value from 0 to 32767");
joy_pitch_deadzone = Cvar_Get( "joy_pitch_deadzone", DEFAULT_JOY_DEADZONE, FCVAR_ARCHIVE | FCVAR_FILTERABLE, "pitch axis deadzone. Value from 0 to 32767");
joy_yaw_deadzone = Cvar_Get( "joy_yaw_deadzone", DEFAULT_JOY_DEADZONE, FCVAR_ARCHIVE | FCVAR_FILTERABLE, "yaw axis deadzone. Value from 0 to 32767" );
joy_axis_binding = Cvar_Get( "joy_axis_binding", "sfpyrl", FCVAR_ARCHIVE | FCVAR_FILTERABLE, "axis hardware id to engine inner axis binding, "
"s - side, f - forward, y - yaw, p - pitch, r - left trigger, l - right trigger" );

View File

@ -87,7 +87,7 @@ typedef struct touchbuttonlist_s
touch_button_t *last;
} touchbuttonlist_t;
struct touch_s
static struct touch_s
{
qboolean initialized;
qboolean config_loaded;
@ -340,7 +340,7 @@ static void Touch_ExportConfig_f( void )
if( Q_strstr( name, "touch_presets/" ))
{
COM_FileBase( name, profilebase );
COM_FileBase( name, profilebase, sizeof( profilebase ));
Q_snprintf( profilename, sizeof( profilebase ), "touch_profiles/%s (copy).cfg", profilebase );
}
else Q_strncpy( profilename, name, sizeof( profilename ));
@ -737,7 +737,7 @@ static void Touch_ReloadConfig_f( void )
touch.edit = touch.selection = NULL;
touch.resize_finger = touch.move_finger = touch.look_finger = touch.wheel_finger = -1;
Cbuf_AddText( va("exec %s\n", touch_config_file->string ) );
Cbuf_AddTextf( "exec %s\n", touch_config_file->string );
}
static touch_button_t *Touch_AddButton( touchbuttonlist_t *list,
@ -1111,7 +1111,7 @@ static void Touch_InitConfig( void )
//pfnGetScreenInfo( NULL ); //HACK: update hud screen parameters like iHeight
if( FS_FileExists( touch_config_file->string, true ) )
{
Cbuf_AddText( va( "exec \"%s\"\n", touch_config_file->string ) );
Cbuf_AddTextf( "exec \"%s\"\n", touch_config_file->string );
Cbuf_Execute();
}
else
@ -1498,9 +1498,9 @@ static void Touch_EditMove( touchEventType type, int fingerID, float x, float y,
touch.hidebutton->flags &= ~TOUCH_FL_HIDE;
if( FBitSet( button->flags, TOUCH_FL_HIDE ))
Q_strcpy( touch.hidebutton->texturefile, "touch_default/edit_show" );
Q_strncpy( touch.hidebutton->texturefile, "touch_default/edit_show", sizeof( touch.hidebutton->texturefile ));
else
Q_strcpy( touch.hidebutton->texturefile, "touch_default/edit_hide" );
Q_strncpy( touch.hidebutton->texturefile, "touch_default/edit_hide", sizeof( touch.hidebutton->texturefile ));
}
}
if( type == event_motion ) // shutdown button move

View File

@ -176,14 +176,14 @@ void IN_ToggleClientMouse( int newstate, int oldstate )
// since SetCursorType controls cursor visibility
// execute it first, and then check mouse grab state
if( newstate == key_menu || newstate == key_console || newstate == key_message )
if( newstate == key_menu || newstate == key_console )
{
Platform_SetCursorType( dc_arrow );
#if XASH_ANDROID
Android_ShowMouse( true );
#endif
#ifdef XASH_USE_EVDEV
#if XASH_USE_EVDEV
Evdev_SetGrab( false );
#endif
}
@ -194,7 +194,7 @@ void IN_ToggleClientMouse( int newstate, int oldstate )
#if XASH_ANDROID
Android_ShowMouse( false );
#endif
#ifdef XASH_USE_EVDEV
#if XASH_USE_EVDEV
Evdev_SetGrab( true );
#endif
}
@ -214,7 +214,7 @@ void IN_CheckMouseState( qboolean active )
static qboolean s_bRawInput, s_bMouseGrab;
#if XASH_WIN32
qboolean useRawInput = CVAR_TO_BOOL( m_rawinput ) && clgame.client_dll_uses_sdl || clgame.dllFuncs.pfnLookEvent;
qboolean useRawInput = ( CVAR_TO_BOOL( m_rawinput ) && clgame.client_dll_uses_sdl ) || clgame.dllFuncs.pfnLookEvent != NULL;
#else
qboolean useRawInput = true; // always use SDL code
#endif
@ -399,7 +399,7 @@ void IN_Shutdown( void )
{
IN_DeactivateMouse( );
#ifdef XASH_USE_EVDEV
#if XASH_USE_EVDEV
Evdev_Shutdown();
#endif
@ -426,7 +426,7 @@ void IN_Init( void )
Touch_Init();
#ifdef XASH_USE_EVDEV
#if XASH_USE_EVDEV
Evdev_Init();
#endif
}
@ -532,7 +532,7 @@ static void IN_CollectInput( float *forward, float *side, float *pitch, float *y
*pitch += y * m_pitch->value;
*yaw -= x * m_yaw->value;
#ifdef XASH_USE_EVDEV
#if XASH_USE_EVDEV
IN_EvdevMove( yaw, pitch );
#endif
}
@ -590,7 +590,7 @@ void IN_EngineAppendMove( float frametime, void *cmd1, qboolean active )
void IN_Commands( void )
{
#ifdef XASH_USE_EVDEV
#if XASH_USE_EVDEV
IN_EvdevFrame();
#endif

View File

@ -159,18 +159,6 @@ int GAME_EXPORT Key_IsDown( int keynum )
return keys[keynum].down;
}
/*
===================
Key_GetBind
===================
*/
const char *Key_IsBind( int keynum )
{
if( keynum == -1 || !keys[keynum].binding )
return NULL;
return keys[keynum].binding;
}
/*
===================
Key_StringToKeynum
@ -446,8 +434,8 @@ void Key_Bind_f( void )
for( i = 2; i < c; i++ )
{
Q_strcat( cmd, Cmd_Argv( i ));
if( i != ( c - 1 )) Q_strcat( cmd, " " );
Q_strncat( cmd, Cmd_Argv( i ), sizeof( cmd ));
if( i != ( c - 1 )) Q_strncat( cmd, " ", sizeof( cmd ));
}
Key_SetBinding( b, cmd );
@ -553,8 +541,8 @@ void Key_AddKeyCommands( int key, const char *kb, qboolean down )
if( button[0] == '+' )
{
// button commands add keynum as a parm
if( down ) Q_sprintf( cmd, "%s %i\n", button, key );
else Q_sprintf( cmd, "-%s %i\n", button + 1, key );
if( down ) Q_snprintf( cmd, sizeof( cmd ), "%s %i\n", button, key );
else Q_snprintf( cmd, sizeof( cmd ), "-%s %i\n", button + 1, key );
Cbuf_AddText( cmd );
}
else if( down )
@ -842,7 +830,7 @@ void GAME_EXPORT Key_SetKeyDest( int key_dest )
cls.key_dest = key_menu;
break;
case key_console:
#if !XASH_NSWITCH // if we don't disable this, pops up the keyboard during load
#if !XASH_NSWITCH && !XASH_PSVITA // if we don't disable this, pops up the keyboard during load
Key_EnableTextInput( true, false );
#endif
cls.key_dest = key_console;

View File

@ -75,16 +75,6 @@ static void pfnStudioEvent( const mstudioevent_t *event, const cl_entity_t *e )
clgame.dllFuncs.pfnStudioEvent( event, e );
}
static efrag_t* pfnGetEfragsFreeList( void )
{
return clgame.free_efrags;
}
static void pfnSetEfragsFreeList( efrag_t *list )
{
clgame.free_efrags = list;
}
static model_t *pfnGetDefaultSprite( enum ref_defaultsprite_e spr )
{
switch( spr )
@ -225,7 +215,7 @@ static qboolean R_DoResetGamma( void )
static qboolean R_Init_Video_( const int type )
{
host.apply_opengl_config = true;
Cbuf_AddText( va( "exec %s.cfg", ref.dllFuncs.R_GetConfigName()));
Cbuf_AddTextf( "exec %s.cfg", ref.dllFuncs.R_GetConfigName());
Cbuf_Execute();
host.apply_opengl_config = false;
@ -527,7 +517,7 @@ static void R_GetRendererName( char *dest, size_t size, const char *opt )
else
{
// full path
Q_strcpy( dest, opt );
Q_strncpy( dest, opt, size );
}
}
@ -571,66 +561,68 @@ static void SetWidthAndHeightFromCommandLine( void )
static void SetFullscreenModeFromCommandLine( void )
{
#if !XASH_MOBILE_PLATFORM
if ( Sys_CheckParm("-fullscreen") )
if( Sys_CheckParm( "-fullscreen" ))
{
Cvar_Set( "fullscreen", "1" );
}
else if ( Sys_CheckParm( "-windowed" ) )
else if( Sys_CheckParm( "-windowed" ))
{
Cvar_Set( "fullscreen", "0" );
}
#endif
}
void R_CollectRendererNames( void )
static void R_CollectRendererNames( void )
{
const char *renderers[] = DEFAULT_RENDERERS;
int i, cur;
cur = 0;
for( i = 0; i < DEFAULT_RENDERERS_LEN; i++ )
// ordering is important!
static const char *shortNames[] =
{
string temp;
void *dll, *pfn;
#if XASH_REF_GL_ENABLED
"gl",
#endif
#if XASH_REF_NANOGL_ENABLED
"gles1",
#endif
#if XASH_REF_GLWES_ENABLED
"gles2",
#endif
#if XASH_REF_GL4ES_ENABLED
"gl4es",
#endif
#if XASH_REF_SOFT_ENABLED
"soft",
#endif
#if XASH_REF_VULKAN_ENABLED
"vk"
#endif
};
R_GetRendererName( temp, sizeof( temp ), renderers[i] );
// ordering is important here too!
static const char *readableNames[ARRAYSIZE( shortNames )] =
{
#if XASH_REF_GL_ENABLED
"OpenGL",
#endif
#if XASH_REF_NANOGL_ENABLED
"GLES1 (NanoGL)",
#endif
#if XASH_REF_GLWES_ENABLED
"GLES2 (gl-wes-v2)",
#endif
#if XASH_REF_GL4ES_ENABLED
"GL4ES",
#endif
#if XASH_REF_SOFT_ENABLED
"Software",
#endif
#if XASH_REF_VULKAN_ENABLED
"Vulkan"
#endif
};
dll = COM_LoadLibrary( temp, false, true );
if( !dll )
{
Con_Reportf( "R_CollectRendererNames: can't load library %s: %s\n", temp, COM_GetLibraryError() );
continue;
}
pfn = COM_GetProcAddress( dll, GET_REF_API );
if( !pfn )
{
Con_Reportf( "R_CollectRendererNames: can't find API entry point in %s\n", temp );
COM_FreeLibrary( dll );
continue;
}
Q_strncpy( ref.shortNames[cur], renderers[i], sizeof( ref.shortNames[cur] ));
pfn = COM_GetProcAddress( dll, GET_REF_HUMANREADABLE_NAME );
if( !pfn ) // just in case
{
Con_Reportf( "R_CollectRendererNames: can't find GetHumanReadableName export in %s\n", temp );
Q_strncpy( ref.readableNames[cur], renderers[i], sizeof( ref.readableNames[cur] ));
}
else
{
REF_HUMANREADABLE_NAME GetHumanReadableName = (REF_HUMANREADABLE_NAME)pfn;
GetHumanReadableName( ref.readableNames[cur], sizeof( ref.readableNames[cur] ));
}
Con_Printf( "Found renderer %s: %s\n", ref.shortNames[cur], ref.readableNames[cur] );
cur++;
COM_FreeLibrary( dll );
}
ref.numRenderers = cur;
ref.numRenderers = ARRAYSIZE( shortNames );
ref.shortNames = shortNames;
ref.readableNames = readableNames;
}
const ref_device_t *R_GetRenderDevice( unsigned int idx )
@ -746,30 +738,28 @@ qboolean R_Init( void )
// 1. Command line `-ref` argument.
// 2. `ref_dll` cvar.
// 3. Detected renderers in `DEFAULT_RENDERERS` order.
requested[0] = '\0';
if( !Sys_GetParmFromCmdLine( "-ref", requested ) && COM_CheckString( r_refdll->string ) )
// r_refdll is set to empty by default, so we can change hardcoded defaults just in case
Q_strncpy( requested, r_refdll->string, sizeof( requested ) );
requested[0] = 0;
if ( requested[0] )
if( !success && Sys_GetParmFromCmdLine( "-ref", requested ))
success = R_LoadRenderer( requested );
if( !success && COM_CheckString( r_refdll->string ))
{
Q_strncpy( requested, r_refdll->string, sizeof( requested ));
success = R_LoadRenderer( requested );
}
if( !success )
{
int i;
// cycle through renderers that we collected in CollectRendererNames
for( i = 0; i < ref.numRenderers; i++ )
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, ref.shortNames[i] ))
continue;
success = R_LoadRenderer( ref.shortNames[i] );
// yay, found working one
if( success )
break;
}
}

View File

@ -27,9 +27,10 @@ struct ref_state_s
HINSTANCE hInstance;
ref_interface_t dllFuncs;
// depends on build configuration
int numRenderers;
string shortNames[DEFAULT_RENDERERS_LEN];
string readableNames[DEFAULT_RENDERERS_LEN];
const char **shortNames;
const char **readableNames;
};
extern struct ref_state_s ref;

View File

@ -159,7 +159,7 @@ void S_UpdateSoundFade( void )
}
// spline it.
f = SimpleSpline( f );
f = -( cos( M_PI * f ) - 1 ) / 2;
f = bound( 0.0f, f, 1.0f );
soundfade.percent = soundfade.initial_percent * f;
@ -1292,36 +1292,6 @@ void S_StreamAviSamples( void *Avi, int entnum, float fvol, float attn, float sy
}
}
/*
===================
S_GetRawSamplesLength
===================
*/
uint S_GetRawSamplesLength( int entnum )
{
rawchan_t *ch;
if( !( ch = S_FindRawChannel( entnum, false )))
return 0;
return ch->s_rawend <= paintedtime ? 0 : (float)(ch->s_rawend - paintedtime) * DMA_MSEC_PER_SAMPLE;
}
/*
===================
S_ClearRawChannel
===================
*/
void S_ClearRawChannel( int entnum )
{
rawchan_t *ch;
if( !( ch = S_FindRawChannel( entnum, false )))
return;
ch->s_rawend = 0;
}
/*
===================
S_FreeIdleRawChannels
@ -1842,8 +1812,12 @@ void S_Music_f( void )
for( i = 0; i < 2; i++ )
{
const char *intro_path = va( "media/%s.%s", intro, ext[i] );
const char *main_path = va( "media/%s.%s", main, ext[i] );
char intro_path[MAX_VA_STRING];
char main_path[MAX_VA_STRING];
char track_path[MAX_VA_STRING];
Q_snprintf( intro_path, sizeof( intro_path ), "media/%s.%s", intro, ext[i] );
Q_snprintf( main_path, sizeof( main_path ), "media/%s.%s", main, ext[i] );
if( FS_FileExists( intro_path, false ) && FS_FileExists( main_path, false ))
{
@ -1851,7 +1825,10 @@ void S_Music_f( void )
S_StartBackgroundTrack( intro, main, 0, false );
break;
}
else if( FS_FileExists( va( "media/%s.%s", track, ext[i] ), false ))
Q_snprintf( track_path, sizeof( track_path ), "media/%s.%s", track, ext[i] );
if( FS_FileExists( track_path, false ))
{
// single non-looped theme
S_StartBackgroundTrack( track, NULL, 0, false );

View File

@ -117,13 +117,6 @@ _inline void MIX_ActivatePaintbuffer( int ipaintbuffer )
paintbuffers[ipaintbuffer].factive = true;
}
// don't mix into this paintbuffer
_inline void MIX_DeactivatePaintbuffer( int ipaintbuffer )
{
Assert( ipaintbuffer < CPAINTBUFFERS );
paintbuffers[ipaintbuffer].factive = false;
}
_inline void MIX_SetCurrentPaintbuffer( int ipaintbuffer )
{
Assert( ipaintbuffer < CPAINTBUFFERS );
@ -169,12 +162,6 @@ _inline void MIX_ResetPaintbufferFilterCounters( void )
paintbuffers[i].ifilter = FILTERTYPE_NONE;
}
_inline void MIX_ResetPaintbufferFilterCounter( int ipaintbuffer )
{
Assert( ipaintbuffer < CPAINTBUFFERS );
paintbuffers[ipaintbuffer].ifilter = 0;
}
// return pointer to front paintbuffer pbuf, given index
_inline portable_samplepair_t *MIX_GetPFrontFromIPaint( int ipaintbuffer )
{

View File

@ -95,7 +95,7 @@ void S_StartBackgroundTrack( const char *introTrack, const char *mainTrack, int
else Q_strncpy( s_bgTrack.loopName, mainTrack, sizeof( s_bgTrack.loopName ));
// open stream
s_bgTrack.stream = FS_OpenStream( va( "media/%s", introTrack ));
s_bgTrack.stream = FS_OpenStream( introTrack );
Q_strncpy( s_bgTrack.current, introTrack, sizeof( s_bgTrack.current ));
memset( &musicfade, 0, sizeof( musicfade )); // clear any soundfade
s_bgTrack.source = cls.key_dest;
@ -242,7 +242,7 @@ void S_StreamBackgroundTrack( void )
if( s_bgTrack.loopName[0] )
{
FS_FreeStream( s_bgTrack.stream );
s_bgTrack.stream = FS_OpenStream( va( "media/%s", s_bgTrack.loopName ));
s_bgTrack.stream = FS_OpenStream( s_bgTrack.loopName );
Q_strncpy( s_bgTrack.current, s_bgTrack.loopName, sizeof( s_bgTrack.current ));
if( !s_bgTrack.stream ) return;

View File

@ -142,7 +142,7 @@ static const char *VOX_GetDirectory( char *szpath, const char *psz, int nsize )
if( !p )
{
Q_strcpy( szpath, "vox/" );
Q_strncpy( szpath, "vox/", nsize );
return psz;
}

View File

@ -276,8 +276,6 @@ void S_RawEntSamples( int entnum, uint samples, uint rate, word width, word chan
void S_RawSamples( uint samples, uint rate, word width, word channels, const byte *data, int entnum );
void S_StopSound( int entnum, int channel, const char *soundname );
void S_UpdateFrame( struct ref_viewpass_s *rvp );
uint S_GetRawSamplesLength( int entnum );
void S_ClearRawChannel( int entnum );
void S_StopAllSounds( qboolean ambient );
void S_FreeSounds( void );

View File

@ -218,6 +218,7 @@ void CL_TextMessageParse( byte *pMemFile, int fileSize )
client_textmessage_t textMessages[MAX_MESSAGES];
int i, nameHeapSize, textHeapSize, messageSize, nameOffset;
int messageCount, lastNamePos;
size_t textHeapSizeRemaining;
lastNamePos = 0;
lineNumber = 0;
@ -252,7 +253,7 @@ void CL_TextMessageParse( byte *pMemFile, int fileSize )
Con_Reportf( "TextMessage: unexpected '}' found, line %d\n", lineNumber );
return;
}
Q_strcpy( currentName, trim );
Q_strncpy( currentName, trim, sizeof( currentName ));
break;
case MSGFILE_TEXT:
if( IsEndOfText( trim ))
@ -266,7 +267,7 @@ void CL_TextMessageParse( byte *pMemFile, int fileSize )
return;
}
Q_strcpy( nameHeap + lastNamePos, currentName );
Q_strncpy( nameHeap + lastNamePos, currentName, sizeof( nameHeap ) - lastNamePos );
// terminate text in-place in the memory file
// (it's temporary memory that will be deleted)
@ -329,15 +330,20 @@ void CL_TextMessageParse( byte *pMemFile, int fileSize )
// copy text & fixup pointers
textHeapSizeRemaining = textHeapSize;
pCurrentText = pNameHeap + nameHeapSize;
for( i = 0; i < messageCount; i++ )
{
size_t currentTextSize = Q_strlen( clgame.titles[i].pMessage ) + 1;
clgame.titles[i].pName = pNameHeap; // adjust name pointer (parallel buffer)
Q_strcpy( pCurrentText, clgame.titles[i].pMessage ); // copy text over
Q_strncpy( pCurrentText, clgame.titles[i].pMessage, textHeapSizeRemaining ); // copy text over
clgame.titles[i].pMessage = pCurrentText;
pNameHeap += Q_strlen( pNameHeap ) + 1;
pCurrentText += Q_strlen( pCurrentText ) + 1;
pCurrentText += currentTextSize;
textHeapSizeRemaining -= currentTextSize;
}
if(( pCurrentText - (char *)clgame.titles ) != ( textHeapSize + nameHeapSize + messageSize ))

View File

@ -17,10 +17,20 @@ GNU General Public License for more details.
#include "base_cmd.h"
#include "cdll_int.h"
// TODO: use another hash function, as COM_HashKey depends on string length
#define HASH_SIZE 128 // 128 * 4 * 4 == 2048 bytes
typedef struct base_command_hashmap_s
{
base_command_t *basecmd; // base command: cvar, alias or command
const char *name; // key for searching
base_command_type_e type; // type for faster searching
struct base_command_hashmap_s *next;
} base_command_hashmap_t;
static base_command_hashmap_t *hashed_cmds[HASH_SIZE];
#define BaseCmd_HashKey( x ) COM_HashKey( name, HASH_SIZE )
/*
============
BaseCmd_FindInBucket
@ -28,7 +38,7 @@ BaseCmd_FindInBucket
Find base command in bucket
============
*/
base_command_hashmap_t *BaseCmd_FindInBucket( base_command_hashmap_t *bucket, base_command_type_e type, const char *name )
static base_command_hashmap_t *BaseCmd_FindInBucket( base_command_hashmap_t *bucket, base_command_type_e type, const char *name )
{
base_command_hashmap_t *i = bucket;
for( ; i && ( i->type != type || Q_stricmp( name, i->name ) ); // filter out
@ -44,9 +54,9 @@ BaseCmd_GetBucket
Get bucket which contain basecmd by given name
============
*/
base_command_hashmap_t *BaseCmd_GetBucket( const char *name )
static base_command_hashmap_t *BaseCmd_GetBucket( const char *name )
{
return hashed_cmds[ COM_HashKey( name, HASH_SIZE ) ];
return hashed_cmds[ BaseCmd_HashKey( name ) ];
}
/*
@ -73,7 +83,7 @@ BaseCmd_Find
Find every type of base command and write into arguments
============
*/
void BaseCmd_FindAll(const char *name, base_command_t **cmd, base_command_t **alias, base_command_t **cvar)
void BaseCmd_FindAll( const char *name, base_command_t **cmd, base_command_t **alias, base_command_t **cvar )
{
base_command_hashmap_t *base = BaseCmd_GetBucket( name );
base_command_hashmap_t *i = base;
@ -101,7 +111,6 @@ void BaseCmd_FindAll(const char *name, base_command_t **cmd, base_command_t **al
}
}
}
}
/*
@ -113,41 +122,23 @@ Add new typed base command to hashmap
*/
void BaseCmd_Insert( base_command_type_e type, base_command_t *basecmd, const char *name )
{
uint hash = COM_HashKey( name, HASH_SIZE );
base_command_hashmap_t *elem;
base_command_hashmap_t *elem, *cur, *find;
uint hash = BaseCmd_HashKey( name );
elem = Z_Malloc( sizeof( base_command_hashmap_t ) );
elem->basecmd = basecmd;
elem->type = type;
elem->name = name;
elem->next = hashed_cmds[hash];
hashed_cmds[hash] = elem;
}
/*
============
BaseCmd_Replace
// link the variable in alphanumerical order
for( cur = NULL, find = hashed_cmds[hash];
find && Q_strcmp( find->name, elem->name ) < 0;
cur = find, find = find->next );
Used in case, when basecmd has been registered, but gamedll wants to register it's own
============
*/
qboolean BaseCmd_Replace( base_command_type_e type, base_command_t *basecmd, const char *name )
{
base_command_hashmap_t *i = BaseCmd_GetBucket( name );
if( cur ) cur->next = elem;
else hashed_cmds[hash] = elem;
for( ; i && ( i->type != type || Q_stricmp( name, i->name ) ) ; // filter out
i = i->next );
if( !i )
{
Con_Reportf( S_ERROR "BaseCmd_Replace: couldn't find %s\n", name);
return false;
}
i->basecmd = basecmd;
i->name = name; // may be freed after
return true;
elem->next = find;
}
/*
@ -159,7 +150,7 @@ Remove base command from hashmap
*/
void BaseCmd_Remove( base_command_type_e type, const char *name )
{
uint hash = COM_HashKey( name, HASH_SIZE );
uint hash = BaseCmd_HashKey( name );
base_command_hashmap_t *i, *prev;
for( prev = NULL, i = hashed_cmds[hash]; i &&
@ -221,23 +212,27 @@ void BaseCmd_Stats_f( void )
if( len > maxsize )
maxsize = len;
}
Con_Printf( "Base command stats:\n");
Con_Printf( "Bucket minimal length: %d\n", minsize );
Con_Printf( "Bucket maximum length: %d\n", maxsize );
Con_Printf( "Empty buckets: %d\n", empty );
Con_Printf( "min length: %d, max length: %d, empty: %d\n", minsize, maxsize, empty );
}
typedef struct
{
qboolean valid;
int lookups;
} basecmd_test_stats_t;
static void BaseCmd_CheckCvars( const char *key, const char *value, const void *unused, void *ptr )
{
base_command_t *v = BaseCmd_Find( HM_CVAR, key );
qboolean *invalid = ptr;
basecmd_test_stats_t *stats = ptr;
if( !v )
stats->lookups++;
if( !BaseCmd_Find( HM_CVAR, key ))
{
Con_Printf( "Cvar %s is missing in basecmd\n", key );
*invalid = true;
stats->valid = false;
}
}
@ -250,38 +245,51 @@ testing order matches cbuf execute
*/
void BaseCmd_Test_f( void )
{
void *cmd;
cmdalias_t *a;
qboolean invalid = false;
basecmd_test_stats_t stats;
double start, end, dt;
int i;
// Cmd_LookupCmds don't allows to check alias, so just iterate
for( a = Cmd_AliasGetList(); a; a = a->next )
stats.valid = true;
stats.lookups = 0;
start = Sys_DoubleTime() * 1000;
for( i = 0; i < 1000; i++ )
{
base_command_t *v = BaseCmd_Find( HM_CMDALIAS, a->name );
cmdalias_t *a;
void *cmd;
if( !v )
// Cmd_LookupCmds don't allows to check alias, so just iterate
for( a = Cmd_AliasGetList(); a; a = a->next, stats.lookups++ )
{
Con_Printf( "Alias %s is missing in basecmd\n", a->name );
invalid = true;
if( !BaseCmd_Find( HM_CMDALIAS, a->name ))
{
Con_Printf( "Alias %s is missing in basecmd\n", a->name );
stats.valid = false;
}
}
for( cmd = Cmd_GetFirstFunctionHandle(); cmd;
cmd = Cmd_GetNextFunctionHandle( cmd ), stats.lookups++ )
{
if( !BaseCmd_Find( HM_CMD, Cmd_GetName( cmd )))
{
Con_Printf( "Command %s is missing in basecmd\n", Cmd_GetName( cmd ));
stats.valid = false;
}
}
Cvar_LookupVars( 0, NULL, &stats.valid, (setpair_t)BaseCmd_CheckCvars );
}
for( cmd = Cmd_GetFirstFunctionHandle(); cmd;
cmd = Cmd_GetNextFunctionHandle( cmd ) )
{
base_command_t *v = BaseCmd_Find( HM_CMD, Cmd_GetName( cmd ) );
end = Sys_DoubleTime() * 1000;
if( !v )
{
Con_Printf( "Command %s is missing in basecmd\n", Cmd_GetName( cmd ) );
invalid = true;
}
}
dt = end - start;
Cvar_LookupVars( 0, NULL, &invalid, (setpair_t)BaseCmd_CheckCvars );
if( !invalid )
{
if( !stats.valid )
Con_Printf( "BaseCmd is valid\n" );
}
Con_Printf( "Test took %.3f ms, %d lookups, %.3f us/lookup\n", dt, stats.lookups, dt / stats.lookups * 1000 );
BaseCmd_Stats_f();
}

View File

@ -17,8 +17,6 @@ GNU General Public License for more details.
#ifndef BASE_CMD_H
#define BASE_CMD_H
// TODO: Find cases when command hashmap works incorrect
// and maybe disable it
#define XASH_HASHED_VARS
#ifdef XASH_HASHED_VARS
@ -33,23 +31,13 @@ typedef enum base_command_type
typedef void base_command_t;
typedef struct base_command_hashmap_s
{
base_command_t *basecmd; // base command: cvar, alias or command
const char *name; // key for searching
base_command_type_e type; // type for faster searching
struct base_command_hashmap_s *next;
} base_command_hashmap_t;
void BaseCmd_Init( void );
base_command_hashmap_t *BaseCmd_GetBucket( const char *name );
base_command_hashmap_t *BaseCmd_FindInBucket( base_command_hashmap_t *bucket, base_command_type_e type, const char *name );
base_command_t *BaseCmd_Find( base_command_type_e type, const char *name );
void BaseCmd_FindAll( const char *name,
base_command_t **cmd, base_command_t **alias, base_command_t **cvar );
void BaseCmd_Insert ( base_command_type_e type, base_command_t *basecmd, const char *name );
qboolean BaseCmd_Replace( base_command_type_e type, base_command_t *basecmd, const char *name ); // only if same name
void BaseCmd_Remove ( base_command_type_e type, const char *name );
void BaseCmd_Stats_f( void ); // to be registered later
void BaseCmd_Test_f( void ); // to be registered later

View File

@ -120,6 +120,18 @@ void Cbuf_AddText( const char *text )
Cbuf_AddTextToBuffer( &cmd_text, text );
}
void Cbuf_AddTextf( const char *fmt, ... )
{
va_list va;
char buf[MAX_VA_STRING];
va_start( va, fmt );
Q_vsnprintf( buf, sizeof( buf ), fmt, va );
va_end( va );
Cbuf_AddText( buf );
}
/*
============
Cbuf_AddFilteredText
@ -1150,13 +1162,13 @@ void Cmd_ForwardToServer( void )
str[0] = 0;
if( Q_stricmp( Cmd_Argv( 0 ), "cmd" ))
{
Q_strcat( str, Cmd_Argv( 0 ));
Q_strcat( str, " " );
Q_strncat( str, Cmd_Argv( 0 ), sizeof( str ));
Q_strncat( str, " ", sizeof( str ));
}
if( Cmd_Argc() > 1 )
Q_strcat( str, Cmd_Args( ));
else Q_strcat( str, "\n" );
Q_strncat( str, Cmd_Args( ), sizeof( str ));
else Q_strncat( str, "\n", sizeof( str ));
MSG_WriteString( &cls.netchan.message, str );
}
@ -1254,21 +1266,21 @@ static void Cmd_Apropos_f( void )
cmdalias_t *alias;
const char *partial;
int count = 0;
qboolean ispattern;
char buf[MAX_VA_STRING];
if( Cmd_Argc() > 1 )
{
partial = Cmd_Args();
}
else
if( Cmd_Argc() < 2 )
{
Msg( "apropos what?\n" );
return;
}
ispattern = partial && Q_strpbrk( partial, "*?" );
if( !ispattern )
partial = va( "*%s*", partial );
partial = Cmd_Args();
if( !Q_strpbrk( partial, "*?" ))
{
Q_snprintf( buf, sizeof( buf ), "*%s*", partial );
partial = buf;
}
for( var = (convar_t*)Cvar_GetList(); var; var = var->next )
{

View File

@ -68,8 +68,4 @@ GNU General Public License for more details.
#define XASH_VERSION "0.20" // engine current version
#define XASH_COMPAT_VERSION "0.99" // version we are based on
// renderers order is important, software is always a last chance fallback
#define DEFAULT_RENDERERS { "vk", "gl", "gles1", "gles2", "gl4es", "soft" }
#define DEFAULT_RENDERERS_LEN 6
#endif//COM_STRINGS_H

View File

@ -151,6 +151,30 @@ int GAME_EXPORT COM_RandomLong( int lLow, int lHigh )
return lLow + (n % x);
}
/*
============
va
does a varargs printf into a temp buffer,
so I don't need to have varargs versions
of all text functions.
============
*/
char *va( const char *format, ... )
{
va_list argptr;
static char string[16][MAX_VA_STRING], *s;
static int stringindex = 0;
s = string[stringindex];
stringindex = (stringindex + 1) & 15;
va_start( argptr, format );
Q_vsnprintf( s, sizeof( string[0] ), format, argptr );
va_end( argptr );
return s;
}
/*
===============================================================================
@ -540,7 +564,7 @@ int GAME_EXPORT COM_ExpandFilename( const char *fileName, char *nameOutBuffer, i
// models\barney.mdl - D:\Xash3D\bshift\models\barney.mdl
if(( path = FS_GetDiskPath( fileName, false )) != NULL )
{
Q_sprintf( result, "%s/%s", host.rootdir, path );
Q_snprintf( result, sizeof( result ), "%s/%s", host.rootdir, path );
// check for enough room
if( Q_strlen( result ) > nameOutBufferSize )
@ -876,9 +900,7 @@ cvar_t *pfnCvar_RegisterClientVariable( const char *szName, const char *szValue,
if( !Q_stricmp( szName, "motdfile" ))
flags |= FCVAR_PRIVILEGED;
if( FBitSet( flags, FCVAR_GLCONFIG ))
return (cvar_t *)Cvar_Get( szName, szValue, flags, va( CVAR_GLCONFIG_DESCRIPTION, szName ));
return (cvar_t *)Cvar_Get( szName, szValue, flags|FCVAR_CLIENTDLL, Cvar_BuildAutoDescription( flags|FCVAR_CLIENTDLL ));
return (cvar_t *)Cvar_Get( szName, szValue, flags|FCVAR_CLIENTDLL, Cvar_BuildAutoDescription( szName, flags|FCVAR_CLIENTDLL ));
}
/*
@ -889,9 +911,7 @@ pfnCvar_RegisterVariable
*/
cvar_t *pfnCvar_RegisterGameUIVariable( const char *szName, const char *szValue, int flags )
{
if( FBitSet( flags, FCVAR_GLCONFIG ))
return (cvar_t *)Cvar_Get( szName, szValue, flags, va( CVAR_GLCONFIG_DESCRIPTION, szName ));
return (cvar_t *)Cvar_Get( szName, szValue, flags|FCVAR_GAMEUIDLL, Cvar_BuildAutoDescription( flags|FCVAR_GAMEUIDLL ));
return (cvar_t *)Cvar_Get( szName, szValue, flags|FCVAR_GAMEUIDLL, Cvar_BuildAutoDescription( szName, flags|FCVAR_GAMEUIDLL ));
}
/*
@ -986,7 +1006,7 @@ pfnGetGameDir
void GAME_EXPORT pfnGetGameDir( char *szGetGameDir )
{
if( !szGetGameDir ) return;
Q_strcpy( szGetGameDir, GI->gamefolder );
Q_strncpy( szGetGameDir, GI->gamefolder, sizeof( GI->gamefolder ));
}
qboolean COM_IsSafeFileToDownload( const char *filename )
@ -1033,15 +1053,32 @@ qboolean COM_IsSafeFileToDownload( const char *filename )
return true;
}
const char *COM_GetResourceTypeName( resourcetype_t restype )
{
switch( restype )
{
case t_decal: return "decal";
case t_eventscript: return "eventscript";
case t_generic: return "generic";
case t_model: return "model";
case t_skin: return "skin";
case t_sound: return "sound";
case t_world: return "world";
default: return "unknown";
}
}
char *_copystring( poolhandle_t mempool, const char *s, const char *filename, int fileline )
{
size_t size;
char *b;
if( !s ) return NULL;
if( !mempool ) mempool = host.mempool;
b = _Mem_Alloc( mempool, Q_strlen( s ) + 1, false, filename, fileline );
Q_strcpy( b, s );
size = Q_strlen( s ) + 1;
b = _Mem_Alloc( mempool, size, false, filename, fileline );
Q_strncpy( b, s, size );
return b;
}
@ -1066,7 +1103,6 @@ void *GAME_EXPORT pfnSequenceGet( const char *fileName, const char *entryName )
{
Msg( "Sequence_Get: file %s, entry %s\n", fileName, entryName );
return Sequence_Get( fileName, entryName );
}

View File

@ -425,6 +425,7 @@ void FS_Shutdown( void );
void Cbuf_Init( void );
void Cbuf_Clear( void );
void Cbuf_AddText( const char *text );
void Cbuf_AddTextf( const char *text, ... ) _format( 1 );
void Cbuf_AddFilteredText( const char *text );
void Cbuf_InsertText( const char *text );
void Cbuf_ExecStuffCmds( void );
@ -565,6 +566,7 @@ int FS_GetStreamPos( stream_t *stream );
void FS_FreeStream( stream_t *stream );
qboolean Sound_Process( wavdata_t **wav, int rate, int width, uint flags );
uint Sound_GetApproxWavePlayLen( const char *filepath );
qboolean Sound_SupportedFileFormat( const char *fileext );
//
// host.c
@ -636,6 +638,7 @@ 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 );
qboolean COM_IsSafeFileToDownload( const char *filename );
const char *COM_GetResourceTypeName( resourcetype_t restype );
cvar_t *pfnCVarGetPointer( const char *szVarName );
int pfnDrawConsoleString( int x, int y, char *string );
void pfnDrawSetTextColor( float r, float g, float b );
@ -777,8 +780,6 @@ int SV_GetMaxClients( void );
qboolean CL_IsRecordDemo( void );
qboolean CL_IsTimeDemo( void );
qboolean CL_IsPlaybackDemo( void );
qboolean CL_IsBackgroundDemo( void );
qboolean CL_IsBackgroundMap( void );
qboolean SV_Initialized( void );
qboolean CL_LoadProgs( const char *name );
void CL_ProcessFile( qboolean successfully_received, const char *filename );
@ -818,6 +819,7 @@ const char *Info_ValueForKey( const char *s, const char *key );
void Info_RemovePrefixedKeys( char *start, char prefix );
qboolean Info_RemoveKey( char *s, const char *key );
qboolean Info_SetValueForKey( char *s, const char *key, const char *value, int maxsize );
qboolean Info_SetValueForKeyf( char *s, const char *key, int maxsize, const char *format, ... ) _format( 4 );
qboolean Info_SetValueForStarKey( char *s, const char *key, const char *value, int maxsize );
qboolean Info_IsValid( const char *s );
void Info_WriteVars( file_t *f );
@ -843,6 +845,7 @@ void COM_NormalizeAngles( vec3_t angles );
int COM_FileSize( const char *filename );
void COM_FreeFile( void *buffer );
int COM_CompareFileTime( const char *filename1, const char *filename2, int *iCompare );
char *va( const char *format, ... ) _format( 1 );
// soundlib shared exports
qboolean S_Init( void );
@ -855,7 +858,6 @@ void S_StopAllSounds( qboolean ambient );
// gamma routines
void BuildGammaTable( float gamma, float brightness );
byte LightToTexGamma( byte b );
byte TextureToGamma( byte b );
//
// identification.c
@ -871,6 +873,10 @@ void NET_InitMasters( void );
void NET_SaveMasters( void );
qboolean NET_SendToMasters( netsrc_t sock, size_t len, const void *data );
qboolean NET_IsMasterAdr( netadr_t adr );
void NET_MasterHeartbeat( void );
void NET_MasterClear( void );
void NET_MasterShutdown( void );
qboolean NET_GetMaster( netadr_t from, uint *challenge, double *last_heartbeat );
#ifdef REF_DLL
#error "common.h in ref_dll"

View File

@ -101,8 +101,7 @@ int Cmd_ListMaps( search_t *t, char *lastmapname, size_t len )
if( hdrext->id == IDEXTRAHEADER ) version = hdrext->version;
Q_strncpy( entfilename, t->filenames[i], sizeof( entfilename ));
COM_StripExtension( entfilename );
COM_DefaultExtension( entfilename, ".ent" );
COM_ReplaceExtension( entfilename, ".ent", sizeof( entfilename ));
ents = (char *)FS_LoadFile( entfilename, NULL, true );
if( !ents && lumplen >= 10 )
@ -146,7 +145,7 @@ int Cmd_ListMaps( search_t *t, char *lastmapname, size_t len )
}
if( f ) FS_Close(f);
COM_FileBase( t->filenames[i], mapname );
COM_FileBase( t->filenames[i], mapname, sizeof( mapname ));
switch( ver )
{
@ -194,7 +193,7 @@ qboolean Cmd_GetMapList( const char *s, char *completedname, int length )
t = FS_Search( va( "maps/%s*.bsp", s ), true, con_gamemaps->value );
if( !t ) return false;
COM_FileBase( t->filenames[0], matchbuf );
COM_FileBase( t->filenames[0], matchbuf, sizeof( matchbuf ));
if( completedname && length )
Q_strncpy( completedname, matchbuf, length );
if( t->numfilenames == 1 ) return true;
@ -231,7 +230,7 @@ qboolean Cmd_GetDemoList( const char *s, char *completedname, int length )
t = FS_Search( va( "%s*.dem", s ), true, true );
if( !t ) return false;
COM_FileBase( t->filenames[0], matchbuf );
COM_FileBase( t->filenames[0], matchbuf, sizeof( matchbuf ));
if( completedname && length )
Q_strncpy( completedname, matchbuf, length );
if( t->numfilenames == 1 ) return true;
@ -241,7 +240,7 @@ qboolean Cmd_GetDemoList( const char *s, char *completedname, int length )
if( Q_stricmp( COM_FileExtension( t->filenames[i] ), "dem" ))
continue;
COM_FileBase( t->filenames[i], matchbuf );
COM_FileBase( t->filenames[i], matchbuf, sizeof( matchbuf ));
Con_Printf( "%16s\n", matchbuf );
numdems++;
}
@ -277,7 +276,7 @@ qboolean Cmd_GetMovieList( const char *s, char *completedname, int length )
t = FS_Search( va( "media/%s*.avi", s ), true, false );
if( !t ) return false;
COM_FileBase( t->filenames[0], matchbuf );
COM_FileBase( t->filenames[0], matchbuf, sizeof( matchbuf ));
if( completedname && length )
Q_strncpy( completedname, matchbuf, length );
if( t->numfilenames == 1 ) return true;
@ -287,7 +286,7 @@ qboolean Cmd_GetMovieList( const char *s, char *completedname, int length )
if( Q_stricmp( COM_FileExtension( t->filenames[i] ), "avi" ))
continue;
COM_FileBase( t->filenames[i], matchbuf );
COM_FileBase( t->filenames[i], matchbuf, sizeof( matchbuf ));
Con_Printf( "%16s\n", matchbuf );
nummovies++;
}
@ -324,7 +323,7 @@ qboolean Cmd_GetMusicList( const char *s, char *completedname, int length )
t = FS_Search( va( "media/%s*.*", s ), true, false );
if( !t ) return false;
COM_FileBase( t->filenames[0], matchbuf );
COM_FileBase( t->filenames[0], matchbuf, sizeof( matchbuf ));
if( completedname && length )
Q_strncpy( completedname, matchbuf, length );
if( t->numfilenames == 1 ) return true;
@ -336,7 +335,7 @@ qboolean Cmd_GetMusicList( const char *s, char *completedname, int length )
if( Q_stricmp( ext, "wav" ) && Q_stricmp( ext, "mp3" ))
continue;
COM_FileBase( t->filenames[i], matchbuf );
COM_FileBase( t->filenames[i], matchbuf, sizeof( matchbuf ));
Con_Printf( "%16s\n", matchbuf );
numtracks++;
}
@ -372,7 +371,7 @@ qboolean Cmd_GetSavesList( const char *s, char *completedname, int length )
t = FS_Search( va( DEFAULT_SAVE_DIRECTORY "%s*.sav", s ), true, true ); // lookup only in gamedir
if( !t ) return false;
COM_FileBase( t->filenames[0], matchbuf );
COM_FileBase( t->filenames[0], matchbuf, sizeof( matchbuf ));
if( completedname && length )
Q_strncpy( completedname, matchbuf, length );
if( t->numfilenames == 1 ) return true;
@ -382,7 +381,7 @@ qboolean Cmd_GetSavesList( const char *s, char *completedname, int length )
if( Q_stricmp( COM_FileExtension( t->filenames[i] ), "sav" ))
continue;
COM_FileBase( t->filenames[i], matchbuf );
COM_FileBase( t->filenames[i], matchbuf, sizeof( matchbuf ));
Con_Printf( "%16s\n", matchbuf );
numsaves++;
}
@ -419,7 +418,7 @@ qboolean Cmd_GetConfigList( const char *s, char *completedname, int length )
t = FS_Search( va( "%s*.cfg", s ), true, false );
if( !t ) return false;
COM_FileBase( t->filenames[0], matchbuf );
COM_FileBase( t->filenames[0], matchbuf, sizeof( matchbuf ));
if( completedname && length )
Q_strncpy( completedname, matchbuf, length );
if( t->numfilenames == 1 ) return true;
@ -429,7 +428,7 @@ qboolean Cmd_GetConfigList( const char *s, char *completedname, int length )
if( Q_stricmp( COM_FileExtension( t->filenames[i] ), "cfg" ))
continue;
COM_FileBase( t->filenames[i], matchbuf );
COM_FileBase( t->filenames[i], matchbuf, sizeof( matchbuf ));
Con_Printf( "%16s\n", matchbuf );
numconfigs++;
}
@ -519,7 +518,7 @@ qboolean Cmd_GetItemsList( const char *s, char *completedname, int length )
t = FS_Search( va( "%s/%s*.txt", clgame.itemspath, s ), true, false );
if( !t ) return false;
COM_FileBase( t->filenames[0], matchbuf );
COM_FileBase( t->filenames[0], matchbuf, sizeof( matchbuf ));
if( completedname && length )
Q_strncpy( completedname, matchbuf, length );
if( t->numfilenames == 1 ) return true;
@ -529,7 +528,7 @@ qboolean Cmd_GetItemsList( const char *s, char *completedname, int length )
if( Q_stricmp( COM_FileExtension( t->filenames[i] ), "txt" ))
continue;
COM_FileBase( t->filenames[i], matchbuf );
COM_FileBase( t->filenames[i], matchbuf, sizeof( matchbuf ));
Con_Printf( "%16s\n", matchbuf );
numitems++;
}
@ -571,7 +570,7 @@ qboolean Cmd_GetKeysList( const char *s, char *completedname, int length )
const char *keyname = Key_KeynumToString( i );
if(( *s == '*' ) || !Q_strnicmp( keyname, s, len))
Q_strcpy( keys[numkeys++], keyname );
Q_strncpy( keys[numkeys++], keyname, sizeof( keys[0] ));
}
if( !numkeys ) return false;
@ -711,7 +710,7 @@ qboolean Cmd_GetCustomList( const char *s, char *completedname, int length )
t = FS_Search( va( "%s*.hpk", s ), true, false );
if( !t ) return false;
COM_FileBase( t->filenames[0], matchbuf );
COM_FileBase( t->filenames[0], matchbuf, sizeof( matchbuf ));
if( completedname && length )
Q_strncpy( completedname, matchbuf, length );
if( t->numfilenames == 1 ) return true;
@ -721,7 +720,7 @@ qboolean Cmd_GetCustomList( const char *s, char *completedname, int length )
if( Q_stricmp( COM_FileExtension( t->filenames[i] ), "hpk" ))
continue;
COM_FileBase( t->filenames[i], matchbuf );
COM_FileBase( t->filenames[i], matchbuf, sizeof( matchbuf ));
Con_Printf( "%16s\n", matchbuf );
numitems++;
}
@ -765,7 +764,7 @@ qboolean Cmd_GetGamesList( const char *s, char *completedname, int length )
for( i = 0, numgamedirs = 0; i < FI->numgames; i++ )
{
if(( *s == '*' ) || !Q_strnicmp( FI->games[i]->gamefolder, s, len))
Q_strcpy( gamedirs[numgamedirs++], FI->games[i]->gamefolder );
Q_strncpy( gamedirs[numgamedirs++], FI->games[i]->gamefolder, sizeof( gamedirs[0] ));
}
if( !numgamedirs ) return false;
@ -826,7 +825,7 @@ qboolean Cmd_GetCDList( const char *s, char *completedname, int length )
for( i = 0, numcdcommands = 0; i < 8; i++ )
{
if(( *s == '*' ) || !Q_strnicmp( cd_command[i], s, len))
Q_strcpy( cdcommands[numcdcommands++], cd_command[i] );
Q_strncpy( cdcommands[numcdcommands++], cd_command[i], sizeof( cdcommands[0] ));
}
if( !numcdcommands ) return false;
@ -861,6 +860,7 @@ qboolean Cmd_CheckMapsList_R( qboolean fRefresh, qboolean onlyingamedir )
byte buf[MAX_SYSPATH];
string mpfilter;
char *buffer;
size_t buffersize;
string result;
int i, size;
search_t *t;
@ -883,7 +883,8 @@ qboolean Cmd_CheckMapsList_R( qboolean fRefresh, qboolean onlyingamedir )
return false;
}
buffer = Mem_Calloc( host.mempool, t->numfilenames * 2 * sizeof( result ));
buffersize = t->numfilenames * 2 * sizeof( result );
buffer = Mem_Calloc( host.mempool, buffersize );
use_filter = COM_CheckStringEmpty( GI->mp_filter ) ? true : false;
for( i = 0; i < t->numfilenames; i++ )
@ -899,7 +900,7 @@ qboolean Cmd_CheckMapsList_R( qboolean fRefresh, qboolean onlyingamedir )
continue;
f = FS_Open( t->filenames[i], "rb", onlyingamedir );
COM_FileBase( t->filenames[i], mapname );
COM_FileBase( t->filenames[i], mapname, sizeof( mapname ));
if( f )
{
@ -923,8 +924,7 @@ qboolean Cmd_CheckMapsList_R( qboolean fRefresh, qboolean onlyingamedir )
lumplen = entities.filelen;
Q_strncpy( entfilename, t->filenames[i], sizeof( entfilename ));
COM_StripExtension( entfilename );
COM_DefaultExtension( entfilename, ".ent" );
COM_ReplaceExtension( entfilename, ".ent", sizeof( entfilename ));
ents = (char *)FS_LoadFile( entfilename, NULL, true );
if( !ents && lumplen >= 10 )
@ -969,8 +969,8 @@ qboolean Cmd_CheckMapsList_R( qboolean fRefresh, qboolean onlyingamedir )
if( num_spawnpoints )
{
// format: mapname "maptitle"\n
Q_sprintf( result, "%s \"%s\"\n", mapname, message );
Q_strcat( buffer, result ); // add new string
Q_snprintf( result, sizeof( result ), "%s \"%s\"\n", mapname, message );
Q_strncat( buffer, result, buffersize ); // add new string
}
}
}
@ -1029,6 +1029,7 @@ autocomplete_list_t cmd_list[] =
{ "play", 1, Cmd_GetSoundList },
{ "map", 1, Cmd_GetMapList },
{ "cd", 1, Cmd_GetCDList },
{ "mp3", 1, Cmd_GetCDList },
{ NULL }, // termiantor
};
@ -1041,10 +1042,14 @@ compare first argument with string
*/
static qboolean Cmd_CheckName( const char *name )
{
if( !Q_stricmp( Cmd_Argv( 0 ), name ))
const char *p = Cmd_Argv( 0 );
if( !Q_stricmp( p, name ))
return true;
if( !Q_stricmp( Cmd_Argv( 0 ), va( "\\%s", name )))
if( p[0] == '\\' && !Q_stricmp( &p[1], name ))
return true;
return false;
}

View File

@ -34,6 +34,7 @@ Crash handler, called from system
#include <winnt.h>
#include <dbghelp.h>
#include <psapi.h>
#include <time.h>
#ifndef XASH_SDL
typedef ULONG_PTR DWORD_PTR, *PDWORD_PTR;
@ -189,6 +190,64 @@ static void Sys_StackTrace( PEXCEPTION_POINTERS pInfo )
SymCleanup( process );
}
static void Sys_GetProcessName( char *processName, size_t bufferSize )
{
char fullpath[MAX_PATH];
GetModuleBaseName( GetCurrentProcess(), NULL, fullpath, sizeof( fullpath ) - 1 );
COM_FileBase( fullpath, processName, bufferSize );
}
static void Sys_GetMinidumpFileName( const char *processName, char *mdmpFileName, size_t bufferSize )
{
time_t currentUtcTime = time( NULL );
struct tm *currentLocalTime = localtime( &currentUtcTime );
Q_snprintf( mdmpFileName, bufferSize, "%s_%s_crash_%d%.2d%.2d_%.2d%.2d%.2d.mdmp",
processName,
Q_buildcommit(),
currentLocalTime->tm_year + 1900,
currentLocalTime->tm_mon + 1,
currentLocalTime->tm_mday,
currentLocalTime->tm_hour,
currentLocalTime->tm_min,
currentLocalTime->tm_sec);
}
static qboolean Sys_WriteMinidump(PEXCEPTION_POINTERS exceptionInfo, MINIDUMP_TYPE minidumpType)
{
HRESULT errorCode;
string processName;
string mdmpFileName;
MINIDUMP_EXCEPTION_INFORMATION minidumpInfo;
Sys_GetProcessName( processName, sizeof( processName ));
Sys_GetMinidumpFileName( processName, mdmpFileName, sizeof( mdmpFileName ));
SetLastError( NOERROR );
HANDLE fileHandle = CreateFile(
mdmpFileName, GENERIC_WRITE, FILE_SHARE_WRITE,
NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
errorCode = HRESULT_FROM_WIN32( GetLastError( ));
if( !SUCCEEDED( errorCode )) {
CloseHandle( fileHandle );
return false;
}
minidumpInfo.ThreadId = GetCurrentThreadId();
minidumpInfo.ExceptionPointers = exceptionInfo;
minidumpInfo.ClientPointers = FALSE;
qboolean status = MiniDumpWriteDump(
GetCurrentProcess(), GetCurrentProcessId(), fileHandle,
minidumpType, &minidumpInfo, NULL, NULL);
CloseHandle( fileHandle );
return status;
}
#endif /* DBGHELP */
LPTOP_LEVEL_EXCEPTION_FILTER oldFilter;
@ -210,6 +269,26 @@ static long _stdcall Sys_Crash( PEXCEPTION_POINTERS pInfo )
CL_Crashed(); // tell client about crash
else host.status = HOST_CRASHED;
#if DBGHELP
if( Sys_CheckParm( "-minidumps" ))
{
int minidumpFlags = (
MiniDumpWithDataSegs |
MiniDumpWithCodeSegs |
MiniDumpWithHandleData |
MiniDumpWithFullMemory |
MiniDumpWithFullMemoryInfo |
MiniDumpWithIndirectlyReferencedMemory |
MiniDumpWithThreadInfo |
MiniDumpWithModuleHeaders);
if( !Sys_WriteMinidump( pInfo, (MINIDUMP_TYPE)minidumpFlags )) {
// fallback method, create minidump with minimal info in it
Sys_WriteMinidump( pInfo, MiniDumpWithDataSegs );
}
}
#endif
if( host_developer.value <= 0 )
{
// no reason to call debugger in release build - just exit

View File

@ -39,6 +39,10 @@ static cvar_filter_quirks_t cvar_filter_quirks[] =
"ricochet",
"r_drawviewmodel",
},
{
"dod",
"cl_dodmusic" // Day of Defeat Beta 1.3 cvar
},
};
static cvar_filter_quirks_t *cvar_active_filter_quirks = NULL;
@ -95,10 +99,16 @@ Cvar_BuildAutoDescription
build cvar auto description that based on the setup flags
============
*/
const char *Cvar_BuildAutoDescription( int flags )
const char *Cvar_BuildAutoDescription( const char *szName, int flags )
{
static char desc[256];
if( FBitSet( flags, FCVAR_GLCONFIG ))
{
Q_snprintf( desc, sizeof( desc ), CVAR_GLCONFIG_DESCRIPTION, szName );
return desc;
}
desc[0] = '\0';
if( FBitSet( flags, FCVAR_EXTDLL ))
@ -469,6 +479,23 @@ convar_t *Cvar_Get( const char *name, const char *value, int flags, const char *
return var;
}
/*
============
Cvar_Getf
============
*/
convar_t *Cvar_Getf( const char *var_name, int flags, const char *description, const char *format, ... )
{
char value[MAX_VA_STRING];
va_list args;
va_start( args, format );
Q_vsnprintf( value, sizeof( value ), format, args );
va_end( args );
return Cvar_Get( var_name, value, flags, description );
}
/*
============
Cvar_RegisterVariable
@ -1063,7 +1090,7 @@ void Cvar_Toggle_f( void )
v = !Cvar_VariableInteger( Cmd_Argv( 1 ));
Cvar_Set( Cmd_Argv( 1 ), va( "%i", v ));
Cvar_Set( Cmd_Argv( 1 ), v ? "1" : "0" );
}
/*
@ -1092,8 +1119,8 @@ void Cvar_Set_f( void )
len = Q_strlen( Cmd_Argv(i) + 1 );
if( l + len >= MAX_CMD_TOKENS - 2 )
break;
Q_strcat( combined, Cmd_Argv( i ));
if( i != c-1 ) Q_strcat( combined, " " );
Q_strncat( combined, Cmd_Argv( i ), sizeof( combined ));
if( i != c-1 ) Q_strncat( combined, " ", sizeof( combined ));
l += len;
}
@ -1145,7 +1172,6 @@ void Cvar_List_f( void )
{
convar_t *var;
const char *match = NULL;
char *value;
int count = 0;
size_t matchlen = 0;
@ -1157,6 +1183,8 @@ void Cvar_List_f( void )
for( var = cvar_vars; var; var = var->next )
{
char value[MAX_VA_STRING];
if( var->name[0] == '@' )
continue; // never shows system cvars
@ -1164,12 +1192,12 @@ void Cvar_List_f( void )
continue;
if( Q_colorstr( var->string ))
value = va( "\"%s\"", var->string );
else value = va( "\"^2%s^7\"", var->string );
Q_snprintf( value, sizeof( value ), "\"%s\"", var->string );
else Q_snprintf( value, sizeof( value ), "\"^2%s^7\"", var->string );
if( FBitSet( var->flags, FCVAR_EXTENDED|FCVAR_ALLOCATED ))
Con_Printf( " %-*s %s ^3%s^7\n", 32, var->name, value, var->desc );
else Con_Printf( " %-*s %s ^3%s^7\n", 32, var->name, value, Cvar_BuildAutoDescription( var->flags ));
else Con_Printf( " %-*s %s ^3%s^7\n", 32, var->name, value, Cvar_BuildAutoDescription( var->name, var->flags ));
count++;
}

View File

@ -63,12 +63,13 @@ cvar_t *Cvar_GetList( void );
convar_t *Cvar_FindVarExt( const char *var_name, int ignore_group );
void Cvar_RegisterVariable( convar_t *var );
convar_t *Cvar_Get( const char *var_name, const char *value, int flags, const char *description );
convar_t *Cvar_Getf( const char *var_name, int flags, const char *description, const char *format, ... ) _format( 4 );
void Cvar_LookupVars( int checkbit, void *buffer, void *ptr, setpair_t callback );
void Cvar_FullSet( const char *var_name, const char *value, int flags );
void Cvar_DirectSet( convar_t *var, const char *value );
void Cvar_Set( const char *var_name, const char *value );
void Cvar_SetValue( const char *var_name, float value );
const char *Cvar_BuildAutoDescription( int flags );
const char *Cvar_BuildAutoDescription( const char *szName, int flags );
float Cvar_VariableValue( const char *var_name );
int Cvar_VariableInteger( const char *var_name );
const char *Cvar_VariableString( const char *var_name );

View File

@ -70,16 +70,6 @@ qboolean CL_DisableVisibility( void )
return false;
}
qboolean CL_IsBackgroundDemo( void )
{
return false;
}
qboolean CL_IsBackgroundMap( void )
{
return false;
}
void CL_Init( void )
{

View File

@ -1,6 +1,9 @@
/*
filesystem.c - game filesystem based on DP fs
Copyright (C) 2003-2006 Mathieu Olivier
Copyright (C) 2000-2007 DarkPlaces contributors
Copyright (C) 2007 Uncle Mike
Copyright (C) 2015-2023 Xash3D FWGS contributors
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
@ -101,10 +104,7 @@ FS_Init
*/
void FS_Init( void )
{
qboolean hasBaseDir = false;
qboolean hasGameDir = false;
qboolean caseinsensitive = true;
int i;
string gamedir;
Cmd_AddRestrictedCommand( "fs_rescan", FS_Rescan_f, "rescan filesystem search pathes" );

View File

@ -20,7 +20,6 @@ GNU General Public License for more details.
//-----------------------------------------------------------------------------
// Gamma conversion support
//-----------------------------------------------------------------------------
static byte texgammatable[256]; // palette is sent through this to convert to screen gamma
static byte lightgammatable[256];
static int lineargammatable[1024];
static int screengammatable[1024];
@ -60,13 +59,6 @@ void BuildGammaTable( float lightgamma, float brightness )
lightgammatable[i] = bound( 0, inf, 255 );
}
for( i = 0; i < 256; i++ )
{
f = 255.0f * pow(( float )i / 255.0f, TEXGAMMA );
inf = (int)(f + 0.5f);
texgammatable[i] = bound( 0, inf, 255 );
}
for( i = 0; i < 1024; i++ )
{
// convert from screen gamma space to linear space
@ -84,11 +76,3 @@ byte LightToTexGamma( byte b )
else
return lightgammatable[b];
}
byte TextureToGamma( byte b )
{
if( FBitSet( host.features, ENGINE_LINEAR_GAMMA_SPACE ))
return b;
else
return texgammatable[b];
}

View File

@ -114,6 +114,7 @@ void Sys_PrintUsage( void )
#if XASH_WIN32
O("-noavi ","disable AVI support")
O("-nointro ","disable intro video")
O("-minidumps ","enable writing minidumps when game crashed")
#endif // XASH_WIN32
#if XASH_DOS
@ -345,10 +346,10 @@ void Host_ChangeGame_f( void )
}
else
{
const char *arg1 = va( "%s", Cmd_Argv( 1 ));
const char *arg2 = va( "change game to '%s'", FI->games[i]->title );
char finalmsg[MAX_VA_STRING];
Host_NewInstance( arg1, arg2 );
Q_snprintf( finalmsg, sizeof( finalmsg ), "change game to '%s'", FI->games[i]->title );
Host_NewInstance( Cmd_Argv( 1 ), finalmsg );
}
}
@ -383,9 +384,11 @@ void Host_Exec_f( void )
"pyro.cfg", "spy.cfg", "engineer.cfg", "civilian.cfg"
};
int i;
char temp[MAX_VA_STRING];
qboolean allow = false;
unprivilegedWhitelist[0] = va( "%s.cfg", clgame.mapname );
Q_snprintf( temp, sizeof( temp ), "%s.cfg", clgame.mapname );
unprivilegedWhitelist[0] = temp;
for( i = 0; i < ARRAYSIZE( unprivilegedWhitelist ); i++ )
{
@ -412,7 +415,7 @@ void Host_Exec_f( void )
}
Q_strncpy( cfgpath, arg, sizeof( cfgpath ));
COM_DefaultExtension( cfgpath, ".cfg" ); // append as default
COM_DefaultExtension( cfgpath, ".cfg", sizeof( cfgpath )); // append as default
f = FS_LoadFile( cfgpath, &len, false );
if( !f )
@ -506,7 +509,7 @@ qboolean Host_RegisterDecal( const char *name, int *count )
if( !COM_CheckString( name ))
return 0;
COM_FileBase( name, shortname );
COM_FileBase( name, shortname, sizeof( shortname ));
for( i = 1; i < MAX_DECALS && host.draw_decals[i][0]; i++ )
{
@ -730,7 +733,7 @@ void GAME_EXPORT Host_Error( const char *error, ... )
va_list argptr;
va_start( argptr, error );
Q_vsprintf( hosterror1, error, argptr );
Q_vsnprintf( hosterror1, sizeof( hosterror1 ), error, argptr );
va_end( argptr );
CL_WriteMessageHistory (); // before Q_error call
@ -766,7 +769,7 @@ void GAME_EXPORT Host_Error( const char *error, ... )
recursive = true;
Q_strncpy( hosterror2, hosterror1, MAX_SYSPATH );
host.errorframe = host.framecount; // to avoid multply calls per frame
Q_sprintf( host.finalmsg, "Server crashed: %s", hosterror1 );
Q_snprintf( host.finalmsg, sizeof( host.finalmsg ), "Server crashed: %s", hosterror1 );
// clearing cmd buffer to prevent execute any commands
COM_InitHostState();
@ -826,7 +829,7 @@ void Host_Userconfigd_f( void )
for( i = 0; i < t->numfilenames; i++ )
{
Cbuf_AddText( va("exec %s\n", t->filenames[i] ) );
Cbuf_AddTextf( "exec %s\n", t->filenames[i] );
}
Mem_Free( t );
@ -1015,6 +1018,12 @@ void Host_InitCommon( int argc, char **argv, const char *progname, qboolean bCha
#if TARGET_OS_IOS
const char *IOS_GetDocsDir();
Q_strncpy( host.rootdir, IOS_GetDocsDir(), sizeof(host.rootdir) );
#elif XASH_PSVITA
if ( !PSVita_GetBasePath( host.rootdir, sizeof( host.rootdir ) ) )
{
Sys_Error( "couldn't find xash3d data directory" );
host.rootdir[0] = 0;
}
#elif (XASH_SDL == 2) && !XASH_NSWITCH // GetBasePath not impl'd in switch-sdl2
char *szBasePath;
@ -1166,10 +1175,10 @@ int EXPORT Host_Main( int argc, char **argv, const char *progname, int bChangeGa
con_gamemaps = Cvar_Get( "con_mapfilter", "1", FCVAR_ARCHIVE, "when true show only maps in game folder" );
Cvar_RegisterVariable( &sys_timescale );
build = Cvar_Get( "buildnum", va( "%i", Q_buildnum_compat()), FCVAR_READ_ONLY, "returns a current build number" );
ver = Cvar_Get( "ver", va( "%i/%s (hw build %i)", PROTOCOL_VERSION, XASH_COMPAT_VERSION, Q_buildnum_compat()), FCVAR_READ_ONLY, "shows an engine version" );
Cvar_Get( "host_ver", va( "%i " XASH_VERSION " %s %s %s", Q_buildnum(), Q_buildos(), Q_buildarch(), Q_buildcommit() ), FCVAR_READ_ONLY, "detailed info about this build" );
Cvar_Get( "host_lowmemorymode", va( "%i", XASH_LOW_MEMORY ), FCVAR_READ_ONLY, "indicates if engine compiled for low RAM consumption (0 - normal, 1 - low engine limits, 2 - low protocol limits)" );
build = Cvar_Getf( "buildnum", FCVAR_READ_ONLY, "returns a current build number", "%i", Q_buildnum_compat());
ver = Cvar_Getf( "ver", FCVAR_READ_ONLY, "shows an engine version", "%i/%s (hw build %i)", PROTOCOL_VERSION, XASH_COMPAT_VERSION, Q_buildnum_compat());
Cvar_Getf( "host_ver", FCVAR_READ_ONLY, "detailed info about this build", "%i " XASH_VERSION " %s %s %s", Q_buildnum(), Q_buildos(), Q_buildarch(), Q_buildcommit());
Cvar_Getf( "host_lowmemorymode", FCVAR_READ_ONLY, "indicates if engine compiled for low RAM consumption (0 - normal, 1 - low engine limits, 2 - low protocol limits)", "%i", XASH_LOW_MEMORY );
Mod_Init();
NET_Init();
@ -1204,6 +1213,8 @@ int EXPORT Host_Main( int argc, char **argv, const char *progname, int bChangeGa
}
else Cmd_AddRestrictedCommand( "minimize", Host_Minimize_f, "minimize main window to tray" );
HPAK_CheckIntegrity( CUSTOM_RES_PATH );
host.errorframe = 0;
// post initializations
@ -1214,7 +1225,7 @@ int EXPORT Host_Main( int argc, char **argv, const char *progname, int bChangeGa
Wcon_ShowConsole( false ); // hide console
#endif
// execute startup config and cmdline
Cbuf_AddText( va( "exec %s.rc\n", SI.rcName ));
Cbuf_AddTextf( "exec %s.rc\n", SI.rcName );
Cbuf_Execute();
if( !host.config_executed )
{
@ -1248,7 +1259,7 @@ int EXPORT Host_Main( int argc, char **argv, const char *progname, int bChangeGa
// execute server.cfg after commandline
// so we have a chance to set servercfgfile
Cbuf_AddText( va( "exec %s\n", Cvar_VariableString( "servercfgfile" )));
Cbuf_AddTextf( "exec %s\n", Cvar_VariableString( "servercfgfile" ));
Cbuf_Execute();
}

View File

@ -29,10 +29,10 @@ typedef struct hash_pack_queue_s
struct hash_pack_queue_s *next;
} hash_pack_queue_t;
convar_t *hpk_maxsize;
hash_pack_queue_t *gp_hpak_queue = NULL;
hpak_header_t hash_pack_header;
hpak_info_t hash_pack_info;
static CVAR_DEFINE_AUTO( hpk_maxsize, "4", FCVAR_ARCHIVE, "set limit by size for all HPK-files ( 0 - unlimited )" );
static hash_pack_queue_t *gp_hpak_queue = NULL;
static hpak_header_t hash_pack_header;
static hpak_info_t hash_pack_info;
const char *HPAK_TypeFromIndex( int type )
{
@ -101,7 +101,6 @@ void HPAK_CreatePak( const char *filename, resource_t *pResource, byte *pData, f
byte md5[16];
file_t *fout;
MD5Context_t ctx;
dresource_t dresource;
if( !COM_CheckString( filename ))
return;
@ -110,7 +109,7 @@ void HPAK_CreatePak( const char *filename, resource_t *pResource, byte *pData, f
return;
Q_strncpy( pakname, filename, sizeof( pakname ));
COM_ReplaceExtension( pakname, ".hpk" );
COM_ReplaceExtension( pakname, ".hpk", sizeof( pakname ));
Con_Printf( "creating HPAK %s.\n", pakname );
@ -258,7 +257,7 @@ void HPAK_AddLump( qboolean bUseQueue, const char *name, resource_t *pResource,
}
Q_strncpy( srcname, name, sizeof( srcname ));
COM_ReplaceExtension( srcname, ".hpk" );
COM_ReplaceExtension( srcname, ".hpk", sizeof( srcname ));
file_src = FS_Open( srcname, "rb", true );
@ -270,7 +269,7 @@ void HPAK_AddLump( qboolean bUseQueue, const char *name, resource_t *pResource,
}
Q_strncpy( dstname, srcname, sizeof( dstname ));
COM_ReplaceExtension( dstname, ".hp2" );
COM_ReplaceExtension( dstname, ".hp2", sizeof( dstname ));
file_dst = FS_Open( dstname, "wb", true );
@ -377,7 +376,7 @@ void HPAK_AddLump( qboolean bUseQueue, const char *name, resource_t *pResource,
FS_Rename( dstname, srcname );
}
static qboolean HPAK_Validate( const char *filename, qboolean quiet )
static qboolean HPAK_Validate( const char *filename, qboolean quiet, qboolean delete )
{
file_t *f;
hpak_lump_t *dataDir;
@ -396,7 +395,7 @@ static qboolean HPAK_Validate( const char *filename, qboolean quiet )
return true;
Q_strncpy( pakname, filename, sizeof( pakname ));
COM_ReplaceExtension( pakname, ".hpk" );
COM_ReplaceExtension( pakname, ".hpk", sizeof( pakname ));
f = FS_Open( pakname, "rb", true );
if( !f )
@ -412,6 +411,7 @@ static qboolean HPAK_Validate( const char *filename, qboolean quiet )
{
Con_DPrintf( S_ERROR "HPAK_ValidatePak: %s does not have a valid HPAK header.\n", pakname );
FS_Close( f );
if( delete ) FS_Delete( pakname );
return false;
}
@ -422,6 +422,7 @@ static qboolean HPAK_Validate( const char *filename, qboolean quiet )
{
Con_DPrintf( S_ERROR "HPAK_ValidatePak: %s has too many lumps %u.\n", pakname, num_lumps );
FS_Close( f );
if( delete ) FS_Delete( pakname );
return false;
}
@ -439,7 +440,8 @@ static qboolean HPAK_Validate( const char *filename, qboolean quiet )
// odd max size
Con_DPrintf( S_ERROR "HPAK_ValidatePak: lump %i has invalid size %s\n", i, Q_pretifymem( dataDir[i].disksize, 2 ));
Mem_Free( dataDir );
FS_Close(f);
FS_Close( f );
if( delete ) FS_Delete( pakname );
return false;
}
@ -454,8 +456,11 @@ static qboolean HPAK_Validate( const char *filename, qboolean quiet )
pRes = &dataDir[i].resource;
Con_Printf( "%i: %s %s %s: ", i, HPAK_TypeFromIndex( pRes->type ),
Q_pretifymem( pRes->nDownloadSize, 2 ), pRes->szFileName );
if( !quiet )
{
Con_Printf( "%i: %s %s %s: ", i, HPAK_TypeFromIndex( pRes->type ),
Q_pretifymem( pRes->nDownloadSize, 2 ), pRes->szFileName );
}
if( memcmp( md5, pRes->rgucMD5_hash, 0x10 ))
{
@ -465,6 +470,7 @@ static qboolean HPAK_Validate( const char *filename, qboolean quiet )
Mem_Free( dataPak );
Mem_Free( dataDir );
FS_Close( f );
if( delete ) FS_Delete( pakname );
return false;
}
else Con_DPrintf( S_ERROR "failed\n" );
@ -483,11 +489,6 @@ static qboolean HPAK_Validate( const char *filename, qboolean quiet )
return true;
}
void HPAK_ValidatePak( const char *filename )
{
HPAK_Validate( filename, true );
}
void HPAK_CheckIntegrity( const char *filename )
{
string pakname;
@ -496,9 +497,9 @@ void HPAK_CheckIntegrity( const char *filename )
return;
Q_strncpy( pakname, filename, sizeof( pakname ));
COM_ReplaceExtension( pakname, ".hpk" );
COM_ReplaceExtension( pakname, ".hpk", sizeof( pakname ));
HPAK_ValidatePak( pakname );
HPAK_Validate( pakname, true, true );
}
void HPAK_CheckSize( const char *filename )
@ -506,19 +507,19 @@ void HPAK_CheckSize( const char *filename )
string pakname;
int maxsize;
maxsize = hpk_maxsize->value;
maxsize = hpk_maxsize.value;
if( maxsize <= 0 ) return;
if( !COM_CheckString( filename ) )
return;
Q_strncpy( pakname, filename, sizeof( pakname ));
COM_ReplaceExtension( pakname, ".hpk" );
COM_ReplaceExtension( pakname, ".hpk", sizeof( pakname ));
if( FS_FileSize( pakname, false ) > ( maxsize * 1048576 ))
{
Con_Printf( "Server: Size of %s > %f MB, deleting.\n", filename, hpk_maxsize->value );
Log_Printf( "Server: Size of %s > %f MB, deleting.\n", filename, hpk_maxsize->value );
Con_Printf( "Server: Size of %s > %f MB, deleting.\n", filename, hpk_maxsize.value );
Log_Printf( "Server: Size of %s > %f MB, deleting.\n", filename, hpk_maxsize.value );
FS_Delete( filename );
}
}
@ -546,7 +547,7 @@ qboolean HPAK_ResourceForHash( const char *filename, byte *hash, resource_t *pRe
}
Q_strncpy( pakname, filename, sizeof( pakname ));
COM_ReplaceExtension( pakname, ".hpk" );
COM_ReplaceExtension( pakname, ".hpk", sizeof( pakname ));
f = FS_Open( pakname, "rb", true );
if( !f ) return false;
@ -594,7 +595,7 @@ static qboolean HPAK_ResourceForIndex( const char *filename, int index, resource
return false;
Q_strncpy( pakname, filename, sizeof( pakname ));
COM_ReplaceExtension( pakname, ".hpk" );
COM_ReplaceExtension( pakname, ".hpk", sizeof( pakname ));
f = FS_Open( pakname, "rb", true );
if( !f )
@ -680,7 +681,7 @@ qboolean HPAK_GetDataPointer( const char *filename, resource_t *pResource, byte
}
Q_strncpy( pakname, filename, sizeof( pakname ));
COM_ReplaceExtension( pakname, ".hpk" );
COM_ReplaceExtension( pakname, ".hpk", sizeof( pakname ));
f = FS_Open( pakname, "rb", true );
if( !f ) return false;
@ -763,7 +764,7 @@ void HPAK_RemoveLump( const char *name, resource_t *pResource )
HPAK_FlushHostQueue();
Q_strncpy( read_path, name, sizeof( read_path ));
COM_ReplaceExtension( read_path, ".hpk" );
COM_ReplaceExtension( read_path, ".hpk", sizeof( read_path ));
file_src = FS_Open( read_path, "rb", true );
if( !file_src )
@ -773,7 +774,7 @@ void HPAK_RemoveLump( const char *name, resource_t *pResource )
}
Q_strncpy( save_path, read_path, sizeof( save_path ));
COM_ReplaceExtension( save_path, ".hp2" );
COM_ReplaceExtension( save_path, ".hp2", sizeof( save_path ));
file_dst = FS_Open( save_path, "wb", true );
if( !file_dst )
@ -892,7 +893,7 @@ void HPAK_List_f( void )
HPAK_FlushHostQueue();
Q_strncpy( pakname, Cmd_Argv( 1 ), sizeof( pakname ));
COM_ReplaceExtension( pakname, ".hpk" );
COM_ReplaceExtension( pakname, ".hpk", sizeof( pakname ));
Con_Printf( "Contents for %s.\n", pakname );
f = FS_Open( pakname, "rb", true );
@ -937,7 +938,7 @@ void HPAK_List_f( void )
for( nCurrent = 0; nCurrent < directory.count; nCurrent++ )
{
entry = &directory.entries[nCurrent];
COM_FileBase( entry->resource.szFileName, lumpname );
COM_FileBase( entry->resource.szFileName, lumpname, sizeof( lumpname ));
type = HPAK_TypeFromIndex( entry->resource.type );
size = Q_memprint( entry->resource.nDownloadSize );
@ -983,7 +984,7 @@ void HPAK_Extract_f( void )
HPAK_FlushHostQueue();
Q_strncpy( pakname, Cmd_Argv( 1 ), sizeof( pakname ));
COM_ReplaceExtension( pakname, ".hpk" );
COM_ReplaceExtension( pakname, ".hpk", sizeof( pakname ));
Con_Printf( "Contents for %s.\n", pakname );
f = FS_Open( pakname, "rb", true );
@ -1032,7 +1033,7 @@ void HPAK_Extract_f( void )
if( nIndex != -1 && nIndex != nCurrent )
continue;
COM_FileBase( entry->resource.szFileName, lumpname );
COM_FileBase( entry->resource.szFileName, lumpname, sizeof( lumpname ) );
type = HPAK_TypeFromIndex( entry->resource.type );
size = Q_memprint( entry->resource.nDownloadSize );
@ -1090,7 +1091,7 @@ void HPAK_Validate_f( void )
return;
}
HPAK_Validate( Cmd_Argv( 1 ), false );
HPAK_Validate( Cmd_Argv( 1 ), false, false );
}
void HPAK_Init( void )
@ -1099,7 +1100,7 @@ void HPAK_Init( void )
Cmd_AddRestrictedCommand( "hpkremove", HPAK_Remove_f, "remove specified file from HPK-file" );
Cmd_AddRestrictedCommand( "hpkval", HPAK_Validate_f, "validate specified HPK-file" );
Cmd_AddRestrictedCommand( "hpkextract", HPAK_Extract_f, "extract all lumps from specified HPK-file" );
hpk_maxsize = Cvar_Get( "hpk_maxsize", "0", FCVAR_ARCHIVE, "set limit by size for all HPK-files ( 0 - unlimited )" );
Cvar_RegisterVariable( &hpk_maxsize );
gp_hpak_queue = NULL;
}

View File

@ -35,7 +35,7 @@ static bloomfilter_t id;
#define bf64_mask ((1U<<6)-1)
bloomfilter_t BloomFilter_Process( const char *buffer, int size )
static bloomfilter_t BloomFilter_Process( const char *buffer, int size )
{
dword crc32;
bloomfilter_t value = 0;
@ -55,12 +55,12 @@ bloomfilter_t BloomFilter_Process( const char *buffer, int size )
return value;
}
bloomfilter_t BloomFilter_ProcessStr( const char *buffer )
static bloomfilter_t BloomFilter_ProcessStr( const char *buffer )
{
return BloomFilter_Process( buffer, Q_strlen( buffer ) );
}
uint BloomFilter_Weight( bloomfilter_t value )
static uint BloomFilter_Weight( bloomfilter_t value )
{
int weight = 0;
@ -77,7 +77,7 @@ uint BloomFilter_Weight( bloomfilter_t value )
return weight;
}
qboolean BloomFilter_ContainsString( bloomfilter_t filter, const char *str )
static qboolean BloomFilter_ContainsString( bloomfilter_t filter, const char *str )
{
bloomfilter_t value = BloomFilter_ProcessStr( str );
@ -94,9 +94,9 @@ IDENTIFICATION
#define MAXBITS_GEN 30
#define MAXBITS_CHECK MAXBITS_GEN + 6
qboolean ID_ProcessFile( bloomfilter_t *value, const char *path );
static qboolean ID_ProcessFile( bloomfilter_t *value, const char *path );
void ID_BloomFilter_f( void )
static void ID_BloomFilter_f( void )
{
bloomfilter_t value = 0;
int i;
@ -111,7 +111,7 @@ void ID_BloomFilter_f( void )
// Msg( "%s: %d\n", Cmd_Argv( i ), BloomFilter_ContainsString( value, Cmd_Argv( i ) ) );
}
qboolean ID_VerifyHEX( const char *hex )
static qboolean ID_VerifyHEX( const char *hex )
{
uint chars = 0;
char prev = 0;
@ -153,7 +153,7 @@ qboolean ID_VerifyHEX( const char *hex )
return false;
}
void ID_VerifyHEX_f( void )
static void ID_VerifyHEX_f( void )
{
if( ID_VerifyHEX( Cmd_Argv( 1 ) ) )
Msg( "Good\n" );
@ -162,7 +162,7 @@ void ID_VerifyHEX_f( void )
}
#if XASH_LINUX
qboolean ID_ProcessCPUInfo( bloomfilter_t *value )
static qboolean ID_ProcessCPUInfo( bloomfilter_t *value )
{
int cpuinfofd = open( "/proc/cpuinfo", O_RDONLY );
char buffer[1024], *pbuf, *pbuf2;
@ -198,7 +198,7 @@ qboolean ID_ProcessCPUInfo( bloomfilter_t *value )
return true;
}
qboolean ID_ValidateNetDevice( const char *dev )
static qboolean ID_ValidateNetDevice( const char *dev )
{
const char *prefix = "/sys/class/net";
byte *pfile;
@ -226,7 +226,7 @@ qboolean ID_ValidateNetDevice( const char *dev )
return true;
}
int ID_ProcessNetDevices( bloomfilter_t *value )
static int ID_ProcessNetDevices( bloomfilter_t *value )
{
const char *prefix = "/sys/class/net";
DIR *dir;
@ -250,7 +250,7 @@ int ID_ProcessNetDevices( bloomfilter_t *value )
return count;
}
int ID_CheckNetDevices( bloomfilter_t value )
static int ID_CheckNetDevices( bloomfilter_t value )
{
const char *prefix = "/sys/class/net";
@ -278,7 +278,7 @@ int ID_CheckNetDevices( bloomfilter_t value )
return count;
}
void ID_TestCPUInfo_f( void )
static void ID_TestCPUInfo_f( void )
{
bloomfilter_t value = 0;
@ -290,7 +290,7 @@ void ID_TestCPUInfo_f( void )
#endif
qboolean ID_ProcessFile( bloomfilter_t *value, const char *path )
static qboolean ID_ProcessFile( bloomfilter_t *value, const char *path )
{
int fd = open( path, O_RDONLY );
char buffer[256];
@ -317,7 +317,7 @@ qboolean ID_ProcessFile( bloomfilter_t *value, const char *path )
}
#if !XASH_WIN32
int ID_ProcessFiles( bloomfilter_t *value, const char *prefix, const char *postfix )
static int ID_ProcessFiles( bloomfilter_t *value, const char *prefix, const char *postfix )
{
DIR *dir;
struct dirent *entry;
@ -337,7 +337,7 @@ int ID_ProcessFiles( bloomfilter_t *value, const char *prefix, const char *postf
return count;
}
int ID_CheckFiles( bloomfilter_t value, const char *prefix, const char *postfix )
static int ID_CheckFiles( bloomfilter_t value, const char *prefix, const char *postfix )
{
DIR *dir;
struct dirent *entry;
@ -360,7 +360,7 @@ int ID_CheckFiles( bloomfilter_t value, const char *prefix, const char *postfix
return count;
}
#else
int ID_GetKeyData( HKEY hRootKey, char *subKey, char *value, LPBYTE data, DWORD cbData )
static int ID_GetKeyData( HKEY hRootKey, char *subKey, char *value, LPBYTE data, DWORD cbData )
{
HKEY hKey;
@ -376,7 +376,7 @@ int ID_GetKeyData( HKEY hRootKey, char *subKey, char *value, LPBYTE data, DWORD
RegCloseKey( hKey );
return 1;
}
int ID_SetKeyData( HKEY hRootKey, char *subKey, DWORD dwType, char *value, LPBYTE data, DWORD cbData)
static int ID_SetKeyData( HKEY hRootKey, char *subKey, DWORD dwType, char *value, LPBYTE data, DWORD cbData)
{
HKEY hKey;
if( RegCreateKey( hRootKey, subKey, &hKey ) != ERROR_SUCCESS )
@ -394,7 +394,7 @@ int ID_SetKeyData( HKEY hRootKey, char *subKey, DWORD dwType, char *value, LPBYT
#define BUFSIZE 4096
int ID_RunWMIC(char *buffer, const char *cmdline)
static int ID_RunWMIC(char *buffer, const char *cmdline)
{
HANDLE g_IN_Rd = NULL;
HANDLE g_IN_Wr = NULL;
@ -438,7 +438,7 @@ int ID_RunWMIC(char *buffer, const char *cmdline)
return bSuccess;
}
int ID_ProcessWMIC( bloomfilter_t *value, const char *cmdline )
static int ID_ProcessWMIC( bloomfilter_t *value, const char *cmdline )
{
char buffer[BUFSIZE], token[BUFSIZE], *pbuf;
int count = 0;
@ -458,7 +458,7 @@ int ID_ProcessWMIC( bloomfilter_t *value, const char *cmdline )
return count;
}
int ID_CheckWMIC( bloomfilter_t value, const char *cmdline )
static int ID_CheckWMIC( bloomfilter_t value, const char *cmdline )
{
char buffer[BUFSIZE], token[BUFSIZE], *pbuf;
int count = 0;
@ -486,7 +486,7 @@ int ID_CheckWMIC( bloomfilter_t value, const char *cmdline )
char *IOS_GetUDID( void );
#endif
bloomfilter_t ID_GenerateRawId( void )
static bloomfilter_t ID_GenerateRawId( void )
{
bloomfilter_t value = 0;
int count = 0;
@ -519,7 +519,7 @@ bloomfilter_t ID_GenerateRawId( void )
return value;
}
uint ID_CheckRawId( bloomfilter_t filter )
static uint ID_CheckRawId( bloomfilter_t filter )
{
bloomfilter_t value = 0;
int count = 0;
@ -563,7 +563,7 @@ uint ID_CheckRawId( bloomfilter_t filter )
#define SYSTEM_XOR_MASK 0x10331c2dce4c91db
#define GAME_XOR_MASK 0x7ffc48fbac1711f1
void ID_Check( void )
static void ID_Check( void )
{
uint weight = BloomFilter_Weight( id );
uint mincount = weight >> 2;
@ -677,7 +677,7 @@ void ID_Init( void )
MD5Final( (byte*)md5, &hash );
for( i = 0; i < 16; i++ )
Q_sprintf( &id_md5[i*2], "%02hhx", md5[i] );
Q_snprintf( &id_md5[i*2], sizeof( id_md5 ) - i * 2, "%02hhx", md5[i] );
#if XASH_ANDROID && !XASH_DEDICATED
Android_SaveID( va("%016llX", id^SYSTEM_XOR_MASK ) );

View File

@ -321,10 +321,9 @@ rgbdata_t *FS_LoadImage( const char *filename, const byte *buffer, size_t size )
{
for( i = 0; i < 6; i++ )
{
if( Image_ProbeLoad( extfmt, loadname, cmap->type[i].suf, cmap->type[i].hint ) &&
FS_AddSideToPack( cmap->type[i].flags )) // process flags to flip some sides
if( Image_ProbeLoad( extfmt, loadname, cmap->type[i].suf, cmap->type[i].hint ))
{
break;
FS_AddSideToPack( cmap->type[i].flags );
}
if( image.num_sides != i + 1 ) // check side
@ -339,7 +338,7 @@ rgbdata_t *FS_LoadImage( const char *filename, const byte *buffer, size_t size )
}
}
// make sure what all sides is loaded
// make sure that all sides is loaded
if( image.num_sides != 6 )
{
// unexpected errors ?
@ -423,7 +422,8 @@ qboolean FS_SaveImage( const char *filename, rgbdata_t *pix )
{
for( i = 0; i < 6; i++ )
{
Q_sprintf( path, format->formatstring, savename, box[i].suf, format->ext );
Q_snprintf( path, sizeof( path ),
format->formatstring, savename, box[i].suf, format->ext );
if( !format->savefunc( path, pix )) break; // there were errors
pix->buffer += pix->size; // move pointer
}
@ -445,7 +445,8 @@ qboolean FS_SaveImage( const char *filename, rgbdata_t *pix )
{
if( !Q_stricmp( ext, format->ext ))
{
Q_sprintf( path, format->formatstring, savename, "", format->ext );
Q_snprintf( path, sizeof( path ),
format->formatstring, savename, "", format->ext );
if( format->savefunc( path, pix ))
{
// clear any force flags
@ -577,10 +578,13 @@ void Test_RunImagelib( void )
for( i = 0; i < sizeof(extensions) / sizeof(extensions[0]); i++ )
{
const char *name = va( "test_gen.%s", extensions[i] );
qboolean ret;
char name[MAX_VA_STRING];
Q_snprintf( name, sizeof( name ), "test_gen.%s", extensions[i] );
// test saving
qboolean ret = FS_SaveImage( name, &rgb );
ret = FS_SaveImage( name, &rgb );
Con_Printf( "Checking if we can save images in '%s' format...\n", extensions[i] );
ASSERT(ret == true);

View File

@ -277,7 +277,9 @@ qboolean GAME_EXPORT Info_RemoveKey( char *s, const char *key )
if( !Q_strncmp( key, pkey, cmpsize ))
{
Q_strcpy( start, s ); // remove this part
size_t size = Q_strlen( s ) + 1;
memmove( start, s, size ); // remove this part
return true;
}
@ -496,3 +498,16 @@ qboolean Info_SetValueForKey( char *s, const char *key, const char *value, int m
return Info_SetValueForStarKey( s, key, value, maxsize );
}
qboolean Info_SetValueForKeyf( char *s, const char *key, int maxsize, const char *format, ... )
{
char value[MAX_VA_STRING];
va_list args;
va_start( args, format );
Q_vsnprintf( value, sizeof( value ), format, args );
va_end( args );
return Info_SetValueForKey( s, key, value, maxsize );
}

View File

@ -91,9 +91,13 @@ _inline int Sys_Start( void )
#if !XASH_WIN32
int main( int argc, char **argv )
{
#if XASH_PSVITA
// inject -dev -console into args if required
szArgc = PSVita_GetArgv( argc, argv, &szArgv );
#else
szArgc = argc;
szArgv = argv;
#endif // XASH_PSVITA
return Sys_Start();
}
#else

View File

@ -14,22 +14,49 @@ GNU General Public License for more details.
*/
#include "common.h"
#include "netchan.h"
#include "server.h"
typedef struct master_s
{
struct master_s *next;
qboolean sent;
qboolean sent; // TODO: get rid of this internal state
qboolean save;
string address;
netadr_t adr; // temporary, rewritten after each send
uint heartbeat_challenge;
double last_heartbeat;
} master_t;
struct masterlist_s
static struct masterlist_s
{
master_t *list;
qboolean modified;
} ml;
static CVAR_DEFINE_AUTO( sv_verbose_heartbeats, "0", 0, "print every heartbeat to console" );
#define HEARTBEAT_SECONDS ((sv_nat.value > 0.0f) ? 60.0f : 300.0f) // 1 or 5 minutes
/*
========================
NET_GetMasterHostByName
========================
*/
static net_gai_state_t NET_GetMasterHostByName( master_t *m )
{
net_gai_state_t res = NET_StringToAdrNB( m->address, &m->adr );
if( res == NET_EAI_OK )
return res;
m->adr.type = NA_UNUSED;
if( res == NET_EAI_NONAME )
Con_Reportf( "Can't resolve adr: %s\n", m->address );
return res;
}
/*
========================
NET_SendToMasters
@ -45,48 +72,167 @@ qboolean NET_SendToMasters( netsrc_t sock, size_t len, const void *data )
for( list = ml.list; list; list = list->next )
{
int res;
if( list->sent )
continue;
res = NET_StringToAdrNB( list->address, &list->adr );
if( !res )
{
Con_Reportf( "Can't resolve adr: %s\n", list->address );
list->sent = true;
list->adr.type = NA_UNUSED;
continue;
}
if( res == 2 )
switch( NET_GetMasterHostByName( list ))
{
case NET_EAI_AGAIN:
list->sent = false;
list->adr.type = NA_UNUSED;
wait = true;
continue;
break;
case NET_EAI_NONAME:
list->sent = true;
break;
case NET_EAI_OK:
list->sent = true;
NET_SendPacket( sock, len, data, list->adr );
break;
}
list->sent = true;
NET_SendPacket( sock, len, data, list->adr );
}
if( !wait )
{
list = ml.list;
while( list )
{
// reset sent state
for( list = ml.list; list; list = list->next )
list->sent = false;
list = list->next;
}
}
return wait;
}
/*
========================
NET_AnnounceToMaster
========================
*/
static void NET_AnnounceToMaster( master_t *m )
{
sizebuf_t msg;
char buf[16];
m->heartbeat_challenge = COM_RandomLong( 0, INT_MAX );
MSG_Init( &msg, "Master Join", buf, sizeof( buf ));
MSG_WriteBytes( &msg, "q\xFF", 2 );
MSG_WriteDword( &msg, m->heartbeat_challenge );
NET_SendPacket( NS_SERVER, MSG_GetNumBytesWritten( &msg ), MSG_GetBuf( &msg ), m->adr );
if( sv_verbose_heartbeats.value )
{
Con_Printf( S_NOTE "sent heartbeat to %s (%s, 0x%x)\n",
m->address, NET_AdrToString( m->adr ), m->heartbeat_challenge );
}
}
/*
========================
NET_AnnounceToMaster
========================
*/
void NET_MasterClear( void )
{
master_t *m;
for( m = ml.list; m; m = m->next )
m->last_heartbeat = MAX_HEARTBEAT;
}
/*
========================
NET_MasterHeartbeat
========================
*/
void NET_MasterHeartbeat( void )
{
master_t *m;
if(( !public_server.value && !sv_nat.value ) || svs.maxclients == 1 )
return; // only public servers send heartbeats
for( m = ml.list; m; m = m->next )
{
if( host.realtime - m->last_heartbeat < HEARTBEAT_SECONDS )
continue;
switch( NET_GetMasterHostByName( m ))
{
case NET_EAI_AGAIN:
m->last_heartbeat = MAX_HEARTBEAT; // retry on next frame
if( sv_verbose_heartbeats.value )
Con_Printf( S_NOTE "delay heartbeat to next frame until %s resolves\n", m->address );
break;
case NET_EAI_NONAME:
m->last_heartbeat = host.realtime; // try to resolve again on next heartbeat
break;
case NET_EAI_OK:
m->last_heartbeat = host.realtime;
NET_AnnounceToMaster( m );
break;
}
}
}
/*
=================
NET_MasterShutdown
Informs all masters that this server is going down
(ignored by master servers in current implementation)
=================
*/
void NET_MasterShutdown( void )
{
NET_Config( true, false ); // allow remote
while( NET_SendToMasters( NS_SERVER, 2, "\x62\x0A" ));
}
/*
========================
NET_GetMasterFromAdr
========================
*/
static master_t *NET_GetMasterFromAdr( netadr_t adr )
{
master_t *master;
for( master = ml.list; master; master = master->next )
{
if( NET_CompareAdr( adr, master->adr ))
return master;
}
return NULL;
}
/*
========================
NET_GetMaster
========================
*/
qboolean NET_GetMaster( netadr_t from, uint *challenge, double *last_heartbeat )
{
master_t *m;
m = NET_GetMasterFromAdr( from );
if( m )
{
*challenge = m->heartbeat_challenge;
*last_heartbeat = m->last_heartbeat;
}
return m != NULL;
}
/*
========================
NET_IsMasterAdr
@ -95,15 +241,7 @@ NET_IsMasterAdr
*/
qboolean NET_IsMasterAdr( netadr_t adr )
{
master_t *master;
for( master = ml.list; master; master = master->next )
{
if( NET_CompareAdr( adr, master->adr ))
return true;
}
return false;
return NET_GetMasterFromAdr( adr ) != NULL;
}
/*
@ -277,6 +415,8 @@ void NET_InitMasters( void )
Cmd_AddRestrictedCommand( "clearmasters", NET_ClearMasters_f, "clear masterserver list" );
Cmd_AddCommand( "listmasters", NET_ListMasters_f, "list masterservers" );
Cvar_RegisterVariable( &sv_verbose_heartbeats );
// keep main master always there
NET_AddMaster( MASTERSERVER_ADR, false );
NET_LoadMasters( );

View File

@ -24,6 +24,9 @@ GNU General Public License for more details.
#include "client.h"
#include "server.h" // LUMP_ error codes
#include "ref_common.h"
#define MIPTEX_CUSTOM_PALETTE_SIZE_BYTES ( sizeof( int16_t ) + 768 )
typedef struct wadlist_s
{
char wadnames[MAX_MAP_WADS][32];
@ -207,6 +210,134 @@ static mlumpinfo_t extlumps[EXTRA_LUMPS] =
{ LUMP_SHADOWMAP, 0, MAX_MAP_LIGHTING / 3, sizeof( byte ), -1, "shadowmap", USE_EXTRAHEADER, (const void **)&srcmodel.shadowdata, &srcmodel.shadowdatasize },
};
/*
===============================================================================
Static helper functions
===============================================================================
*/
static mip_t *Mod_GetMipTexForTexture( dbspmodel_t *bmod, int i )
{
if( i < 0 || i >= bmod->textures->nummiptex )
return NULL;
if( bmod->textures->dataofs[i] == -1 )
return NULL;
return (mip_t *)((byte *)bmod->textures + bmod->textures->dataofs[i] );
}
// Returns index of WAD that texture was found in, or -1 if not found.
static int Mod_FindTextureInWadList( wadlist_t *list, const char *name, char *dst, size_t size )
{
int i;
if( !list || !COM_CheckString( name ))
return -1;
// check wads in reverse order
for( i = list->count - 1; i >= 0; i-- )
{
char path[MAX_VA_STRING];
Q_snprintf( path, sizeof( path ), "%s.wad/%s.mip", list->wadnames[i], name );
if( FS_FileExists( path, false ))
{
if( dst && size > 0 )
Q_strncpy( dst, path, size );
return i;
}
}
return -1;
}
static fs_offset_t Mod_CalculateMipTexSize( mip_t *mt, qboolean palette )
{
if( !mt )
return 0;
return sizeof( *mt ) + (( mt->width * mt->height * 85 ) >> 6 ) +
( palette ? MIPTEX_CUSTOM_PALETTE_SIZE_BYTES : 0 );
}
static qboolean Mod_CalcMipTexUsesCustomPalette( dbspmodel_t *bmod, int textureIndex )
{
int nextTextureIndex = 0;
mip_t *mipTex;
fs_offset_t size, remainingBytes;
mipTex = Mod_GetMipTexForTexture( bmod, textureIndex );
if( !mipTex || mipTex->offsets[0] <= 0 )
return false;
// Calculate the size assuming we are not using a custom palette.
size = Mod_CalculateMipTexSize( mipTex, false );
// Compute next data offset to determine allocated miptex space
for( nextTextureIndex = textureIndex + 1; nextTextureIndex < loadmodel->numtextures; nextTextureIndex++ )
{
int nextOffset = bmod->textures->dataofs[nextTextureIndex];
if( nextOffset != -1 )
{
remainingBytes = nextOffset - ( bmod->textures->dataofs[textureIndex] + size );
return remainingBytes >= MIPTEX_CUSTOM_PALETTE_SIZE_BYTES;
}
}
// There was no other miptex after this one.
// See if there is enough space between the end and our offset.
remainingBytes = bmod->texdatasize - ( bmod->textures->dataofs[textureIndex] + size );
return remainingBytes >= MIPTEX_CUSTOM_PALETTE_SIZE_BYTES;
}
static qboolean Mod_NameImpliesTextureIsAnimated( texture_t *tex )
{
if( !tex )
return false;
// Not an animated texture name
if( tex->name[0] != '-' && tex->name[0] != '+' )
return false;
// Name implies texture is animated - check second character is valid.
if( !( tex->name[1] >= '0' && tex->name[1] <= '9' ) &&
!( tex->name[1] >= 'a' && tex->name[1] <= 'j' ))
{
Con_Printf( S_ERROR "Mod_NameImpliesTextureIsAnimated: animating texture \"%s\" has invalid name\n", tex->name );
return false;
}
return true;
}
static void Mod_CreateDefaultTexture( texture_t **texture )
{
texture_t *tex;
// Pointer must be valid, and value pointed to must be null.
if( !texture || *texture != NULL )
return;
*texture = tex = Mem_Calloc( loadmodel->mempool, sizeof( *tex ));
Q_strncpy( tex->name, REF_DEFAULT_TEXTURE, sizeof( tex->name ));
#if !XASH_DEDICATED
if( !Host_IsDedicated( ))
{
tex->gl_texturenum = R_GetBuiltinTexture( REF_DEFAULT_TEXTURE );
tex->width = 16;
tex->height = 16;
}
#endif // XASH_DEDICATED
}
/*
===============================================================================
@ -309,7 +440,7 @@ static void Mod_LoadLump( const byte *in, mlumpinfo_t *info, mlumpstat_t *stat,
if( l->filelen % real_entrysize )
{
if( !FBitSet( flags, LUMP_SILENT ))
Con_DPrintf( S_ERROR "Mod_Load%s: Lump size %d was not a multiple of %lu bytes\n", msg2, l->filelen, real_entrysize );
Con_DPrintf( S_ERROR "Mod_Load%s: Lump size %d was not a multiple of %zu bytes\n", msg2, l->filelen, real_entrysize );
loadstat.numerrors++;
return;
}
@ -745,24 +876,6 @@ qboolean Mod_HeadnodeVisible( mnode_t *node, const byte *visbits, int *lastleaf
return false;
}
/*
==================
Mod_AmbientLevels
grab the ambient sound levels for current point
==================
*/
void Mod_AmbientLevels( const vec3_t p, byte *pvolumes )
{
mleaf_t *leaf;
if( !worldmodel || !p || !pvolumes )
return;
leaf = Mod_PointInLeaf( p, worldmodel->nodes );
*(int *)pvolumes = *(int *)leaf->ambient_sound_level;
}
/*
=================
Mod_FindModelOrigin
@ -778,7 +891,7 @@ static void Mod_FindModelOrigin( const char *entities, const char *modelname, ve
qboolean model_found;
qboolean origin_found;
if( !entities || !modelname || !*modelname )
if( !entities || !COM_CheckString( modelname ))
return;
if( !origin || !VectorIsNull( origin ))
@ -1370,7 +1483,7 @@ static qboolean Mod_LoadColoredLighting( dbspmodel_t *bmod )
fs_offset_t litdatasize;
byte *in;
COM_FileBase( loadmodel->name, modelname );
COM_FileBase( loadmodel->name, modelname, sizeof( modelname ));
Q_snprintf( path, sizeof( path ), "maps/%s.lit", modelname );
// make sure what deluxemap is actual
@ -1395,7 +1508,7 @@ static qboolean Mod_LoadColoredLighting( dbspmodel_t *bmod )
if( litdatasize != ( bmod->lightdatasize * 3 ))
{
Con_Printf( S_ERROR "%s has mismatched size (%li should be %lu)\n", path, litdatasize, bmod->lightdatasize * 3 );
Con_Printf( S_ERROR "%s has mismatched size (%llu should be %zu)\n", path, litdatasize, bmod->lightdatasize * 3 );
Mem_Free( in );
return false;
}
@ -1425,7 +1538,7 @@ static void Mod_LoadDeluxemap( dbspmodel_t *bmod )
if( !FBitSet( host.features, ENGINE_LOAD_DELUXEDATA ))
return;
COM_FileBase( loadmodel->name, modelname );
COM_FileBase( loadmodel->name, modelname, sizeof( modelname ));
Q_snprintf( path, sizeof( path ), "maps/%s.dlit", modelname );
// make sure what deluxemap is actual
@ -1450,7 +1563,7 @@ static void Mod_LoadDeluxemap( dbspmodel_t *bmod )
if( deluxdatasize != bmod->lightdatasize )
{
Con_Reportf( S_ERROR "%s has mismatched size (%li should be %lu)\n", path, deluxdatasize, bmod->lightdatasize );
Con_Reportf( S_ERROR "%s has mismatched size (%llu should be %zu)\n", path, deluxdatasize, bmod->lightdatasize );
Mem_Free( in );
return;
}
@ -1517,7 +1630,10 @@ static void Mod_SetupSubmodels( dbspmodel_t *bmod )
if( i != 0 )
{
Mod_FindModelOrigin( ents, va( "*%i", i ), bm->origin );
char temp[MAX_VA_STRING];
Q_snprintf( temp, sizeof( temp ), "*%i", i );
Mod_FindModelOrigin( ents, temp, bm->origin );
// mark models that have origin brushes
if( !VectorIsNull( bm->origin ))
@ -1648,7 +1764,7 @@ static void Mod_LoadEntities( dbspmodel_t *bmod )
// world is check for entfile too
Q_strncpy( entfilename, loadmodel->name, sizeof( entfilename ));
COM_ReplaceExtension( entfilename, ".ent" );
COM_ReplaceExtension( entfilename, ".ent", sizeof( entfilename ));
// make sure what entity patch is never than bsp
ft1 = FS_FileTime( loadmodel->name, false );
@ -1711,13 +1827,13 @@ static void Mod_LoadEntities( dbspmodel_t *bmod )
wadstring[MAX_TOKEN - 2] = 0;
if( !Q_strchr( wadstring, ';' ))
Q_strcat( wadstring, ";" );
Q_strncat( wadstring, ";", sizeof( wadstring ));
// parse wad pathes
for( pszWadFile = strtok( wadstring, ";" ); pszWadFile != NULL; pszWadFile = strtok( NULL, ";" ))
{
COM_FixSlashes( pszWadFile );
COM_FileBase( pszWadFile, token );
COM_FileBase( pszWadFile, token, sizeof( token ));
// make sure what wad is really exist
if( FS_FileExists( va( "%s.wad", token ), false ))
@ -1896,6 +2012,289 @@ static void Mod_LoadMarkSurfaces( dbspmodel_t *bmod )
}
}
static void Mod_LoadTextureData( dbspmodel_t *bmod, int textureIndex )
{
#if !XASH_DEDICATED
texture_t *texture = NULL;
mip_t *mipTex = NULL;
qboolean usesCustomPalette = false;
uint32_t txFlags = 0;
// Don't load texture data on dedicated server, as there is no renderer.
// FIXME: for ENGINE_IMPROVED_LINETRACE we need to load textures on server too
// but there is no facility for this yet
if( Host_IsDedicated( ))
return;
texture = loadmodel->textures[textureIndex];
mipTex = Mod_GetMipTexForTexture( bmod, textureIndex );
if( FBitSet( host.features, ENGINE_IMPROVED_LINETRACE ) && mipTex->name[0] == '{' )
SetBits( txFlags, TF_KEEP_SOURCE ); // Paranoia2 texture alpha-tracing
usesCustomPalette = Mod_CalcMipTexUsesCustomPalette( bmod, textureIndex );
// check for multi-layered sky texture (quake1 specific)
if( bmod->isworld && Q_strncmp( mipTex->name, "sky", 3 ) == 0 && ( mipTex->width / mipTex->height ) == 2 )
{
ref.dllFuncs.R_InitSkyClouds( mipTex, texture, usesCustomPalette ); // load quake sky
if( R_GetBuiltinTexture( REF_SOLIDSKY_TEXTURE ) && R_GetBuiltinTexture( REF_ALPHASKY_TEXTURE ))
SetBits( world.flags, FWORLD_SKYSPHERE );
// No texture to load in this case, so just exit.
return;
}
// Texture loading order:
// 1. From WAD
// 2. Internal from map
// Try WAD texture (force while r_wadtextures is 1)
if(( r_wadtextures->value && bmod->wadlist.count > 0 ) || mipTex->offsets[0] <= 0 )
{
char texpath[MAX_VA_STRING];
int wadIndex = Mod_FindTextureInWadList( &bmod->wadlist, mipTex->name, texpath, sizeof( texpath ));
if( wadIndex >= 0 )
{
texture->gl_texturenum = ref.dllFuncs.GL_LoadTexture( texpath, NULL, 0, txFlags );
bmod->wadlist.wadusage[wadIndex]++;
}
}
// WAD failed, so use internal texture (if present)
if( mipTex->offsets[0] > 0 && texture->gl_texturenum == 0 )
{
char texName[64];
const size_t size = Mod_CalculateMipTexSize( mipTex, usesCustomPalette );
Q_snprintf( texName, sizeof( texName ), "#%s:%s.mip", loadstat.name, mipTex->name );
texture->gl_texturenum = ref.dllFuncs.GL_LoadTexture( texName, (byte *)mipTex, size, txFlags );
}
// If texture is completely missed:
if( texture->gl_texturenum == 0 )
{
Con_DPrintf( S_ERROR "Unable to find %s.mip\n", mipTex->name );
texture->gl_texturenum = R_GetBuiltinTexture( REF_DEFAULT_TEXTURE );
}
// Check for luma texture
if( FBitSet( REF_GET_PARM( PARM_TEX_FLAGS, texture->gl_texturenum ), TF_HAS_LUMA ))
{
char texName[64];
Q_snprintf( texName, sizeof( texName ), "#%s:%s_luma.mip", loadstat.name, mipTex->name );
if( mipTex->offsets[0] > 0 )
{
const size_t size = Mod_CalculateMipTexSize( mipTex, usesCustomPalette );
texture->fb_texturenum = ref.dllFuncs.GL_LoadTexture( texName, (byte *)mipTex, size, TF_MAKELUMA );
}
else
{
char texpath[MAX_VA_STRING];
int wadIndex;
fs_offset_t srcSize = 0;
byte* src = NULL;
// NOTE: We can't load the _luma texture from the WAD as normal because it
// 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 ));
if( wadIndex >= 0 )
{
src = FS_LoadFile( texpath, &srcSize, false );
bmod->wadlist.wadusage[wadIndex]++;
}
// OK, loading it from wad or hi-res version
texture->fb_texturenum = ref.dllFuncs.GL_LoadTexture( texName, src, srcSize, TF_MAKELUMA );
if( src )
Mem_Free( src );
}
}
#endif // !XASH_DEDICATED
}
static void Mod_LoadTexture( dbspmodel_t *bmod, int textureIndex )
{
texture_t *texture;
mip_t *mipTex;
if( textureIndex < 0 || textureIndex >= loadmodel->numtextures )
return;
mipTex = Mod_GetMipTexForTexture( bmod, textureIndex );
if( !mipTex )
{
// No data for this texture.
// Create default texture (some mods require this).
Mod_CreateDefaultTexture( &loadmodel->textures[textureIndex] );
return;
}
if( mipTex->name[0] == '\0' )
Q_snprintf( mipTex->name, sizeof( mipTex->name ), "miptex_%i", textureIndex );
texture = (texture_t *)Mem_Calloc( loadmodel->mempool, sizeof( *texture ));
loadmodel->textures[textureIndex] = texture;
// Ensure texture name is lowercase.
Q_strnlwr( mipTex->name, texture->name, sizeof( texture->name ));
texture->width = mipTex->width;
texture->height = mipTex->height;
Mod_LoadTextureData( bmod, textureIndex );
}
static void Mod_LoadAllTextures( dbspmodel_t *bmod )
{
int i;
for( i = 0; i < loadmodel->numtextures; i++ )
Mod_LoadTexture( bmod, i );
}
static void Mod_SequenceAnimatedTexture( int baseTextureIndex )
{
texture_t *anims[10];
texture_t *altanims[10];
texture_t *baseTexture;
int max = 0;
int altmax = 0;
int candidateIndex;
if( baseTextureIndex < 0 || baseTextureIndex >= loadmodel->numtextures )
return;
baseTexture = loadmodel->textures[baseTextureIndex];
if( !Mod_NameImpliesTextureIsAnimated( baseTexture ))
return;
// Already sequenced
if( baseTexture->anim_next )
return;
// find the number of frames in the animation
memset( anims, 0, sizeof( anims ));
memset( altanims, 0, sizeof( altanims ));
if( baseTexture->name[1] >= '0' && baseTexture->name[1] <= '9' )
{
// This texture is a standard animation frame.
int frameIndex = (int)baseTexture->name[1] - (int)'0';
anims[frameIndex] = baseTexture;
max = frameIndex + 1;
}
else
{
// This texture is an alternate animation frame.
int frameIndex = (int)baseTexture->name[1] - (int)'a';
altanims[frameIndex] = baseTexture;
altmax = frameIndex + 1;
}
// Now search the rest of the textures to find all other frames.
for( candidateIndex = baseTextureIndex + 1; candidateIndex < loadmodel->numtextures; candidateIndex++ )
{
texture_t *altTexture = loadmodel->textures[candidateIndex];
if( !Mod_NameImpliesTextureIsAnimated( altTexture ))
continue;
// This texture is animated, but is it part of the same group as
// the original texture we encountered? Check that the rest of
// the name matches the original (both will be valid for at least
// string index 2).
if( Q_strcmp( altTexture->name + 2, baseTexture->name + 2 ) != 0 )
continue;
if( altTexture->name[1] >= '0' && altTexture->name[1] <= '9' )
{
// This texture is a standard frame.
int frameIndex = (int)altTexture->name[1] - (int)'0';
anims[frameIndex] = altTexture;
if( frameIndex >= max )
max = frameIndex + 1;
}
else
{
// This texture is an alternate frame.
int frameIndex = (int)altTexture->name[1] - (int)'a';
altanims[frameIndex] = altTexture;
if( frameIndex >= altmax )
altmax = frameIndex + 1;
}
}
// Link all standard animated frames together.
for( candidateIndex = 0; candidateIndex < max; candidateIndex++ )
{
texture_t *tex = anims[candidateIndex];
if( !tex )
{
Con_Printf( S_ERROR "Mod_SequenceAnimatedTexture: missing frame %i of animated texture \"%s\"\n",
candidateIndex,
baseTexture->name );
baseTexture->anim_total = 0;
break;
}
tex->anim_total = max * ANIM_CYCLE;
tex->anim_min = candidateIndex * ANIM_CYCLE;
tex->anim_max = ( candidateIndex + 1 ) * ANIM_CYCLE;
tex->anim_next = anims[( candidateIndex + 1 ) % max];
if( altmax > 0 )
tex->alternate_anims = altanims[0];
}
// Link all alternate animated frames together.
for( candidateIndex = 0; candidateIndex < altmax; candidateIndex++ )
{
texture_t *tex = altanims[candidateIndex];
if( !tex )
{
Con_Printf( S_ERROR "Mod_SequenceAnimatedTexture: missing alternate frame %i of animated texture \"%s\"\n",
candidateIndex,
baseTexture->name );
baseTexture->anim_total = 0;
break;
}
tex->anim_total = altmax * ANIM_CYCLE;
tex->anim_min = candidateIndex * ANIM_CYCLE;
tex->anim_max = ( candidateIndex + 1 ) * ANIM_CYCLE;
tex->anim_next = altanims[( candidateIndex + 1 ) % altmax];
if( max > 0 )
tex->alternate_anims = anims[0];
}
}
static void Mod_SequenceAllAnimatedTextures( void )
{
int i;
for( i = 0; i < loadmodel->numtextures; i++ )
Mod_SequenceAnimatedTexture( i );
}
/*
=================
Mod_LoadTextures
@ -1903,300 +2302,31 @@ Mod_LoadTextures
*/
static void Mod_LoadTextures( dbspmodel_t *bmod )
{
dmiptexlump_t *in;
texture_t *tx, *tx2;
texture_t *anims[10];
texture_t *altanims[10];
int num, max, altmax;
qboolean custom_palette;
char texname[64];
mip_t *mt;
int i, j;
dmiptexlump_t *lump;
if( bmod->isworld )
{
#if !XASH_DEDICATED
// release old sky layers first
if( !Host_IsDedicated() )
{
ref.dllFuncs.GL_FreeTexture( R_GetBuiltinTexture( REF_ALPHASKY_TEXTURE ));
ref.dllFuncs.GL_FreeTexture( R_GetBuiltinTexture( REF_SOLIDSKY_TEXTURE ));
}
#endif
// release old sky layers first
if( !Host_IsDedicated() && bmod->isworld )
{
ref.dllFuncs.GL_FreeTexture( R_GetBuiltinTexture( REF_ALPHASKY_TEXTURE ));
ref.dllFuncs.GL_FreeTexture( R_GetBuiltinTexture( REF_SOLIDSKY_TEXTURE ));
}
#endif
if( !bmod->texdatasize )
lump = bmod->textures;
if( bmod->texdatasize < 1 || !lump || lump->nummiptex < 1 )
{
// no textures
loadmodel->textures = NULL;
return;
}
in = bmod->textures;
loadmodel->textures = (texture_t **)Mem_Calloc( loadmodel->mempool, in->nummiptex * sizeof( texture_t* ));
loadmodel->numtextures = in->nummiptex;
loadmodel->textures = (texture_t **)Mem_Calloc( loadmodel->mempool, lump->nummiptex * sizeof( texture_t * ));
loadmodel->numtextures = lump->nummiptex;
for( i = 0; i < loadmodel->numtextures; i++ )
{
int txFlags = 0;
if( in->dataofs[i] == -1 )
{
// create default texture (some mods requires this)
tx = Mem_Calloc( loadmodel->mempool, sizeof( *tx ));
loadmodel->textures[i] = tx;
Q_strncpy( tx->name, "*default", sizeof( tx->name ));
#if !XASH_DEDICATED
if( !Host_IsDedicated() )
{
tx->gl_texturenum = R_GetBuiltinTexture( REF_DEFAULT_TEXTURE );
tx->width = tx->height = 16;
}
#endif
continue; // missed
}
mt = (mip_t *)((byte *)in + in->dataofs[i] );
if( !mt->name[0] )
Q_snprintf( mt->name, sizeof( mt->name ), "miptex_%i", i );
tx = Mem_Calloc( loadmodel->mempool, sizeof( *tx ));
loadmodel->textures[i] = tx;
// convert to lowercase
Q_strncpy( tx->name, mt->name, sizeof( tx->name ));
Q_strnlwr( tx->name, tx->name, sizeof( tx->name ));
custom_palette = false;
tx->width = mt->width;
tx->height = mt->height;
if( FBitSet( host.features, ENGINE_IMPROVED_LINETRACE ) && mt->name[0] == '{' )
SetBits( txFlags, TF_KEEP_SOURCE ); // Paranoia2 texture alpha-tracing
if( mt->offsets[0] > 0 )
{
int size = (int)sizeof( mip_t ) + ((mt->width * mt->height * 85)>>6);
int next_dataofs = 0, remaining;
// compute next dataofset to determine allocated miptex space
for( j = i + 1; j < loadmodel->numtextures; j++ )
{
next_dataofs = in->dataofs[j];
if( next_dataofs != -1 ) break;
}
if( j == loadmodel->numtextures )
next_dataofs = bmod->texdatasize;
// NOTE: imagelib detect miptex version by size
// 770 additional bytes is indicated custom palette
remaining = next_dataofs - (in->dataofs[i] + size);
if( remaining >= 770 ) custom_palette = true;
}
#if !XASH_DEDICATED
if( !Host_IsDedicated() )
{
// check for multi-layered sky texture (quake1 specific)
if( bmod->isworld && !Q_strncmp( mt->name, "sky", 3 ) && (( mt->width / mt->height ) == 2 ) )
{
ref.dllFuncs.R_InitSkyClouds( mt, tx, custom_palette ); // load quake sky
if( R_GetBuiltinTexture( REF_SOLIDSKY_TEXTURE ) &&
R_GetBuiltinTexture( REF_ALPHASKY_TEXTURE ) )
SetBits( world.flags, FWORLD_SKYSPHERE );
continue;
}
// texture loading order:
// 1. from wad
// 2. internal from map
// trying wad texture (force while r_wadtextures is 1)
if(( r_wadtextures->value && bmod->wadlist.count > 0 ) || ( mt->offsets[0] <= 0 ))
{
Q_snprintf( texname, sizeof( texname ), "%s.mip", mt->name );
// check wads in reverse order
for( j = bmod->wadlist.count - 1; j >= 0; j-- )
{
char *texpath = va( "%s.wad/%s", bmod->wadlist.wadnames[j], texname );
if( FS_FileExists( texpath, false ))
{
tx->gl_texturenum = ref.dllFuncs.GL_LoadTexture( texpath, NULL, 0, txFlags );
bmod->wadlist.wadusage[j]++; // this wad are really used
break;
}
}
}
// wad failed, so use internal texture (if present)
if( mt->offsets[0] > 0 && !tx->gl_texturenum )
{
// NOTE: imagelib detect miptex version by size
// 770 additional bytes is indicated custom palette
int size = (int)sizeof( mip_t ) + ((mt->width * mt->height * 85)>>6);
if( custom_palette ) size += sizeof( short ) + 768;
Q_snprintf( texname, sizeof( texname ), "#%s:%s.mip", loadstat.name, mt->name );
tx->gl_texturenum = ref.dllFuncs.GL_LoadTexture( texname, (byte *)mt, size, txFlags );
}
// if texture is completely missed
if( !tx->gl_texturenum )
{
Con_DPrintf( S_ERROR "unable to find %s.mip\n", mt->name );
tx->gl_texturenum = R_GetBuiltinTexture( REF_DEFAULT_TEXTURE );
}
// check for luma texture
if( FBitSet( REF_GET_PARM( PARM_TEX_FLAGS, tx->gl_texturenum ), TF_HAS_LUMA ))
{
Q_snprintf( texname, sizeof( texname ), "#%s:%s_luma.mip", loadstat.name, mt->name );
if( mt->offsets[0] > 0 )
{
// NOTE: imagelib detect miptex version by size
// 770 additional bytes is indicated custom palette
int size = (int)sizeof( mip_t ) + ((mt->width * mt->height * 85)>>6);
if( custom_palette ) size += sizeof( short ) + 768;
tx->fb_texturenum = ref.dllFuncs.GL_LoadTexture( texname, (byte *)mt, size, TF_MAKELUMA );
}
else
{
fs_offset_t srcSize = 0;
byte *src = NULL;
// NOTE: we can't loading it from wad as normal because _luma texture doesn't exist
// and not be loaded. But original texture is already loaded and can't be modified
// So load original texture manually and convert it to luma
// check wads in reverse order
for( j = bmod->wadlist.count - 1; j >= 0; j-- )
{
char *texpath = va( "%s.wad/%s.mip", bmod->wadlist.wadnames[j], tx->name );
if( FS_FileExists( texpath, false ))
{
src = FS_LoadFile( texpath, &srcSize, false );
bmod->wadlist.wadusage[j]++; // this wad are really used
break;
}
}
// okay, loading it from wad or hi-res version
tx->fb_texturenum = ref.dllFuncs.GL_LoadTexture( texname, src, srcSize, TF_MAKELUMA );
if( src ) Mem_Free( src );
}
}
}
#endif
}
// sequence the animations and detail textures
for( i = 0; i < loadmodel->numtextures; i++ )
{
tx = loadmodel->textures[i];
if( !tx || ( tx->name[0] != '-' && tx->name[0] != '+' ))
continue;
if( tx->anim_next )
continue; // already sequenced
// find the number of frames in the animation
memset( anims, 0, sizeof( anims ));
memset( altanims, 0, sizeof( altanims ));
max = tx->name[1];
altmax = 0;
if( max >= '0' && max <= '9' )
{
max -= '0';
altmax = 0;
anims[max] = tx;
max++;
}
else if( max >= 'a' && max <= 'j' )
{
altmax = max - 'a';
max = 0;
altanims[altmax] = tx;
altmax++;
}
else Con_Printf( S_ERROR "Mod_LoadTextures: bad animating texture %s\n", tx->name );
for( j = i + 1; j < loadmodel->numtextures; j++ )
{
tx2 = loadmodel->textures[j];
if( !tx2 || ( tx2->name[0] != '-' && tx2->name[0] != '+' ))
continue;
if( Q_strcmp( tx2->name + 2, tx->name + 2 ))
continue;
num = tx2->name[1];
if( num >= '0' && num <= '9' )
{
num -= '0';
anims[num] = tx2;
if( num + 1 > max )
max = num + 1;
}
else if( num >= 'a' && num <= 'j' )
{
num = num - 'a';
altanims[num] = tx2;
if( num + 1 > altmax )
altmax = num + 1;
}
else Con_Printf( S_ERROR "Mod_LoadTextures: bad animating texture %s\n", tx->name );
}
// link them all together
for( j = 0; j < max; j++ )
{
tx2 = anims[j];
if( !tx2 )
{
Con_Printf( S_ERROR "Mod_LoadTextures: missing frame %i of %s\n", j, tx->name );
tx->anim_total = 0;
break;
}
tx2->anim_total = max * ANIM_CYCLE;
tx2->anim_min = j * ANIM_CYCLE;
tx2->anim_max = (j + 1) * ANIM_CYCLE;
tx2->anim_next = anims[(j + 1) % max];
if( altmax ) tx2->alternate_anims = altanims[0];
}
for( j = 0; j < altmax; j++ )
{
tx2 = altanims[j];
if( !tx2 )
{
Con_Printf( S_ERROR "Mod_LoadTextures: missing frame %i of %s\n", j, tx->name );
tx->anim_total = 0;
break;
}
tx2->anim_total = altmax * ANIM_CYCLE;
tx2->anim_min = j * ANIM_CYCLE;
tx2->anim_max = (j+1) * ANIM_CYCLE;
tx2->anim_next = altanims[(j + 1) % altmax];
if( max ) tx2->alternate_anims = anims[0];
}
}
Mod_LoadAllTextures( bmod );
Mod_SequenceAllAnimatedTextures();
}
/*
@ -2299,7 +2429,7 @@ static void Mod_LoadSurfaces( dbspmodel_t *bmod )
if(( in->firstedge + in->numedges ) > loadmodel->numsurfedges )
{
Con_Reportf( S_ERROR "bad surface %i from %lu\n", i, bmod->numsurfaces );
Con_Reportf( S_ERROR "bad surface %i from %zu\n", i, bmod->numsurfaces );
continue;
}
@ -2319,7 +2449,7 @@ static void Mod_LoadSurfaces( dbspmodel_t *bmod )
if( !Q_strncmp( tex->name, "sky", 3 ))
SetBits( out->flags, SURF_DRAWSKY );
if(( tex->name[0] == '*' && Q_stricmp( tex->name, "*default" )) || tex->name[0] == '!' )
if(( tex->name[0] == '*' && Q_stricmp( tex->name, REF_DEFAULT_TEXTURE )) || tex->name[0] == '!' )
SetBits( out->flags, SURF_DRAWTURB );
if( !Host_IsQuakeCompatible( ))
@ -2634,7 +2764,7 @@ static void Mod_LoadLightVecs( dbspmodel_t *bmod )
if( bmod->deluxdatasize != bmod->lightdatasize )
{
if( bmod->deluxdatasize > 0 )
Con_Printf( S_ERROR "Mod_LoadLightVecs: has mismatched size (%lu should be %i)\n", bmod->deluxdatasize, bmod->lightdatasize );
Con_Printf( S_ERROR "Mod_LoadLightVecs: has mismatched size (%zu should be %zu)\n", bmod->deluxdatasize, bmod->lightdatasize );
else Mod_LoadDeluxemap( bmod ); // old method
return;
}
@ -2653,7 +2783,7 @@ static void Mod_LoadShadowmap( dbspmodel_t *bmod )
if( bmod->shadowdatasize != ( bmod->lightdatasize / 3 ))
{
if( bmod->shadowdatasize > 0 )
Con_Printf( S_ERROR "Mod_LoadShadowmap: has mismatched size (%i should be %lu)\n", bmod->shadowdatasize, bmod->lightdatasize / 3 );
Con_Printf( S_ERROR "Mod_LoadShadowmap: has mismatched size (%zu should be %zu)\n", bmod->shadowdatasize, bmod->lightdatasize / 3 );
return;
}
@ -3019,9 +3149,13 @@ Mod_LoadBrushModel
*/
void Mod_LoadBrushModel( model_t *mod, const void *buffer, qboolean *loaded )
{
char poolname[MAX_VA_STRING];
Q_snprintf( poolname, sizeof( poolname ), "^2%s^7", loadmodel->name );
if( loaded ) *loaded = false;
loadmodel->mempool = Mem_AllocPool( va( "^2%s^7", loadmodel->name ));
loadmodel->mempool = Mem_AllocPool( poolname );
loadmodel->type = mod_brush;
// loading all the lumps into heap

View File

@ -156,7 +156,6 @@ int Mod_CheckLump( const char *filename, const int lump, int *lumpsize );
int Mod_ReadLump( const char *filename, const int lump, void **lumpdata, int *lumpsize );
int Mod_SaveLump( const char *filename, const int lump, void *lumpdata, int lumpsize );
mleaf_t *Mod_PointInLeaf( const vec3_t p, mnode_t *node );
void Mod_AmbientLevels( const vec3_t p, byte *pvolumes );
int Mod_SampleSizeForFace( msurface_t *surf );
byte *Mod_GetPVSForPoint( const vec3_t p );
void Mod_UnloadBrushModel( model_t *mod );

View File

@ -35,6 +35,7 @@ void Mod_LoadSpriteModel( model_t *mod, const void *buffer, qboolean *loaded, ui
dsprite_hl_t *pinhl;
dsprite_t *pin;
msprite_t *psprite;
char poolname[MAX_VA_STRING];
int i, size;
if( loaded ) *loaded = false;
@ -54,7 +55,8 @@ void Mod_LoadSpriteModel( model_t *mod, const void *buffer, qboolean *loaded, ui
return;
}
mod->mempool = Mem_AllocPool( va( "^2%s^7", mod->name ));
Q_snprintf( poolname, sizeof( poolname ), "^2%s^7", mod->name );
mod->mempool = Mem_AllocPool( poolname );
if( i == SPRITE_VERSION_Q1 || i == SPRITE_VERSION_32 )
{

View File

@ -429,7 +429,7 @@ void *R_StudioGetAnim( studiohdr_t *m_pStudioHeader, model_t *m_pSubModel, mstud
{
string filepath, modelname, modelpath;
COM_FileBase( m_pSubModel->name, modelname );
COM_FileBase( m_pSubModel->name, modelname, sizeof( modelname ));
COM_ExtractFilePath( m_pSubModel->name, modelpath );
// NOTE: here we build real sub-animation filename because stupid user may rename model without recompile
@ -848,10 +848,13 @@ Mod_LoadStudioModel
*/
void Mod_LoadStudioModel( model_t *mod, const void *buffer, qboolean *loaded )
{
char poolname[MAX_VA_STRING];
studiohdr_t *phdr;
Q_snprintf( poolname, sizeof( poolname ), "^2%s^7", loadmodel->name );
if( loaded ) *loaded = false;
loadmodel->mempool = Mem_AllocPool( va( "^2%s^7", loadmodel->name ));
loadmodel->mempool = Mem_AllocPool( poolname );
loadmodel->type = mod_studio;
phdr = R_StudioLoadHeader( mod, buffer );

View File

@ -359,17 +359,6 @@ void MSG_WriteVec3Angles( sizebuf_t *sb, const float *fa )
MSG_WriteBitAngle( sb, fa[2], 16 );
}
void MSG_WriteBitFloat( sizebuf_t *sb, float val )
{
int intVal;
Assert( sizeof( int ) == sizeof( float ));
Assert( sizeof( float ) == 4 );
intVal = *((int *)&val );
MSG_WriteUBitLong( sb, intVal, 32 );
}
void MSG_WriteCmdExt( sizebuf_t *sb, int cmd, netsrc_t type, const char *name )
{
#ifdef DEBUG_NET_MESSAGES_SEND
@ -452,6 +441,18 @@ qboolean MSG_WriteString( sizebuf_t *sb, const char *pStr )
return !sb->bOverflow;
}
qboolean MSG_WriteStringf( sizebuf_t *sb, const char *format, ... )
{
va_list va;
char buf[MAX_VA_STRING];
va_start( va, format );
Q_vsnprintf( buf, sizeof( buf ), format, va );
va_end( va );
return MSG_WriteString( sb, buf );
}
int MSG_ReadOneBit( sizebuf_t *sb )
{
if( !MSG_Overflow( sb, 1 ))
@ -511,32 +512,6 @@ uint MSG_ReadUBitLong( sizebuf_t *sb, int numbits )
return ret;
}
float MSG_ReadBitFloat( sizebuf_t *sb )
{
int val;
int bit, byte;
Assert( sizeof( float ) == sizeof( int ));
Assert( sizeof( float ) == 4 );
if( MSG_Overflow( sb, 32 ))
return 0.0f;
bit = sb->iCurBit & 0x7;
byte = sb->iCurBit >> 3;
val = sb->pData[byte] >> bit;
val |= ((int)sb->pData[byte + 1]) << ( 8 - bit );
val |= ((int)sb->pData[byte + 2]) << ( 16 - bit );
val |= ((int)sb->pData[byte + 3]) << ( 24 - bit );
if( bit != 0 )
val |= ((int)sb->pData[byte + 4]) << ( 32 - bit );
sb->iCurBit += 32;
return *((float *)&val);
}
qboolean MSG_ReadBits( sizebuf_t *sb, void *pOutData, int nBits )
{
byte *pOut = (byte *)pOutData;

View File

@ -84,7 +84,6 @@ void MSG_WriteSBitLong( sizebuf_t *sb, int data, int numbits );
void MSG_WriteBitLong( sizebuf_t *sb, uint data, int numbits, qboolean bSigned );
qboolean MSG_WriteBits( sizebuf_t *sb, const void *pData, int nBits );
void MSG_WriteBitAngle( sizebuf_t *sb, float fAngle, int numbits );
void MSG_WriteBitFloat( sizebuf_t *sb, float val );
// Byte-write functions
#define MSG_BeginServerCmd( sb, cmd ) MSG_WriteCmdExt( sb, cmd, NS_SERVER, NULL )
@ -102,6 +101,7 @@ void MSG_WriteVec3Coord( sizebuf_t *sb, const float *fa );
void MSG_WriteVec3Angles( sizebuf_t *sb, const float *fa );
qboolean MSG_WriteBytes( sizebuf_t *sb, const void *pBuf, int nBytes ); // same as MSG_WriteData
qboolean MSG_WriteString( sizebuf_t *sb, const char *pStr ); // returns false if it overflows the buffer.
qboolean MSG_WriteStringf( sizebuf_t *sb, const char *format, ... ) _format( 2 );
// helper functions
_inline int MSG_GetNumBytesWritten( sizebuf_t *sb ) { return BitByte( sb->iCurBit ); }
@ -116,7 +116,6 @@ _inline byte *MSG_GetBuf( sizebuf_t *sb ) { return sb->pData; } // just an alias
// Bit-read functions
int MSG_ReadOneBit( sizebuf_t *sb );
float MSG_ReadBitFloat( sizebuf_t *sb );
qboolean MSG_ReadBits( sizebuf_t *sb, void *pOutData, int nBits );
float MSG_ReadBitAngle( sizebuf_t *sb, int numbits );
int MSG_ReadSBitLong( sizebuf_t *sb, int numbits );

View File

@ -251,7 +251,7 @@ void Netchan_Init( void )
net_showpackets = Cvar_Get ("net_showpackets", "0", 0, "show network packets" );
net_chokeloopback = Cvar_Get( "net_chokeloop", "0", 0, "apply bandwidth choke to loopback packets" );
net_showdrop = Cvar_Get( "net_showdrop", "0", 0, "show packets that are dropped" );
net_qport = Cvar_Get( "net_qport", va( "%i", port ), FCVAR_READ_ONLY, "current quake netport" );
net_qport = Cvar_Getf( "net_qport", FCVAR_READ_ONLY, "current quake netport", "%i", port );
net_mempool = Mem_AllocPool( "Network Pool" );
@ -273,8 +273,8 @@ void Netchan_ReportFlow( netchan_t *chan )
Assert( chan != NULL );
Q_strcpy( incoming, Q_pretifymem((float)chan->flow[FLOW_INCOMING].totalbytes, 3 ));
Q_strcpy( outgoing, Q_pretifymem((float)chan->flow[FLOW_OUTGOING].totalbytes, 3 ));
Q_strncpy( incoming, Q_pretifymem((float)chan->flow[FLOW_INCOMING].totalbytes, 3 ), sizeof( incoming ));
Q_strncpy( outgoing, Q_pretifymem((float)chan->flow[FLOW_OUTGOING].totalbytes, 3 ), sizeof( outgoing ));
Con_DPrintf( "Signon network traffic: %s from server, %s to server\n", incoming, outgoing );
}
@ -973,7 +973,7 @@ int Netchan_CreateFileFragments( netchan_t *chan, const char *filename )
else chunksize = FRAGMENT_MAX_SIZE; // fallback
Q_strncpy( compressedfilename, filename, sizeof( compressedfilename ));
COM_ReplaceExtension( compressedfilename, ".ztmp" );
COM_ReplaceExtension( compressedfilename, ".ztmp", sizeof( compressedfilename ));
compressedFileTime = FS_FileTime( compressedfilename, false );
fileTime = FS_FileTime( filename, false );
@ -1559,7 +1559,7 @@ void Netchan_TransmitBits( netchan_t *chan, int length, byte *data )
char compressedfilename[MAX_OSPATH];
Q_strncpy( compressedfilename, pbuf->filename, sizeof( compressedfilename ));
COM_ReplaceExtension( compressedfilename, ".ztmp" );
COM_ReplaceExtension( compressedfilename, ".ztmp", sizeof( compressedfilename ));
file = FS_Open( compressedfilename, "rb", false );
}
else file = FS_Open( pbuf->filename, "rb", false );
@ -1711,21 +1711,6 @@ void Netchan_TransmitBits( netchan_t *chan, int length, byte *data )
}
}
/*
===============
Netchan_Transmit
tries to send an unreliable message to a connection, and handles the
transmition / retransmition of the reliable messages.
A 0 length will still generate a packet and deal with the reliable messages.
================
*/
void Netchan_Transmit( netchan_t *chan, int lengthInBytes, byte *data )
{
Netchan_TransmitBits( chan, lengthInBytes << 3, data );
}
/*
=================
Netchan_Process

View File

@ -28,6 +28,26 @@ GNU General Public License for more details.
#define DELTA_PATH "delta.lst"
#define DT_BYTE BIT( 0 ) // A byte
#define DT_SHORT BIT( 1 ) // 2 byte field
#define DT_FLOAT BIT( 2 ) // A floating point field
#define DT_INTEGER BIT( 3 ) // 4 byte integer
#define DT_ANGLE BIT( 4 ) // A floating point angle ( will get masked correctly )
#define DT_TIMEWINDOW_8 BIT( 5 ) // A floating point timestamp, relative to sv.time
#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 NUM_FIELDS( x ) ((sizeof( x ) / sizeof( x[0] )) - 1)
// helper macroses
#define ENTS_DEF( x ) #x, offsetof( entity_state_t, x ), sizeof( ((entity_state_t *)0)->x )
#define UCMD_DEF( x ) #x, offsetof( usercmd_t, x ), sizeof( ((usercmd_t *)0)->x )
#define EVNT_DEF( x ) #x, offsetof( event_args_t, x ), sizeof( ((event_args_t *)0)->x )
#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 )
static qboolean delta_init = false;
// list of all the struct names
@ -308,7 +328,7 @@ static delta_info_t dt_info[] =
{ NULL },
};
delta_info_t *Delta_FindStruct( const char *name )
static delta_info_t *Delta_FindStruct( const char *name )
{
int i;
@ -340,7 +360,7 @@ delta_info_t *Delta_FindStructByIndex( int index )
return &dt_info[index];
}
delta_info_t *Delta_FindStructByEncoder( const char *encoderName )
static delta_info_t *Delta_FindStructByEncoder( const char *encoderName )
{
int i;
@ -356,7 +376,7 @@ delta_info_t *Delta_FindStructByEncoder( const char *encoderName )
return NULL;
}
delta_info_t *Delta_FindStructByDelta( const delta_t *pFields )
static delta_info_t *Delta_FindStructByDelta( const delta_t *pFields )
{
int i;
@ -371,7 +391,7 @@ delta_info_t *Delta_FindStructByDelta( const delta_t *pFields )
return NULL;
}
void Delta_CustomEncode( delta_info_t *dt, const void *from, const void *to )
static void Delta_CustomEncode( delta_info_t *dt, const void *from, const void *to )
{
int i;
@ -387,7 +407,7 @@ void Delta_CustomEncode( delta_info_t *dt, const void *from, const void *to )
}
}
delta_field_t *Delta_FindFieldInfo( const delta_field_t *pInfo, const char *fieldName )
static delta_field_t *Delta_FindFieldInfo( const delta_field_t *pInfo, const char *fieldName )
{
if( !fieldName || !*fieldName )
return NULL;
@ -400,7 +420,7 @@ delta_field_t *Delta_FindFieldInfo( const delta_field_t *pInfo, const char *fiel
return NULL;
}
int Delta_IndexForFieldInfo( const delta_field_t *pInfo, const char *fieldName )
static int Delta_IndexForFieldInfo( const delta_field_t *pInfo, const char *fieldName )
{
int i;
@ -415,7 +435,7 @@ int Delta_IndexForFieldInfo( const delta_field_t *pInfo, const char *fieldName )
return -1;
}
qboolean Delta_AddField( const char *pStructName, const char *pName, int flags, int bits, float mul, float post_mul )
static qboolean Delta_AddField( const char *pStructName, const char *pName, int flags, int bits, float mul, float post_mul )
{
delta_info_t *dt;
delta_field_t *pFieldInfo;
@ -494,14 +514,14 @@ void Delta_WriteTableField( sizebuf_t *msg, int tableIndex, const delta_t *pFiel
MSG_WriteUBitLong( msg, pField->bits - 1, 5 ); // max received value is 32 (32 bit)
// multipliers is null-compressed
if( !Q_equal(pField->multiplier, 1.0f) )
if( !Q_equal( pField->multiplier, 1.0f ))
{
MSG_WriteOneBit( msg, 1 );
MSG_WriteFloat( msg, pField->multiplier );
}
else MSG_WriteOneBit( msg, 0 );
if( !Q_equal(pField->post_multiplier, 1.0f) )
if( !Q_equal( pField->post_multiplier, 1.0f ))
{
MSG_WriteOneBit( msg, 1 );
MSG_WriteFloat( msg, pField->post_multiplier );
@ -555,7 +575,7 @@ void Delta_ParseTableField( sizebuf_t *msg )
Delta_AddField( dt->pName, pName, flags, bits, mul, post_mul );
}
qboolean Delta_ParseField( char **delta_script, const delta_field_t *pInfo, delta_t *pField, qboolean bPost )
static qboolean Delta_ParseField( char **delta_script, const delta_field_t *pInfo, delta_t *pField, qboolean bPost )
{
string token;
delta_field_t *pFieldInfo;
@ -633,7 +653,7 @@ qboolean Delta_ParseField( char **delta_script, const delta_field_t *pInfo, delt
// read delta-bits
if(( *delta_script = COM_ParseFile( *delta_script, token, sizeof( token ))) == NULL )
{
Con_DPrintf( S_ERROR "Delta_ReadField: %s field bits argument is missing\n", pField->name );
Con_DPrintf( S_ERROR "Delta_ParseField: %s field bits argument is missing\n", pField->name );
return false;
}
@ -642,14 +662,14 @@ qboolean Delta_ParseField( char **delta_script, const delta_field_t *pInfo, delt
*delta_script = COM_ParseFile( *delta_script, token, sizeof( token ));
if( Q_strcmp( token, "," ))
{
Con_DPrintf( S_ERROR "Delta_ReadField: expected ',', found '%s' instead\n", token );
Con_DPrintf( S_ERROR "Delta_ParseField: expected ',', found '%s' instead\n", token );
return false;
}
// read delta-multiplier
if(( *delta_script = COM_ParseFile( *delta_script, token, sizeof( token ))) == NULL )
{
Con_DPrintf( S_ERROR "Delta_ReadField: %s missing 'multiplier' argument\n", pField->name );
Con_DPrintf( S_ERROR "Delta_ParseField: %s missing 'multiplier' argument\n", pField->name );
return false;
}
@ -660,14 +680,14 @@ qboolean Delta_ParseField( char **delta_script, const delta_field_t *pInfo, delt
*delta_script = COM_ParseFile( *delta_script, token, sizeof( token ));
if( Q_strcmp( token, "," ))
{
Con_DPrintf( S_ERROR "Delta_ReadField: expected ',', found '%s' instead\n", token );
Con_DPrintf( S_ERROR "Delta_ParseField: expected ',', found '%s' instead\n", token );
return false;
}
// read delta-postmultiplier
if(( *delta_script = COM_ParseFile( *delta_script, token, sizeof( token ))) == NULL )
{
Con_DPrintf( S_ERROR "Delta_ReadField: %s missing 'post_multiply' argument\n", pField->name );
Con_DPrintf( S_ERROR "Delta_ParseField: %s missing 'post_multiply' argument\n", pField->name );
return false;
}
@ -695,7 +715,7 @@ qboolean Delta_ParseField( char **delta_script, const delta_field_t *pInfo, delt
return true;
}
void Delta_ParseTable( char **delta_script, delta_info_t *dt, const char *encodeDll, const char *encodeFunc )
static void Delta_ParseTable( char **delta_script, delta_info_t *dt, const char *encodeDll, const char *encodeFunc )
{
string token;
delta_t *pField;
@ -749,7 +769,7 @@ void Delta_ParseTable( char **delta_script, delta_info_t *dt, const char *encode
dt->bInitialized = true; // table is ok
}
void Delta_InitFields( void )
static void Delta_InitFields( void )
{
byte *afile;
char *pfile;
@ -773,7 +793,7 @@ void Delta_InitFields( void )
pfile = COM_ParseFile( pfile, encodeDll, sizeof( encodeDll ));
if( !Q_stricmp( encodeDll, "none" ))
Q_strcpy( encodeFunc, "null" );
Q_strncpy( encodeFunc, "null", sizeof( encodeFunc ));
else pfile = COM_ParseFile( pfile, encodeFunc, sizeof( encodeFunc ));
// jump to '{'
@ -894,7 +914,7 @@ Delta_ClampIntegerField
prevent data to out of range
=====================
*/
int Delta_ClampIntegerField( delta_t *pField, int iValue, qboolean bSigned, int numbits )
static int Delta_ClampIntegerField( delta_t *pField, int iValue, qboolean bSigned, int numbits )
{
#ifdef _DEBUG
if( numbits < 32 && abs( iValue ) >= (uint)BIT( numbits ))
@ -902,7 +922,7 @@ int Delta_ClampIntegerField( delta_t *pField, int iValue, qboolean bSigned, int
#endif
if( numbits < 32 )
{
int signbits = bSigned ? (numbits - 1) : numbits;
int signbits = bSigned ? ( numbits - 1 ) : numbits;
int maxnum = BIT( signbits ) - 1;
int minnum = bSigned ? ( -maxnum - 1 ) : 0;
iValue = bound( minnum, iValue, maxnum );
@ -919,7 +939,7 @@ compare fields by offsets
assume from and to is valid
=====================
*/
qboolean Delta_CompareField( delta_t *pField, void *from, void *to, double timebase )
static qboolean Delta_CompareField( delta_t *pField, void *from, void *to, double timebase )
{
qboolean bSigned = ( pField->flags & DT_SIGNED ) ? true : false;
float val_a, val_b;
@ -1009,8 +1029,8 @@ qboolean Delta_CompareField( delta_t *pField, void *from, void *to, double timeb
val_b = Q_rint((*(float *)((byte *)to + pField->offset )) * 100.0 );
val_a -= Q_rint(timebase * 100.0);
val_b -= Q_rint(timebase * 100.0);
fromF = *((int *)&val_a);
toF = *((int *)&val_b);
fromF = FloatAsInt( val_a );
toF = FloatAsInt( val_b );
}
else if( pField->flags & DT_TIMEWINDOW_BIG )
{
@ -1030,8 +1050,8 @@ qboolean Delta_CompareField( delta_t *pField, void *from, void *to, double timeb
val_b = timebase - val_b;
}
fromF = *((int *)&val_a);
toF = *((int *)&val_b);
fromF = FloatAsInt( val_a );
toF = FloatAsInt( val_b );
}
else if( pField->flags & DT_STRING )
{
@ -1111,7 +1131,7 @@ write fields by offsets
assume from and to is valid
=====================
*/
qboolean Delta_WriteField( sizebuf_t *msg, delta_t *pField, void *from, void *to, double timebase )
static qboolean Delta_WriteField( sizebuf_t *msg, delta_t *pField, void *from, void *to, double timebase )
{
qboolean bSigned = ( pField->flags & DT_SIGNED ) ? true : false;
float flValue, flAngle;
@ -1259,7 +1279,7 @@ read fields by offsets
assume 'from' and 'to' is valid
=====================
*/
qboolean Delta_ReadField( sizebuf_t *msg, delta_t *pField, void *from, void *to, double timebase )
static qboolean Delta_ReadField( sizebuf_t *msg, delta_t *pField, void *from, void *to, double timebase )
{
qboolean bSigned = ( pField->flags & DT_SIGNED ) ? true : false;
float flValue, flAngle, flTime;

View File

@ -18,26 +18,6 @@ GNU General Public License for more details.
#include "eiface.h"
#define DT_BYTE BIT( 0 ) // A byte
#define DT_SHORT BIT( 1 ) // 2 byte field
#define DT_FLOAT BIT( 2 ) // A floating point field
#define DT_INTEGER BIT( 3 ) // 4 byte integer
#define DT_ANGLE BIT( 4 ) // A floating point angle ( will get masked correctly )
#define DT_TIMEWINDOW_8 BIT( 5 ) // A floating point timestamp, relative to sv.time
#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 NUM_FIELDS( x ) ((sizeof( x ) / sizeof( x[0] )) - 1)
// helper macroses
#define ENTS_DEF( x ) #x, offsetof( entity_state_t, x ), sizeof( ((entity_state_t *)0)->x )
#define UCMD_DEF( x ) #x, offsetof( usercmd_t, x ), sizeof( ((usercmd_t *)0)->x )
#define EVNT_DEF( x ) #x, offsetof( event_args_t, x ), sizeof( ((event_args_t *)0)->x )
#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 )
enum
{
CUSTOM_NONE = 0,
@ -97,7 +77,6 @@ typedef struct
void Delta_Init( void );
void Delta_InitClient( void );
void Delta_Shutdown( void );
void Delta_InitFields( void );
int Delta_NumTables( void );
delta_info_t *Delta_FindStructByIndex( int index );
void Delta_AddEncoder( char *name, pfnDeltaEncode encodeFunc );

View File

@ -25,6 +25,10 @@ GNU General Public License for more details.
#else
#include "platform/posix/net.h"
#endif
#if XASH_PSVITA
#include "platform/psvita/net_psvita.h"
static const struct in6_addr in6addr_any;
#endif
#define NET_USE_FRAGMENTS
@ -394,7 +398,7 @@ void *NET_ThreadStart( void *unused )
#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 create_thread( pfn ) ( nsthread.thread = CreateThread( NULL, 0, pfn, NULL, 0, NULL ))
#define mutex_t CRITICAL_SECTION
#define thread_t HANDLE
DWORD WINAPI NET_ThreadStart( LPVOID unused )
@ -473,7 +477,7 @@ idnewt:28000
192.246.40.70:28000
=============
*/
static int NET_StringToSockaddr( const char *s, struct sockaddr_storage *sadr, qboolean nonblocking, int family )
static net_gai_state_t NET_StringToSockaddr( const char *s, struct sockaddr_storage *sadr, qboolean nonblocking, int family )
{
int ret = 0, port;
char *colon;
@ -482,7 +486,7 @@ static int NET_StringToSockaddr( const char *s, struct sockaddr_storage *sadr, q
struct sockaddr_storage temp;
if( !net.initialized )
return false;
return NET_EAI_NONAME;
memset( sadr, 0, sizeof( *sadr ));
@ -493,7 +497,7 @@ static int NET_StringToSockaddr( const char *s, struct sockaddr_storage *sadr, q
((struct sockaddr_in6 *)sadr)->sin6_port = htons((short)port);
memcpy(((struct sockaddr_in6 *)sadr)->sin6_addr.s6_addr, ip6, sizeof( struct in6_addr ));
return true;
return NET_EAI_OK;
}
Q_strncpy( copy, s, sizeof( copy ));
@ -526,14 +530,14 @@ static int NET_StringToSockaddr( const char *s, struct sockaddr_storage *sadr, q
if( nsthread.busy )
{
mutex_unlock( &nsthread.mutexres );
return 2;
return NET_EAI_AGAIN;
}
if( !Q_strcmp( copy, nsthread.hostname ))
{
ret = nsthread.result;
nsthread.hostname[0] = 0;
nsthread.hostname[0] = '\0';
nsthread.family = AF_UNSPEC;
temp = nsthread.addr;
memset( &nsthread.addr, 0, sizeof( nsthread.addr ));
@ -550,11 +554,11 @@ static int NET_StringToSockaddr( const char *s, struct sockaddr_storage *sadr, q
if( create_thread( NET_ThreadStart ))
{
asyncfailed = false;
return 2;
return NET_EAI_AGAIN;
}
else // failed to create thread
{
Con_Reportf( S_ERROR "NET_StringToSockaddr: failed to create thread!\n");
Con_Reportf( S_ERROR "NET_StringToSockaddr: failed to create thread!\n");
nsthread.busy = false;
}
}
@ -573,7 +577,8 @@ static int NET_StringToSockaddr( const char *s, struct sockaddr_storage *sadr, q
if( family == AF_INET6 )
sadr->ss_family = AF_INET6;
else sadr->ss_family = AF_INET;
return 0;
return NET_EAI_NONAME;
}
sadr->ss_family = temp.ss_family;
@ -591,7 +596,7 @@ static int NET_StringToSockaddr( const char *s, struct sockaddr_storage *sadr, q
}
}
return 1;
return NET_EAI_OK;
}
/*
@ -727,7 +732,8 @@ const char *NET_AdrToString( const netadr_t a )
return s;
}
Q_sprintf( s, "%i.%i.%i.%i:%i", a.ip[0], a.ip[1], a.ip[2], a.ip[3], ntohs( a.port ));
Q_snprintf( s, sizeof( s ),
"%i.%i.%i.%i:%i", a.ip[0], a.ip[1], a.ip[2], a.ip[3], ntohs( a.port ));
return s;
}
@ -753,7 +759,8 @@ const char *NET_BaseAdrToString( const netadr_t a )
return s;
}
Q_sprintf( s, "%i.%i.%i.%i", a.ip[0], a.ip[1], a.ip[2], a.ip[3] );
Q_snprintf( s, sizeof( s ),
"%i.%i.%i.%i", a.ip[0], a.ip[1], a.ip[2], a.ip[3] );
return s;
}
@ -1037,10 +1044,9 @@ qboolean NET_StringToAdrEx( const char *string, netadr_t *adr, int family )
return true;
}
if( !NET_StringToSockaddr( string, &s, false, family ))
if( NET_StringToSockaddr( string, &s, false, family ) != NET_EAI_OK )
return false;
NET_SockadrToNetadr( &s, adr );
return true;
}
@ -1050,13 +1056,13 @@ qboolean NET_StringToAdr( const char *string, netadr_t *adr )
return NET_StringToAdrEx( string, adr, AF_UNSPEC );
}
int NET_StringToAdrNB( const char *string, netadr_t *adr )
net_gai_state_t NET_StringToAdrNB( const char *string, netadr_t *adr )
{
struct sockaddr_storage s;
int res;
net_gai_state_t res;
memset( adr, 0, sizeof( netadr_t ));
if( !Q_stricmp( string, "localhost" ) || !Q_stricmp( string, "loopback" ))
if( !Q_stricmp( string, "localhost" ) || !Q_stricmp( string, "loopback" ))
{
adr->type = NA_LOOPBACK;
return true;
@ -1064,12 +1070,10 @@ int NET_StringToAdrNB( const char *string, netadr_t *adr )
res = NET_StringToSockaddr( string, &s, true, AF_UNSPEC );
if( res == 0 || res == 2 )
return res;
if( res == NET_EAI_OK )
NET_SockadrToNetadr( &s, adr );
NET_SockadrToNetadr( &s, adr );
return true;
return res;
}
/*
@ -1679,68 +1683,6 @@ void NET_SendPacket( netsrc_t sock, size_t length, const void *data, netadr_t to
NET_SendPacketEx( sock, length, data, to, 0 );
}
/*
====================
NET_BufferToBufferCompress
generic fast compression
====================
*/
qboolean NET_BufferToBufferCompress( byte *dest, uint *destLen, byte *source, uint sourceLen )
{
uint uCompressedLen = 0;
byte *pbOut = NULL;
memcpy( dest, source, sourceLen );
pbOut = LZSS_Compress( source, sourceLen, &uCompressedLen );
if( pbOut && uCompressedLen > 0 && uCompressedLen <= *destLen )
{
memcpy( dest, pbOut, uCompressedLen );
*destLen = uCompressedLen;
free( pbOut );
return true;
}
else
{
if( pbOut ) free( pbOut );
memcpy( dest, source, sourceLen );
*destLen = sourceLen;
return false;
}
}
/*
====================
NET_BufferToBufferDecompress
generic fast decompression
====================
*/
qboolean NET_BufferToBufferDecompress( byte *dest, uint *destLen, byte *source, uint sourceLen )
{
if( LZSS_IsCompressed( source ))
{
uint uDecompressedLen = LZSS_GetActualSize( source );
if( uDecompressedLen <= *destLen )
{
*destLen = LZSS_Decompress( source, dest );
}
else
{
return false;
}
}
else
{
memcpy( dest, source, sourceLen );
*destLen = sourceLen;
}
return true;
}
/*
====================
NET_IPSocket
@ -2040,11 +1982,11 @@ void NET_Config( qboolean multiplayer, qboolean changeport )
nov6 = net.allow_ip6 && NET_IsSocketError( net.ip6_sockets[NS_SERVER] );
if( nov4 && nov6 )
Host_Error( "Couldn't allocate IPv4 and IPv6 server ports." );
Host_Error( "Couldn't allocate IPv4 and IPv6 server ports.\n" );
else if( nov4 && !nov6 )
Con_Printf( S_ERROR "Couldn't allocate IPv4 server port" );
Con_Printf( S_ERROR "Couldn't allocate IPv4 server port\n" );
else if( !nov4 && nov6 )
Con_Printf( S_ERROR "Couldn't allocate IPv6 server_port" );
Con_Printf( S_ERROR "Couldn't allocate IPv6 server_port\n" );
}
// get our local address, if possible
@ -2162,9 +2104,9 @@ void NET_Init( void )
net_address = Cvar_Get( "net_address", "0", FCVAR_PRIVILEGED|FCVAR_READ_ONLY, "contain local address of current client" );
net_ipname = Cvar_Get( "ip", "localhost", FCVAR_PRIVILEGED, "network ip address" );
net_iphostport = Cvar_Get( "ip_hostport", "0", FCVAR_READ_ONLY, "network ip host port" );
net_hostport = Cvar_Get( "hostport", va( "%i", PORT_SERVER ), FCVAR_READ_ONLY, "network default host port" );
net_hostport = Cvar_Getf( "hostport", FCVAR_READ_ONLY, "network default host port", "%i", PORT_SERVER );
net_ipclientport = Cvar_Get( "ip_clientport", "0", FCVAR_READ_ONLY, "network ip client port" );
net_clientport = Cvar_Get( "clientport", va( "%i", PORT_CLIENT ), FCVAR_READ_ONLY, "network default client port" );
net_clientport = Cvar_Getf( "clientport", FCVAR_READ_ONLY, "network default client port", "%i", PORT_CLIENT );
net_fakelag = Cvar_Get( "fakelag", "0", FCVAR_PRIVILEGED, "lag all incoming network data (including loopback) by xxx ms." );
net_fakeloss = Cvar_Get( "fakeloss", "0", FCVAR_PRIVILEGED, "act like we dropped the packet this % of the time." );
@ -2574,7 +2516,6 @@ void HTTP_Run( void )
for( curfile = http.first_file; curfile; curfile = curfile->next )
{
int res;
struct sockaddr_storage addr;
if( curfile->state == HTTP_FREE )
@ -2635,18 +2576,23 @@ void HTTP_Run( void )
if( curfile->state < HTTP_NS_RESOLVED )
{
net_gai_state_t res;
char hostport[MAX_VA_STRING];
if( fResolving )
continue;
res = NET_StringToSockaddr( va( "%s:%d", curfile->server->host, curfile->server->port ), &addr, true, AF_INET );
Q_snprintf( hostport, sizeof( hostport ), "%s:%d", curfile->server->host, curfile->server->port );
if( res == 2 )
res = NET_StringToSockaddr( hostport, &addr, true, AF_INET );
if( res == NET_EAI_AGAIN )
{
fResolving = true;
continue;
}
if( !res )
if( res == NET_EAI_NONAME )
{
Con_Printf( S_ERROR "failed to resolve server address for %s!\n", curfile->server->host );
HTTP_FreeFile( curfile, true ); // Cannot connect
@ -2657,7 +2603,7 @@ void HTTP_Run( void )
if( curfile->state < HTTP_CONNECTED ) // Connection not enstabilished
{
res = connect( curfile->socket, (struct sockaddr*)&addr, NET_SockAddrLen( &addr ) );
int res = connect( curfile->socket, (struct sockaddr*)&addr, NET_SockAddrLen( &addr ) );
if( res )
{
@ -2676,11 +2622,23 @@ void HTTP_Run( void )
if( curfile->state < HTTP_REQUEST ) // Request not formatted
{
string useragent;
if( !COM_CheckStringEmpty( http_useragent->string ) || !Q_strcmp( http_useragent->string, "xash3d" ))
{
Q_snprintf( useragent, sizeof( useragent ), "%s/%s (%s-%s; build %d; %s)",
XASH_ENGINE_NAME, XASH_VERSION, Q_buildos( ), Q_buildarch( ), Q_buildnum( ), Q_buildcommit( ));
}
else
{
Q_strncpy( useragent, http_useragent->string, sizeof( useragent ));
}
curfile->query_length = Q_snprintf( curfile->buf, sizeof( curfile->buf ),
"GET %s%s HTTP/1.0\r\n"
"Host: %s\r\n"
"User-Agent: %s\r\n\r\n", curfile->server->path,
curfile->path, curfile->server->host, http_useragent->string );
curfile->path, curfile->server->host, useragent );
curfile->header_size = 0;
curfile->bytes_sent = 0;
curfile->state = HTTP_REQUEST;
@ -2692,8 +2650,7 @@ void HTTP_Run( void )
while( curfile->bytes_sent < curfile->query_length )
{
res = send( curfile->socket, curfile->buf + curfile->bytes_sent, curfile->query_length - curfile->bytes_sent, 0 );
int res = send( curfile->socket, curfile->buf + curfile->bytes_sent, curfile->query_length - curfile->bytes_sent, 0 );
if( res < 0 )
{
@ -3023,16 +2980,16 @@ void HTTP_Init( void )
http.first_file = http.last_file = NULL;
Cmd_AddRestrictedCommand("http_download", &HTTP_Download_f, "add file to download queue");
Cmd_AddRestrictedCommand("http_skip", &HTTP_Skip_f, "skip current download server");
Cmd_AddRestrictedCommand("http_cancel", &HTTP_Cancel_f, "cancel current download");
Cmd_AddRestrictedCommand("http_clear", &HTTP_Clear_f, "cancel all downloads");
Cmd_AddCommand("http_list", &HTTP_List_f, "list all queued downloads");
Cmd_AddCommand("http_addcustomserver", &HTTP_AddCustomServer_f, "add custom fastdl server");
http_useragent = Cvar_Get( "http_useragent", "xash3d", FCVAR_ARCHIVE, "User-Agent string" );
http_autoremove = Cvar_Get( "http_autoremove", "1", FCVAR_ARCHIVE, "remove broken files" );
http_timeout = Cvar_Get( "http_timeout", "45", FCVAR_ARCHIVE, "timeout for http downloader" );
http_maxconnections = Cvar_Get( "http_maxconnections", "4", FCVAR_ARCHIVE, "maximum http connection number" );
Cmd_AddRestrictedCommand( "http_download", HTTP_Download_f, "add file to download queue" );
Cmd_AddRestrictedCommand( "http_skip", HTTP_Skip_f, "skip current download server" );
Cmd_AddRestrictedCommand( "http_cancel", HTTP_Cancel_f, "cancel current download" );
Cmd_AddRestrictedCommand( "http_clear", HTTP_Clear_f, "cancel all downloads" );
Cmd_AddRestrictedCommand( "http_list", HTTP_List_f, "list all queued downloads" );
Cmd_AddCommand( "http_addcustomserver", HTTP_AddCustomServer_f, "add custom fastdl server");
http_useragent = Cvar_Get( "http_useragent", "", FCVAR_ARCHIVE | FCVAR_PRIVILEGED, "User-Agent string" );
http_autoremove = Cvar_Get( "http_autoremove", "1", FCVAR_ARCHIVE | FCVAR_PRIVILEGED, "remove broken files" );
http_timeout = Cvar_Get( "http_timeout", "45", FCVAR_ARCHIVE | FCVAR_PRIVILEGED, "timeout for http downloader" );
http_maxconnections = Cvar_Get( "http_maxconnections", "4", FCVAR_ARCHIVE | FCVAR_PRIVILEGED, "maximum http connection number" );
// Read servers from fastdl.txt
line = serverfile = (char *)FS_LoadFile( "fastdl.txt", 0, false );

View File

@ -23,6 +23,13 @@ typedef enum
NS_COUNT
} netsrc_t;
typedef enum
{
NET_EAI_NONAME = 0,
NET_EAI_OK = 1,
NET_EAI_AGAIN = 2
} net_gai_state_t;
// Max length of unreliable message
#define MAX_DATAGRAM 16384
@ -59,14 +66,12 @@ 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 );
int NET_StringToAdrNB( const char *string, netadr_t *adr );
net_gai_state_t NET_StringToAdrNB( const char *string, netadr_t *adr );
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 );
qboolean NET_CompareAdrByMask( const netadr_t a, const netadr_t b, uint prefixlen );
qboolean NET_GetPacket( netsrc_t sock, netadr_t *from, byte *data, size_t *length );
qboolean NET_BufferToBufferCompress( byte *dest, uint *destLen, byte *source, uint sourceLen );
qboolean NET_BufferToBufferDecompress( byte *dest, uint *destLen, byte *source, uint sourceLen );
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 );
@ -82,6 +87,7 @@ void HTTP_AddCustomServer( const char *url );
void HTTP_AddDownload( const char *path, int size, qboolean process );
void HTTP_ClearCustomServers( void );
void HTTP_Shutdown( void );
void HTTP_ResetProcessState( void );
void HTTP_Init( void );
void HTTP_Run( void );

View File

@ -294,7 +294,6 @@ qboolean Netchan_CopyNormalFragments( netchan_t *chan, sizebuf_t *msg, size_t *l
qboolean Netchan_CopyFileFragments( netchan_t *chan, sizebuf_t *msg );
void Netchan_CreateFragments( netchan_t *chan, sizebuf_t *msg );
int Netchan_CreateFileFragments( netchan_t *chan, const char *filename );
void Netchan_Transmit( netchan_t *chan, int lengthInBytes, byte *data );
void Netchan_TransmitBits( netchan_t *chan, int lengthInBits, byte *data );
void Netchan_OutOfBand( int net_socket, netadr_t adr, int length, byte *data );
void Netchan_OutOfBandPrint( int net_socket, netadr_t adr, const char *format, ... ) _format( 3 );

View File

@ -128,7 +128,7 @@ GNU General Public License for more details.
#define MAX_USER_MESSAGES 197 // another 58 messages reserved for engine routines
#define MAX_DLIGHTS 32 // dynamic lights (rendered per one frame)
#define MAX_ELIGHTS 64 // entity only point lights
#define MAX_LIGHTSTYLES 64 // original quake limit
#define MAX_LIGHTSTYLES 256 // a1ba: increased from 64 to 256, protocol limit
#define MAX_RENDER_DECALS 4096 // max rendering decals per a level
// sound proto

View File

@ -62,7 +62,7 @@ Sequence_GetCommandEnumForName
=============
*/
sequenceCommandEnum_e Sequence_GetCommandEnumForName( const char *commandName, sequenceCommandType_e type )
static sequenceCommandEnum_e Sequence_GetCommandEnumForName( const char *commandName, sequenceCommandType_e type )
{
int i;
@ -82,7 +82,7 @@ Sequence_ResetDefaults
=============
*/
void Sequence_ResetDefaults( sequenceCommandLine_s *destination, sequenceCommandLine_s *source )
static void Sequence_ResetDefaults( sequenceCommandLine_s *destination, sequenceCommandLine_s *source )
{
if( !source )
{
@ -131,7 +131,7 @@ Sequence_WriteDefaults
=============
*/
void Sequence_WriteDefaults( sequenceCommandLine_s *source, sequenceCommandLine_s *destination )
static void Sequence_WriteDefaults( sequenceCommandLine_s *source, sequenceCommandLine_s *destination )
{
if( !destination )
Con_Reportf( S_ERROR "Attempt to bake defaults into a non-existant command." );
@ -210,7 +210,7 @@ Sequence_BakeDefaults
=============
*/
void Sequence_BakeDefaults( sequenceCommandLine_s *destination, sequenceCommandLine_s *source )
static void Sequence_BakeDefaults( sequenceCommandLine_s *destination, sequenceCommandLine_s *source )
{
char *saveName, *saveMessage;
@ -243,7 +243,7 @@ Sequence_SkipWhitespace
=============
*/
qboolean Sequence_SkipWhitespace( void )
static qboolean Sequence_SkipWhitespace( void )
{
qboolean newLine = false;
@ -267,7 +267,7 @@ Sequence_IsNameValueChar
=============
*/
qboolean Sequence_IsNameValueChar( char ch )
static qboolean Sequence_IsNameValueChar( char ch )
{
if( isalnum( ch ) )
return true;
@ -291,7 +291,7 @@ Sequence_IsSymbol
=============
*/
qboolean Sequence_IsSymbol( char ch )
static qboolean Sequence_IsSymbol( char ch )
{
switch( ch )
{
@ -316,7 +316,7 @@ Sequence_GetNameValueString
=============
*/
size_t Sequence_GetNameValueString( char *token, size_t len )
static size_t Sequence_GetNameValueString( char *token, size_t len )
{
char *p;
@ -346,7 +346,7 @@ Sequence_GetSymbol
=============
*/
char Sequence_GetSymbol( void )
static char Sequence_GetSymbol( void )
{
char ch;
@ -366,7 +366,7 @@ Sequence_ValidateNameValueString
=============
*/
void Sequence_ValidateNameValueString( char *token )
static void Sequence_ValidateNameValueString( char *token )
{
char *scan;
@ -383,7 +383,7 @@ Sequence_GetToken
=============
*/
size_t Sequence_GetToken( char *token, size_t size )
static size_t Sequence_GetToken( char *token, size_t size )
{
Sequence_SkipWhitespace( );
@ -408,7 +408,7 @@ Sequence_GetLine
=============
*/
size_t Sequence_GetLine( char *line, int lineMaxLen )
static size_t Sequence_GetLine( char *line, int lineMaxLen )
{
int lineLen;
char *read;
@ -439,7 +439,7 @@ Sequence_StripComments
=============
*/
void Sequence_StripComments( char *buffer, int *pBufSize )
static void Sequence_StripComments( char *buffer, int *pBufSize )
{
char *eof = buffer + *pBufSize;
char *read = buffer;
@ -506,7 +506,7 @@ Sequence_ReadInt
=============
*/
int Sequence_ReadInt( void )
static int Sequence_ReadInt( void )
{
char str[MAX_STRING];
@ -522,7 +522,7 @@ Sequence_ReadFloat
=============
*/
float Sequence_ReadFloat( void )
static float Sequence_ReadFloat( void )
{
char str[MAX_STRING];
@ -538,7 +538,7 @@ Sequence_ReadFloat
=============
*/
void Sequence_ReadString( char **dest, char *string, size_t len )
static void Sequence_ReadString( char **dest, char *string, size_t len )
{
Sequence_SkipWhitespace( );
Sequence_GetNameValueString( string, len );
@ -552,7 +552,7 @@ Sequence_ReadQuotedString
=============
*/
void Sequence_ReadQuotedString( char **dest, char *str, size_t len )
static void Sequence_ReadQuotedString( char **dest, char *str, size_t len )
{
char *write, ch;
@ -585,7 +585,7 @@ Sequence_ConfirmCarriageReturnOrSymbol
=============
*/
qboolean Sequence_ConfirmCarriageReturnOrSymbol( char symbol )
static qboolean Sequence_ConfirmCarriageReturnOrSymbol( char symbol )
{
if( Sequence_SkipWhitespace( ) )
return true;
@ -599,7 +599,7 @@ Sequence_IsCommandAModifier
=============
*/
qboolean Sequence_IsCommandAModifier( sequenceCommandEnum_e commandEnum )
static qboolean Sequence_IsCommandAModifier( sequenceCommandEnum_e commandEnum )
{
int i;
@ -619,7 +619,7 @@ Sequence_ReadCommandData
=============
*/
void Sequence_ReadCommandData( sequenceCommandEnum_e commandEnum, sequenceCommandLine_s *defaults )
static void Sequence_ReadCommandData( sequenceCommandEnum_e commandEnum, sequenceCommandLine_s *defaults )
{
char temp[1024];
@ -722,7 +722,7 @@ Sequence_ParseModifier
=============
*/
char Sequence_ParseModifier( sequenceCommandLine_s *defaults )
static char Sequence_ParseModifier( sequenceCommandLine_s *defaults )
{
char modifierName[MAX_STRING];
char delimiter;
@ -756,7 +756,7 @@ Sequence_AddCommandLineToEntry
=============
*/
void Sequence_AddCommandLineToEntry( sequenceCommandLine_s *commandLine, sequenceEntry_s *entry )
static void Sequence_AddCommandLineToEntry( sequenceCommandLine_s *commandLine, sequenceEntry_s *entry )
{
sequenceCommandLine_s *scan;
@ -776,7 +776,7 @@ Sequence_ParseModifierLine
=============
*/
char Sequence_ParseModifierLine( sequenceEntry_s *entry, sequenceCommandType_e modifierType )
static char Sequence_ParseModifierLine( sequenceEntry_s *entry, sequenceCommandType_e modifierType )
{
sequenceCommandLine_s *newCommandLine;
char delimiter = ',';
@ -808,7 +808,7 @@ Sequence_ParseCommand
=============
*/
char Sequence_ParseCommand( sequenceCommandLine_s *newCommandLine )
static char Sequence_ParseCommand( sequenceCommandLine_s *newCommandLine )
{
char commandName[MAX_STRING], ch;
sequenceCommandEnum_e commandEnum;
@ -847,7 +847,7 @@ Sequence_ParseCommandLine
=============
*/
char Sequence_ParseCommandLine( sequenceEntry_s *entry )
static char Sequence_ParseCommandLine( sequenceEntry_s *entry )
{
char symbol;
sequenceCommandLine_s *newCommandLine;
@ -874,7 +874,7 @@ Sequence_ParseMacro
=============
*/
char Sequence_ParseMacro( sequenceEntry_s *entry )
static char Sequence_ParseMacro( sequenceEntry_s *entry )
{
char symbol;
sequenceCommandLine_s *newCommandLine;
@ -902,7 +902,7 @@ Sequence_ParseLine
=============
*/
char Sequence_ParseLine( char start, sequenceEntry_s *entry )
static char Sequence_ParseLine( char start, sequenceEntry_s *entry )
{
char end = '\0';
@ -933,7 +933,7 @@ Sequence_CalcEntryDuration
=============
*/
float Sequence_CalcEntryDuration( sequenceEntry_s *entry )
static float Sequence_CalcEntryDuration( sequenceEntry_s *entry )
{
float duration;
sequenceCommandLine_s *cmd;
@ -952,7 +952,7 @@ Sequence_DoesEntryContainInfiniteLoop
=============
*/
qboolean Sequence_DoesEntryContainInfiniteLoop( sequenceEntry_s *entry )
static qboolean Sequence_DoesEntryContainInfiniteLoop( sequenceEntry_s *entry )
{
sequenceCommandLine_s *cmd;
@ -971,7 +971,7 @@ Sequence_IsEntrySafe
=============
*/
qboolean Sequence_IsEntrySafe( sequenceEntry_s *entry )
static qboolean Sequence_IsEntrySafe( sequenceEntry_s *entry )
{
float duration;
sequenceCommandLine_s *cmd;
@ -998,7 +998,7 @@ Sequence_CreateDefaultsCommand
=============
*/
void Sequence_CreateDefaultsCommand( sequenceEntry_s *entry )
static void Sequence_CreateDefaultsCommand( sequenceEntry_s *entry )
{
sequenceCommandLine_s *cmd;
@ -1026,7 +1026,7 @@ Sequence_ParseEntry
=============
*/
char Sequence_ParseEntry( void )
static char Sequence_ParseEntry( void )
{
char symbol;
char token[MAX_STRING];
@ -1068,7 +1068,7 @@ Sequence_FindSentenceGroup
=============
*/
sentenceGroupEntry_s *Sequence_FindSentenceGroup( const char *groupName )
static sentenceGroupEntry_s *Sequence_FindSentenceGroup( const char *groupName )
{
sentenceGroupEntry_s *groupEntry;
@ -1152,7 +1152,7 @@ Sequence_AddSentenceGroup
=============
*/
sentenceGroupEntry_s *Sequence_AddSentenceGroup( char *groupName )
static sentenceGroupEntry_s *Sequence_AddSentenceGroup( char *groupName )
{
sentenceGroupEntry_s *entry, *last;
@ -1181,7 +1181,7 @@ Sequence_AddSentenceToGroup
=============
*/
void Sequence_AddSentenceToGroup( char *groupName, char *data )
static void Sequence_AddSentenceToGroup( char *groupName, char *data )
{
sentenceEntry_s *entry, *last;
sentenceGroupEntry_s *group;
@ -1223,7 +1223,7 @@ Sequence_ParseSentenceLine
=============
*/
qboolean Sequence_ParseSentenceLine( void )
static qboolean Sequence_ParseSentenceLine( void )
{
char data[1024];
char fullgroup[64];
@ -1265,7 +1265,7 @@ Sequence_ParseSentenceBlock
==============
*/
char Sequence_ParseSentenceBlock( void )
static char Sequence_ParseSentenceBlock( void )
{
qboolean end = false;
char ch = Sequence_GetSymbol( );
@ -1286,7 +1286,7 @@ Sequence_ParseGlobalDataBlock
==============
*/
char Sequence_ParseGlobalDataBlock( void )
static char Sequence_ParseGlobalDataBlock( void )
{
char token[MAX_STRING];
@ -1304,7 +1304,7 @@ Sequence_GetEntryForName
==============
*/
sequenceEntry_s *Sequence_GetEntryForName( const char *entryName )
static sequenceEntry_s *Sequence_GetEntryForName( const char *entryName )
{
sequenceEntry_s *scan;
@ -1323,7 +1323,7 @@ Sequence_CopyCommand
==============
*/
sequenceCommandLine_s *Sequence_CopyCommand( sequenceCommandLine_s *commandOrig )
static sequenceCommandLine_s *Sequence_CopyCommand( sequenceCommandLine_s *commandOrig )
{
sequenceCommandLine_s *commandCopy;
@ -1354,7 +1354,7 @@ Sequence_CopyCommandList
==============
*/
sequenceCommandLine_s *Sequence_CopyCommandList( sequenceCommandLine_s *list )
static sequenceCommandLine_s *Sequence_CopyCommandList( sequenceCommandLine_s *list )
{
sequenceCommandLine_s *scan, *copy, *new, *prev;
@ -1389,7 +1389,7 @@ Sequence_ExpandGosubsForEntry
==============
*/
qboolean Sequence_ExpandGosubsForEntry( sequenceEntry_s *entry )
static qboolean Sequence_ExpandGosubsForEntry( sequenceEntry_s *entry )
{
sequenceCommandLine_s *cmd, *copyList, *scan;
sequenceEntry_s *gosubEntry;
@ -1437,7 +1437,7 @@ Sequence_ExpandAllGosubs
==============
*/
void Sequence_ExpandAllGosubs( void )
static void Sequence_ExpandAllGosubs( void )
{
sequenceEntry_s *scan;
qboolean isComplete = true;
@ -1457,7 +1457,7 @@ Sequence_FlattenEntry
==============
*/
void Sequence_FlattenEntry( sequenceEntry_s *entry )
static void Sequence_FlattenEntry( sequenceEntry_s *entry )
{
sequenceCommandLine_s *cmd, *last = NULL;
@ -1491,7 +1491,7 @@ Sequence_FlattenAllEntries
==============
*/
void Sequence_FlattenAllEntries( void )
static void Sequence_FlattenAllEntries( void )
{
sequenceEntry_s *entry;
@ -1551,12 +1551,12 @@ Sequence_ParseFile
==============
*/
void Sequence_ParseFile( const char *fileName, qboolean isGlobal )
static void Sequence_ParseFile( const char *fileName, qboolean isGlobal )
{
byte *buffer;
fs_offset_t bufSize = 0;
Q_strcpy( g_sequenceParseFileName, fileName );
Q_strncpy( g_sequenceParseFileName, fileName, sizeof( g_sequenceParseFileName ));
g_sequenceParseFileIsGlobal = isGlobal;
buffer = FS_LoadFile( va("sequences/%s.seq", fileName ), &bufSize, true );
@ -1608,7 +1608,7 @@ Sequence_FreeCommand
==============
*/
void Sequence_FreeCommand( sequenceCommandLine_s *kill )
static void Sequence_FreeCommand( sequenceCommandLine_s *kill )
{
Z_Free( kill->fireTargetNames );
Z_Free( kill->speakerName );
@ -1625,7 +1625,7 @@ Sequence_FreeEntry
==============
*/
void Sequence_FreeEntry( sequenceEntry_s *kill )
static void Sequence_FreeEntry( sequenceEntry_s *kill )
{
sequenceCommandLine_s *dead;
@ -1647,7 +1647,7 @@ Sequence_FreeSentence
==============
*/
void Sequence_FreeSentence( sentenceEntry_s *sentenceEntry )
static void Sequence_FreeSentence( sentenceEntry_s *sentenceEntry )
{
Z_Free( sentenceEntry->data );
Z_Free( sentenceEntry );
@ -1659,7 +1659,7 @@ Sequence_FreeSentenceGroup
==============
*/
void Sequence_FreeSentenceGroup( sentenceGroupEntry_s *groupEntry )
static void Sequence_FreeSentenceGroup( sentenceGroupEntry_s *groupEntry )
{
Z_Free( groupEntry->groupName );
Z_Free( groupEntry );
@ -1671,7 +1671,7 @@ Sequence_FreeSentenceGroupEntries
==============
*/
void Sequence_FreeSentenceGroupEntries( sentenceGroupEntry_s *groupEntry, qboolean purgeGlobals )
static void Sequence_FreeSentenceGroupEntries( sentenceGroupEntry_s *groupEntry, qboolean purgeGlobals )
{
sentenceEntry_s *sentenceEntry;
sentenceEntry_s *deadSentence;
@ -1711,7 +1711,7 @@ Sequence_PurgeEntries
==============
*/
void Sequence_PurgeEntries( qboolean purgeGlobals )
static void Sequence_PurgeEntries( qboolean purgeGlobals )
{
sequenceEntry_s *scan;
sequenceEntry_s *dead;

View File

@ -90,7 +90,9 @@ wavdata_t *FS_LoadSound( const char *filename, const byte *buffer, size_t size )
{
if( anyformat || !Q_stricmp( ext, format->ext ))
{
Q_sprintf( path, format->formatstring, loadname, "", format->ext );
Q_snprintf( path, sizeof( path ),
format->formatstring, loadname, "", format->ext );
f = FS_LoadFile( path, &filesize, false );
if( f && filesize > 0 )
{
@ -175,7 +177,9 @@ stream_t *FS_OpenStream( const char *filename )
{
if( anyformat || !Q_stricmp( ext, format->ext ))
{
Q_sprintf( path, format->formatstring, loadname, "", format->ext );
Q_snprintf( path, sizeof( path ),
format->formatstring, loadname, "", format->ext );
if(( stream = format->openfunc( path )) != NULL )
{
stream->format = format;
@ -280,7 +284,6 @@ void FS_FreeStream( stream_t *stream )
}
#if XASH_ENGINE_TESTS
#define IMPLEMENT_SOUNDLIB_FUZZ_TARGET( export, target ) \
int EXPORT export( const uint8_t *Data, size_t Size ) \
{ \

View File

@ -16,6 +16,184 @@ GNU General Public License for more details.
#include "soundlib.h"
#include "libmpg/libmpg.h"
#pragma pack( push, 1 )
typedef struct did3v2_header_s
{
char ident[3]; // must be "ID3"
uint8_t major_ver; // must be 4
uint8_t minor_ver; // must be 0
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" );
typedef struct did3v2_extended_header_s
{
uint32_t length;
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" );
typedef struct did3v2_frame_s
{
char frame_id[4];
uint32_t length;
uint8_t flags[2];
} did3v2_frame_t;
STATIC_ASSERT( sizeof( did3v2_frame_t ) == 10,
"invalid did3v2_frame_t size" );
#pragma pack( pop )
typedef enum did3v2_header_flags_e
{
ID3V2_HEADER_UNSYHCHRONIZATION = BIT( 7U ),
ID3V2_HEADER_EXTENDED_HEADER = BIT( 6U ),
ID3V2_HEADER_EXPERIMENTAL = BIT( 5U ),
ID3V2_HEADER_FOOTER_PRESENT = BIT( 4U ),
} did3v2_header_flags_t;
#define CHECK_IDENT( ident, b0, b1, b2 ) ((( ident )[0]) == ( b0 ) && (( ident )[1]) == ( b1 ) && (( ident )[2]) == ( b2 ))
#define CHECK_FRAME_ID( ident, b0, b1, b2, b3 ) ( CHECK_IDENT( ident, b0, b1, b2 ) && (( ident )[3]) == ( b3 ))
static uint32_t Sound_ParseSynchInteger( uint32_t v )
{
uint32_t res = 0;
// read as big endian
res |= (( v >> 24 ) & 0x7f ) << 0;
res |= (( v >> 16 ) & 0x7f ) << 7;
res |= (( v >> 8 ) & 0x7f ) << 14;
res |= (( v >> 0 ) & 0x7f ) << 21;
return res;
}
static void Sound_HandleCustomID3Comment( const char *key, const char *value )
{
if( !Q_strcmp( key, "LOOP_START" ) || !Q_strcmp( key, "LOOPSTART" ))
sound.loopstart = Q_atoi( value );
// unknown comment is not an error
}
static qboolean Sound_ParseID3Frame( const did3v2_frame_t *frame, const byte *buffer, size_t frame_length )
{
if( CHECK_FRAME_ID( frame->frame_id, 'T', 'X', 'X', 'X' ))
{
string key, value;
int32_t key_len, value_len;
if( buffer[0] == 0x00 || buffer[1] == 0x03 )
{
key_len = Q_strncpy( key, &buffer[1], sizeof( key ));
value_len = frame_length - (1 + key_len + 1);
if( value_len <= 0 || value_len >= sizeof( value ))
{
Con_Printf( S_ERROR "Sound_ParseID3Frame: invalid TXXX description, possibly broken file.\n" );
return false;
}
memcpy( value, &buffer[1 + key_len + 1], value_len );
value[value_len + 1] = 0;
Sound_HandleCustomID3Comment( key, value );
}
else
{
if( buffer[0] == 0x01 || buffer[0] == 0x02 ) // UTF-16 with BOM
Con_Printf( S_ERROR "Sound_ParseID3Frame: UTF-16 encoding is unsupported. Use UTF-8 or ISO-8859!\n" );
else
Con_Printf( S_ERROR "Sound_ParseID3Frame: unknown TXXX tag encoding %d, possibly broken file.\n", buffer[0] );
return false;
}
}
return true;
}
static qboolean Sound_ParseID3Tag( const byte *buffer, fs_offset_t filesize )
{
const did3v2_header_t *header = (const did3v2_header_t *)buffer;
const byte *buffer_begin = buffer;
uint32_t tag_length;
if( filesize < sizeof( *header ))
return false;
buffer += sizeof( *header );
// support only id3v2
if( !CHECK_IDENT( header->ident, 'I', 'D', '3' ))
{
// old id3v1 header found
if( CHECK_IDENT( header->ident, 'T', 'A', 'G' ))
Con_Printf( S_ERROR "Sound_ParseID3Tag: ID3v1 is not supported! Convert to ID3v2.4!\n", header->major_ver );
return true; // missing tag header is not an error
}
// support only latest id3 v2.4
if( header->major_ver != 4 || header->minor_ver == 0xff )
{
Con_Printf( S_ERROR "Sound_ParseID3Tag: invalid ID3v2 tag version 2.%d.%d. Convert to ID3v2.4!\n", header->major_ver, header->minor_ver );
return false;
}
tag_length = Sound_ParseSynchInteger( header->length );
if( tag_length > filesize - sizeof( *header ))
{
Con_Printf( S_ERROR "Sound_ParseID3Tag: invalid tag length %u, possibly broken file.\n", tag_length );
return false;
}
// just skip extended header
if( FBitSet( header->flags, ID3V2_HEADER_EXTENDED_HEADER ))
{
const did3v2_extended_header_t *ext_header = (const did3v2_extended_header_t *)buffer;
uint32_t ext_length = Sound_ParseSynchInteger( ext_header->length );
if( ext_length > tag_length )
{
Con_Printf( S_ERROR "Sound_ParseID3Tag: invalid extended header length %u, possibly broken file.\n", ext_length );
return false;
}
buffer += ext_length;
}
while( buffer - buffer_begin < tag_length )
{
const did3v2_frame_t *frame = (const did3v2_frame_t *)buffer;
uint32_t frame_length = Sound_ParseSynchInteger( frame->length );
if( frame_length > tag_length )
{
Con_Printf( S_ERROR "Sound_ParseID3Tag: invalid frame length %u, possibly broken file.\n", frame_length );
return false;
}
buffer += sizeof( *frame );
// parse can fail, but it's ok to continue
Sound_ParseID3Frame( frame, buffer, frame_length );
buffer += frame_length;
}
return true;
}
#if XASH_ENGINE_TESTS
int EXPORT Fuzz_Sound_ParseID3Tag( const uint8_t *Data, size_t Size )
{
memset( &sound, 0, sizeof( sound ));
Sound_ParseID3Tag( Data, Size );
return 0;
}
#endif
/*
=================================================================
@ -59,6 +237,12 @@ qboolean Sound_LoadMPG( const char *name, const byte *buffer, fs_offset_t filesi
padsize = sound.size % FRAME_SIZE;
pos += FRAME_SIZE; // evaluate pos
if( !Sound_ParseID3Tag( buffer, filesize ))
{
Con_DPrintf( S_WARN "Sound_LoadMPG: (%s) failed to extract LOOP_START tag\n", name );
sound.loopstart = -1;
}
if( !sound.size )
{
// bad mpeg file ?

View File

@ -290,3 +290,17 @@ qboolean Sound_Process( wavdata_t **wav, int rate, int width, uint flags )
return false;
}
qboolean Sound_SupportedFileFormat( const char *fileext )
{
const loadwavfmt_t *format;
if( COM_CheckStringEmpty( fileext ))
{
for( format = sound.loadformats; format && format->formatstring; format++ )
{
if( !Q_stricmp( format->ext, fileext ))
return true;
}
}
return false;
}

View File

@ -270,6 +270,14 @@ static void Sys_PrintStdout( const char *logtime, const char *msg )
fprintf( stderr, "%s %s", logtime, buf );
#endif // XASH_NSWITCH && NSWITCH_DEBUG
#if XASH_PSVITA
// spew to stderr only in developer mode
if( host_developer.value )
{
fprintf( stderr, "%s %s", logtime, buf );
}
#endif
#elif !XASH_WIN32 // Wcon does the job
Sys_PrintLogfile( STDOUT_FILENO, logtime, msg, XASH_COLORIZE_CONSOLE );
Sys_FlushStdout();

View File

@ -40,6 +40,10 @@ GNU General Public License for more details.
#include <switch.h>
#endif
#if XASH_PSVITA
#include <vitasdk.h>
#endif
#include "menu_int.h" // _UPDATE_PAGE macro
#include "library.h"
@ -129,6 +133,11 @@ const char *Sys_GetCurrentUser( void )
if( GetUserName( s_userName, &size ))
return s_userName;
#elif XASH_PSVITA
static string username;
sceAppUtilSystemParamGetString( SCE_SYSTEM_PARAM_ID_USERNAME, username, sizeof( username ) - 1 );
if( COM_CheckStringEmpty( username ))
return username;
#elif XASH_POSIX && !XASH_ANDROID && !XASH_NSWITCH
uid_t uid = geteuid();
struct passwd *pw = getpwuid( uid );
@ -613,6 +622,12 @@ qboolean Sys_NewInstance( const char *gamedir )
newargs[i++] = strdup( "-changegame" );
newargs[i] = NULL;
#if XASH_PSVITA
// under normal circumstances it's always going to be the same path
exe = strdup( "app0:/eboot.bin" );
Host_Shutdown( );
sceAppMgrLoadExec( exe, newargs, NULL );
#else
exelen = wai_getExecutablePath( NULL, 0, NULL );
exe = malloc( exelen + 1 );
wai_getExecutablePath( exe, exelen, NULL );
@ -621,6 +636,7 @@ qboolean Sys_NewInstance( const char *gamedir )
Host_Shutdown();
execv( exe, newargs );
#endif
// if execv returned, it's probably an error
printf( "execv failed: %s", strerror( errno ));

View File

@ -169,7 +169,7 @@ int WAI_PREFIX(getModulePath)(char* out, int capacity, int* dirname_length)
return length;
}
#elif defined(__linux__) || defined(__CYGWIN__) || defined(__sun) || defined(WAI_USE_PROC_SELF_EXE)
#elif defined(__linux__) || defined(__CYGWIN__) || defined(__sun) || defined(__serenity__) || defined(WAI_USE_PROC_SELF_EXE)
#include <stdio.h>
#include <stdlib.h>
@ -795,7 +795,7 @@ int WAI_PREFIX(getModulePath)(char* out, int capacity, int* dirname_length)
return length;
}
#elif defined(__sgi) || defined(__SWITCH__)
#elif defined(__sgi) || defined(__SWITCH__) || defined(__vita__)
/*
* These functions are stubbed for now to get the code compiling.

View File

@ -1,6 +1,9 @@
/*
zone.c - zone memory allocation from DarkPlaces
Copyright (C) 1996-1997 Id Software, Inc.
Copyright (C) 2000-2007 DarkPlaces contributors
Copyright (C) 2007 Uncle Mike
Copyright (C) 2015-2023 Xash3D FWGS contributors
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

View File

@ -240,7 +240,7 @@ int Android_GetSelectedPixelFormat( void )
qboolean R_Init_Video( const int type )
{
string safe;
char buf[MAX_VA_STRING];
qboolean retval;
switch( Android_GetSelectedPixelFormat() )
@ -258,14 +258,8 @@ qboolean R_Init_Video( const int type )
if( FS_FileExists( GI->iconpath, true ) )
{
if( host.rodir[0] )
{
Android_SetIcon( va( "%s/%s/%s", host.rodir, GI->gamefolder, GI->iconpath ) );
}
else
{
Android_SetIcon( va( "%s/%s/%s", host.rootdir, GI->gamefolder, GI->iconpath ) );
}
Q_snprintf( buf, sizeof( buf ), "%s/%s/%s", COM_CheckStringEmpty( host.rodir ) ? host.rodir : host.rootdir, GI->gamefolder, GI->iconpath );
Android_SetIcon( buf );
}
Android_SetTitle( GI->title );
@ -280,8 +274,8 @@ qboolean R_Init_Video( const int type )
case REF_GL:
Sys_LoadLibrary( &egl_info );
if( !glw_state.safe && Sys_GetParmFromCmdLine( "-safegl", safe ) )
glw_state.safe = bound( SAFE_NO, Q_atoi( safe ), SAFE_DONTCARE );
if( !glw_state.safe && Sys_GetParmFromCmdLine( "-safegl", buf ) )
glw_state.safe = bound( SAFE_NO, Q_atoi( buf ), SAFE_DONTCARE );
break;
default:

View File

@ -24,14 +24,15 @@ void *EMSCRIPTEN_LoadLibrary( const char *dllname )
void *pHandle = NULL;
#ifdef EMSCRIPTEN_LIB_FS
char path[MAX_SYSPATH];
char path[MAX_SYSPATH], buf[MAX_VA_STRING];
string prefix;
Q_strcpy(prefix, getenv( "LIBRARY_PREFIX" ) );
Q_snprintf( path, MAX_SYSPATH, "%s%s%s", prefix, dllname, getenv( "LIBRARY_SUFFIX" ) );
pHandle = dlopen( path, RTLD_LAZY );
if( !pHandle )
{
COM_PushLibraryError( va("Loading %s:\n", path ) );
Q_snprintf( buf, sizeof( buf ), "Loading %s:\n", path );
COM_PushLibraryError( buf );
COM_PushLibraryError( dlerror() );
}
return pHandle;

View File

@ -13,7 +13,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
*/
#include "platform/platform.h"
#ifdef XASH_USE_EVDEV
#if XASH_USE_EVDEV
#include "common.h"

View File

@ -57,6 +57,14 @@ void NSwitch_Init( void );
void NSwitch_Shutdown( void );
#endif
#if XASH_PSVITA
void PSVita_Init( void );
void PSVita_Shutdown( void );
qboolean PSVita_GetBasePath( char *buf, const size_t buflen );
int PSVita_GetArgv( int in_argc, char **in_argv, char ***out_argv );
void PSVita_InputUpdate( void );
#endif
/*
==============================================================================
@ -141,7 +149,7 @@ qboolean SW_CreateBuffer( int width, int height, uint *stride, uint *bpp, uint *
//
// in_evdev.c
//
#ifdef XASH_USE_EVDEV
#if XASH_USE_EVDEV
void Evdev_SetGrab( qboolean grab );
void Evdev_Shutdown( void );
void Evdev_Init( void );

View File

@ -82,6 +82,7 @@ void *COM_LoadLibrary( const char *dllname, int build_ordinals_table, qboolean d
{
dll_user_t *hInst = NULL;
void *pHandle = NULL;
char buf[MAX_VA_STRING];
COM_ResetLibraryError();
@ -110,7 +111,8 @@ void *COM_LoadLibrary( const char *dllname, int build_ordinals_table, qboolean d
if( pHandle )
return pHandle;
COM_PushLibraryError( va( "Failed to find library %s", dllname ));
Q_snprintf( buf, sizeof( buf ), "Failed to find library %s", dllname );
COM_PushLibraryError( buf );
COM_PushLibraryError( dlerror() );
return NULL;
}
@ -118,7 +120,8 @@ void *COM_LoadLibrary( const char *dllname, int build_ordinals_table, qboolean d
if( hInst->custom_loader )
{
COM_PushLibraryError( va( "Custom library loader is not available. Extract library %s and fix gameinfo.txt!", hInst->fullPath ));
Q_snprintf( buf, sizeof( buf ), "Custom library loader is not available. Extract library %s and fix gameinfo.txt!", hInst->fullPath );
COM_PushLibraryError( buf );
Mem_Free( hInst );
return NULL;
}
@ -128,14 +131,16 @@ void *COM_LoadLibrary( const char *dllname, int build_ordinals_table, qboolean d
{
if( hInst->encrypted )
{
COM_PushLibraryError( va( "Library %s is encrypted. Cannot load", hInst->shortPath ) );
Q_snprintf( buf, sizeof( buf ), "Library %s is encrypted. Cannot load", hInst->shortPath );
COM_PushLibraryError( buf );
Mem_Free( hInst );
return NULL;
}
if( !( hInst->hInstance = Loader_LoadLibrary( hInst->fullPath ) ) )
{
COM_PushLibraryError( va( "Failed to load DLL with DLL loader: %s", hInst->shortPath ) );
Q_snprintf( buf, sizeof( buf ), "Failed to load DLL with DLL loader: %s", hInst->shortPath );
COM_PushLibraryError( buf );
Mem_Free( hInst );
return NULL;
}

View File

@ -17,7 +17,9 @@ GNU General Public License for more details.
#include <sys/types.h>
#include <sys/socket.h>
#if !XASH_PSVITA
#include <sys/ioctl.h>
#endif
#include <sys/select.h>
#include <netinet/in.h>
#include <arpa/inet.h>
@ -79,7 +81,7 @@ static int ioctl_stub( int d, unsigned long r, ... )
return 0;
}
#define ioctlsocket ioctl_stub
#else // XASH_EMSCRIPTEN
#elif !XASH_PSVITA // XASH_EMSCRIPTEN
#define ioctlsocket ioctl
#endif // XASH_EMSCRIPTEN
#define closesocket close

View File

@ -50,11 +50,12 @@ static qboolean Sys_FindExecutable( const char *baseName, char *buf, size_t size
needTrailingSlash = ( envPath[length - 1] == '/' ) ? 0 : 1;
if( length + baseNameLength + needTrailingSlash < size )
{
Q_strncpy( buf, envPath, length + 1 );
if( needTrailingSlash )
Q_strcpy( buf + length, "/" );
Q_strcpy( buf + length + needTrailingSlash, baseName );
buf[length + needTrailingSlash + baseNameLength] = '\0';
string temp;
Q_strncpy( temp, envPath, length + 1 );
Q_snprintf( buf, size, "%s%s%s",
temp, needTrailingSlash ? "/" : "", baseName );
if( access( buf, X_OK ) == 0 )
return true;
}
@ -67,7 +68,7 @@ static qboolean Sys_FindExecutable( const char *baseName, char *buf, size_t size
return false;
}
#if !XASH_ANDROID && !XASH_NSWITCH
#if !XASH_ANDROID && !XASH_NSWITCH && !XASH_PSVITA
void Platform_ShellExecute( const char *path, const char *parms )
{
char xdgOpen[128];

View File

@ -0,0 +1,115 @@
/*
in_psvita.h - psvita-specific input code
Copyright (C) 2021-2023 fgsfds
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.
*/
/*
the SDL fork that we use sometimes fails to call sceImeUpdate,
which leads to input being consumed forever without ever showing the keyboard,
so we just reimplement the whole thing here using SceCommonDialog
*/
#include "platform/platform.h"
#include <vitasdk.h>
#include <SDL.h>
extern int SDL_SendKeyboardText( const char *text );
static qboolean ime_enabled;
static SceWChar16 ime_string[SCE_IME_MAX_TEXT_LENGTH + 1];
/* this is dumb but will probably work fine enough */
static inline void utf2ascii( char *dst, const SceWChar16 *src, unsigned dstsize )
{
if ( !src || !dst || !dstsize )
return;
while ( *src && ( dstsize-- > 0 ) )
*(dst++) = (*(src++)) & 0xFF;
*dst = 0x00;
}
static void IME_Open( void )
{
SceInt32 res;
SceImeDialogParam param;
memset( ime_string, 0, sizeof( ime_string ) );
sceImeDialogParamInit( &param );
param.supportedLanguages = SCE_IME_LANGUAGE_ENGLISH;
param.languagesForced = SCE_TRUE;
param.type = SCE_IME_TYPE_BASIC_LATIN;
param.title = u"Input text";
param.maxTextLength = SCE_IME_MAX_TEXT_LENGTH;
param.initialText = (SceWChar16 *)u"";
param.inputTextBuffer = ime_string;
res = sceImeDialogInit( &param );
if ( res < 0 )
{
Con_Reportf( S_WARN "Could not open IME keyboard: %d\n", res );
}
else
{
ime_enabled = true;
}
}
static void IME_Close( void )
{
if ( ime_enabled )
{
ime_enabled = false;
sceImeDialogTerm( );
}
}
static void IME_Update( void )
{
char ascii_string[SCE_IME_MAX_TEXT_LENGTH + 2] = { 0 };
SceImeDialogResult result;
SceCommonDialogStatus status = sceImeDialogGetStatus( );
if( status == 2 )
{
memset( &result, 0, sizeof( SceImeDialogResult ) );
sceImeDialogGetResult( &result );
if( result.button == SCE_IME_DIALOG_BUTTON_ENTER )
{
utf2ascii( ascii_string, ime_string, SCE_IME_MAX_TEXT_LENGTH );
SDL_SendKeyboardText( ascii_string );
}
IME_Close();
}
}
void Platform_EnableTextInput( qboolean enable )
{
if ( enable )
{
if ( ime_enabled )
IME_Close();
IME_Open();
SDL_EventState( SDL_TEXTINPUT, SDL_ENABLE );
}
else
{
SDL_EventState( SDL_TEXTINPUT, SDL_DISABLE );
IME_Close();
}
}
void PSVita_InputUpdate( void )
{
if ( ime_enabled )
IME_Update();
}

View File

@ -0,0 +1,57 @@
/*
net_psvita.h - psvita network stubs
Copyright (C) 2021-2023 fgsfds
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.
*/
#pragma once
#ifndef NET_PSVITA_H
#define NET_PSVITA_H
#include <vitasdk.h>
/* we're missing IPv6 support; define some trash */
#ifndef IN6_IS_ADDR_V4MAPPED
#define IN6_IS_ADDR_V4MAPPED( p ) ( 0 )
#endif
#ifndef IPPROTO_IPV6
#define IPPROTO_IPV6 41
#endif
#ifndef IPV6_MULTICAST_LOOP
#define IPV6_MULTICAST_LOOP 19
#endif
#ifndef IPV6_V6ONLY
#define IPV6_V6ONLY 26
#endif
#ifndef FIONBIO
#define FIONBIO SO_NONBLOCK
#endif
/* ioctlsocket() is only used to set non-blocking on sockets */
static inline int ioctl_psvita( int fd, int req, unsigned int *arg )
{
if ( req == FIONBIO )
{
return setsockopt( fd, SOL_SOCKET, SO_NONBLOCK, arg, sizeof( *arg ) );
}
return -ENOSYS;
}
#define ioctlsocket ioctl_psvita
#endif // NET_PSVITA_H

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 306 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Some files were not shown because too many files have changed in this diff Show More