mirror of
https://github.com/FWGS/xash3d-fwgs.git
synced 2026-08-05 19:45:05 +08:00
Compare commits
21 Commits
continuous
...
apidocs
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
03a9d08053 | ||
|
|
a75666a3cd | ||
|
|
49426721d8 | ||
|
|
04125284a3 | ||
|
|
1d4f7b2f94 | ||
|
|
38c82a3f76 | ||
|
|
785632a437 | ||
|
|
4be75af214 | ||
|
|
dcdca01e86 | ||
|
|
201d9c8f80 | ||
|
|
69341e36a3 | ||
|
|
3532a77643 | ||
|
|
35dc072b26 | ||
|
|
f92a3695b3 | ||
|
|
a7b776f3b9 | ||
|
|
f2fb668c9e | ||
|
|
90e493fa3a | ||
|
|
692bcc4073 | ||
|
|
823642b10d | ||
|
|
07189ca2f5 | ||
|
|
0d55441830 |
5
Documentation/api/README.md
Normal file
5
Documentation/api/README.md
Normal file
@@ -0,0 +1,5 @@
|
||||
# Welcome to the GoldSource API docs
|
||||
|
||||
This documentation is an attempt on explaining inner workings of Valve's Half-Life (R) engine, also known as GoldSource, from programmer's perspective. A deep knowledge of Quake (NQ, QW and Q2) engines is required.
|
||||
|
||||
Everything discussed here is it's author assumption based on studying Xash3D source code and reverse engineering Half-Life mods. Xash3D API extensions is out of scope of this document and will be explained separately.
|
||||
20
Documentation/api/client/01-init.md
Normal file
20
Documentation/api/client/01-init.md
Normal file
@@ -0,0 +1,20 @@
|
||||
# Initializing client.dll
|
||||
|
||||
`client.dll` has got multiple ways of initialization during it's life but we will go through the simplest and the most common route here.
|
||||
|
||||
Here we expect that reader has knowledge of loading dynamic shared objects on their platform. On Windows it's done through `LoadLibrary`/`GetProcAddress`/`FreeLibrary` functions, on POSIX-complaint systems it's done through `dlopen`/`dlsym`/`dlclose` functions.
|
||||
|
||||
## client.dll lifetime
|
||||
|
||||
`client.dll` is expected to be loaded during client initialization and unloaded on client shutdown. Essentially, in non-dedicated builds, it always exists during the engine lifetime. Judging by the API, it might look like `client.dll` might be safely unloaded and loaded again, for example for implementing classic `Change Game` functionality from WON versions of Half-Life, but in practice it's nearly impossible to do this clean in standard and portable manner. If you want to implement changing games, consider using `execv`-like functions.
|
||||
|
||||
## client.dll exported functions
|
||||
|
||||
The first thing you should do, is to acquire pointers to all exported functions, which you can find in the next chapter. Some of them are optional, and might not present in the `client.dll`, and will be labeled as such.
|
||||
|
||||
## client.dll initialization process
|
||||
|
||||
1. The first function you call is `Initialize` function, which lets `client.dll` to store a copy of an engine API functions.
|
||||
2. Since SDK 2.0, `client.dll` have player movement code in it, which you must initialize through `HUD_PlayerMoveInit` function. `client.dll` might want to override player hulls, which can be grabbed with `HUD_GetHullBounds` function.
|
||||
3. HUD functionality must be started up with `HUD_Init` function and can be de-initialized with `HUD_Shutdown` export function.
|
||||
4. And finally, SDK 2.1 brings studio model renderer, which has separate set of API functions, which must be initialized with `HUD_GetStudioModelInterface` function.
|
||||
286
Documentation/api/client/02-exports.md
Normal file
286
Documentation/api/client/02-exports.md
Normal file
@@ -0,0 +1,286 @@
|
||||
# List of client.dll exported functions
|
||||
|
||||
### `int Initialize( cl_enginefuncs_t *enginefuncs, int version )`
|
||||
|
||||
> [!IMPORTANT]
|
||||
> This function is only called once.
|
||||
|
||||
Called after loading DLL and exports engine API to the `client.dll`.
|
||||
* `enginefuncs` must be set to a pointer to a struct filled with engine function pointers, it will be described in next chapters.
|
||||
* `version` must be always set to `7`. (HLSDK 1.0 uses version `6`, and is binary incompatible with `7`).
|
||||
Return value: `0` on error, otherwise success.
|
||||
|
||||
### `void HUD_PlayerMoveInit( struct playermove_s *ppmove, int server )`
|
||||
|
||||
> [!IMPORTANT]
|
||||
> This function is only called once.
|
||||
|
||||
Called on player movement prediction initialization, before HUD. In GoldSrc, engine only runs prediction loop, the players physics are implemented in `client.dll`.
|
||||
* `ppmove` must be set to a pointer to a client instance of player movement structure, which also exports it's own API and will be discussed in the next chapters.
|
||||
* `server` must be always set to `0` on client side.
|
||||
This function is called only once.
|
||||
|
||||
### `void HUD_Init( void )`
|
||||
|
||||
> [!IMPORTANT]
|
||||
> This function is only called once.
|
||||
|
||||
Called to initialize the HUD. At this moment engine should be ready to register new commands, console variables and user messages. No rendering or loading graphics done at this moment.
|
||||
|
||||
### `int HUD_GetStudioModelInterface( int version, struct r_studio_interface_s **ppinterface, struct engine_studio_api_s *pstudio )`
|
||||
|
||||
> [!IMPORTANT]
|
||||
> This function is only called once.
|
||||
|
||||
This function is called after initializing HUD and exports studio model interface to the `client.dll`.
|
||||
* `version` must be always set to `1`.
|
||||
* `ppinterface` will be set by `client.dll` to a pointer to `r_studio_interface_s` structure.
|
||||
* `pstudio` must be set to a pointer to `engine_studio_api_s` structure. The studio model interface will be discussed in the next chapters.
|
||||
Return value: `0` on error, otherwise success.
|
||||
|
||||
### `void HUD_Shutdown( void )`
|
||||
|
||||
> [!IMPORTANT]
|
||||
> This function is only called once.
|
||||
|
||||
Called at client shutdown.
|
||||
|
||||
### `int HUD_GetHullBounds( int hull, vec3_t mins, vec3_t maxs )`
|
||||
|
||||
> [!IMPORTANT]
|
||||
> This function is only called once.
|
||||
|
||||
Called by the engine after `HUD_PlayerMoveInit` to let `client.dll` override hull bounds used for in player movement prediction.
|
||||
|
||||
* `hull` is the hull index (0: player standing, 1: player crouched, 2: point hull, 3: large hull).
|
||||
* `mins` will contain hull mins.
|
||||
* `maxs` will contain hull maxs.
|
||||
Return value: if 0, don't override this hull and stop reading, non-zero means hull is valid _and_ there is more.
|
||||
|
||||
> [!NOTE]
|
||||
> This function is broken in most implementations. It might return non-zero value, but don't write anything to the `mins` and `maxs` vectors, so be prepared to have some default values.
|
||||
|
||||
### `int HUD_VidInit( void )`
|
||||
|
||||
Called when client receives `svc_serverdata` message. It is called before any parsing of that message is done, thus the state is preserved from the previous connection. It lets `client.dll` to re-initialize graphics, if required. At this point, engine is expected to have video subsystem running, but no rendering is done here.
|
||||
|
||||
### `int HUD_Redraw( float flTime, int intermission )`
|
||||
|
||||
Called each frame to redraw the HUD. Only 2D is drawn here.
|
||||
* `flTime` must be set to `cl.time`, i.e. synchronized with server.
|
||||
* `intermission` must be set to `1` during intermission (set through `svc_intermission` message), otherwise it's set to `0`.
|
||||
Return value: ignored.
|
||||
|
||||
### `void HUD_Reset( void )`
|
||||
|
||||
Called on demo recording or playback start and stop.
|
||||
|
||||
### `int HUD_UpdateClientData( client_data_t *cdata, float flTime )`
|
||||
|
||||
Called each frame after taking input.
|
||||
* `cdata` contains pointer to `client_data_t` structure, populated by engine.
|
||||
* `flTime` must be set to `cl.time`, i.e. synchronized with server.
|
||||
Return value: if non-zero, will override engine viewangles and FOV value.
|
||||
|
||||
### `void HUD_PlayerMove( struct playermove_s *pmove, int server )`
|
||||
|
||||
When prediction is enabled, use this function to run player movement prediction. Note that this correlates to QW/Q2's prediction mechanism. It does not include weapon prediction.
|
||||
|
||||
* `pmove` is a pointer to playermove object
|
||||
* `server` must be always set to `0`
|
||||
|
||||
### `char HUD_PlayerMoveTexture( char *name )`
|
||||
|
||||
Not used in the engine.
|
||||
|
||||
### `int HUD_ConnectionlessPacket( const netadr_t *from, const char *args, char *response_buffer, int *response_buffer_size )`
|
||||
|
||||
Called by the engine on unknown connectionless packets. Lets `client.dll` and `server.dll` have custom query protocol.
|
||||
|
||||
* `from` is set to network address where this packet is coming from.
|
||||
* `args` raw network buffer, minus the connectionless packet header (0xFFFFFFFF).
|
||||
* `response_buffer` set by `client.dll` if there is a response.
|
||||
* `response_buffer_size` is initialized by the engine with buffer maximum size. Set by `client.dll` if there is a response.
|
||||
Return value: non-zero if handled.
|
||||
|
||||
### `void HUD_Frame( double time )`
|
||||
|
||||
Called each frame after sending command to the remote server. No rendering is normally done in this function.
|
||||
|
||||
* `time` is the local delta time between previous and this frame (i.e. `host.frametime`)
|
||||
|
||||
### `void HUD_PostRunCmd( struct local_state_s *from, struct local_state_s *to, usercmd_t *cmd, int runfuncs, double time, unsigned int random_seed )`
|
||||
|
||||
Always called after `HUD_PlayerMove`, even if movement prediction is disabled. Used for weapon prediction stuff.
|
||||
|
||||
* `from` is a pointer to `local_state_s` object of the previous predicted frame
|
||||
* `to` is a pointer to `local_state_s` object of this current frame
|
||||
* `cmd` is current user command
|
||||
* `runfuncs` is set to `1` if this frame was never predicted before, and to `0` if it is being predicted again
|
||||
* `random_seed` is set to `incoming_acknowledged` plus number of predicted frames starting with `1`. This way it's synchronized between client and server.
|
||||
|
||||
### `int HUD_Key_Event( int down, int key, const char *current_binding )`
|
||||
|
||||
Called on keyboard event.
|
||||
|
||||
* `down` is set to `1` if key is being pressed or set to `0` on being released.
|
||||
* `key` is set to the key number. The key IDs are predefined.
|
||||
* `current_binding` is set to a null-terminated string with commands bound to this key
|
||||
Return value: `0` if `client.dll` wants engine to ignore that key.
|
||||
|
||||
### `int HUD_AddEntity( int type, struct cl_entity_s *ent, const char *modelname )`
|
||||
|
||||
Called before adding entity to the rendering list.
|
||||
|
||||
* `type` is set to an entity type, see `entity_state_t::entityType`
|
||||
* `ent` is a pointer to `cl_entity_t` object.
|
||||
* `modelname` is a null-terminated string with that entity model name.
|
||||
Return value: `0` if `client.dll` wants engine to not draw this entity.
|
||||
|
||||
### `void HUD_CreateEntities( void )`
|
||||
|
||||
Called each frame after all network entities (including players) are linked to let `client.dll` spawn client-side entities.
|
||||
|
||||
### `void HUD_StudioEvent( const struct mstudioevent_s *event, const struct cl_entity_s *ent )`
|
||||
|
||||
Studio models have events tied to the frame, on which engine calls this function.
|
||||
|
||||
* `event` is a pointer to a studio event object
|
||||
* `ent` is a pointer to a client entity object
|
||||
|
||||
### `void HUD_TxferLocalOverrides( struct entity_state_s *state, const struct clientdata_s *client )`
|
||||
|
||||
When client processes entity updates, for local client it might be truncated, don't have enough precision, miss some critical info, so engine calls this function as `client.dll` might choose to use client data came from `svc_clientdata` message. Note that it is called on raw, non-interpolated networked entity state.
|
||||
|
||||
* `state` is a pointer to the local client entity state coming from the network
|
||||
* `client` is a pointer to local client data object
|
||||
|
||||
### `void HUD_ProcessPlayerState( struct entity_state_s *dst, const struct entity_state_s *src )`
|
||||
|
||||
When client processes entity updates, it calls this function for player entities as `client.dll` might want to override some data or fill the missing parts, but usually it just copies from `src` to `dst`.
|
||||
|
||||
* `src` is a target pointer to the player entity data (stored in frames, for example)
|
||||
* `dst` is a source pointer to the player entity data coming from network
|
||||
|
||||
### `void HUD_TxferPredictionData( struct entity_state_s *ps, const struct entity_state_s *pps, struct clientdata_s *pcd, const struct clientdata_s *ppcd, struct weapon_data_s *wd, const weapon_data_s *pwd )`
|
||||
|
||||
When client receives `svc_clientdata` message, this function is called before any parsing is done, so that the `client.dll` fills in data from prediction.
|
||||
|
||||
* `ps`, `pcd`, `wd` are pointers to current network frame data.
|
||||
* `pps`, `ppcd`, `pwd` are pointers to predicted frame data.
|
||||
|
||||
### `void HUD_TempEntUpdate( double frametime, double client_time, double cl_gravity, TEMPENTITY **ppTempEntFree, TEMPENTITY **ppTempEntActive, int ( *AddVisibleEntity )( cl_entity_t *pEntity ), void ( *TempEntPlaySound)( TEMPENTITY *pTemp, float damp ))`
|
||||
|
||||
Called each frame after network entities are processed and after `HUD_CreateEntities`, to let `client.dll` process temporary entities logic.
|
||||
|
||||
* `frametime` is the delta between `cl.time` and `cl.oldtime`, i.e. server time.
|
||||
* `client_time` is `cl.time`
|
||||
* `gravity` is the synchronized gravity value from the server
|
||||
* `ppTempEntFree` is a pointer to the head of linked list of free temp entities
|
||||
* `ppTempEntActive` is a pointer to the head of linked list of active temp entities
|
||||
* `AddVisibleEntity` is a pointer to function that lets `client.dll` add this entity to the rendering list.
|
||||
* `TempEntPlaySound` is a pointer to function that's called by `client.dll` when temp entity needs to play predefined hit sound. The `damp` argument of this argument only makes sound to NOT play, if it's zero or negative.
|
||||
|
||||
### `void HUD_DrawNormalTriangles( void )`
|
||||
|
||||
Called each rendering frame to let `client.dll` draw custom solid triangles through TriAPI or direct OpenGL calls.
|
||||
|
||||
### `void HUD_DrawTransparentTriangles( void )`
|
||||
|
||||
Called each rendering frame to let `client.dll` draw custom transparent triangles through TriAPI or direct OpenGL calls.
|
||||
|
||||
### `struct cl_entity_s *HUD_GetUserEntity( int index )`
|
||||
|
||||
Called by engine when beam start/end indices are negative, thus allowing attaching beams to a temporary or client-only entity.
|
||||
|
||||
* `index` is the fixed up entity index, as beam start/end indices encode real entity index in low 12 bits (i.e. `beament_start & 0xFFF`).
|
||||
|
||||
### `void Demo_ReadBuffer( int size, unsigned char *buffer )`
|
||||
|
||||
Called by engine on demo playback, if `client.dll` saved some custom data on demo recording prior.
|
||||
|
||||
* `size` is the size of buffer in bytes
|
||||
* `buffer` is the pointer to custom data stored by `client.dll` in demo
|
||||
|
||||
### `void CAM_Think( void )`
|
||||
|
||||
Called each frame before rendering starts to let `client.dll` run custom camera logic, like advanced thirdperson follow camera for example.
|
||||
|
||||
### `int CL_IsThirdPerson( void )`
|
||||
|
||||
Returns non-zero value if camera is in thirdperson mode, lets engine figure out whether add local client entity to the rendering list or not.
|
||||
|
||||
### `void CL_CameraOffset( vec3_t offset )`
|
||||
|
||||
Not used in the engine.
|
||||
|
||||
### `void CL_CreateMove( float frametime, usercmd_t *cmd, int active )`
|
||||
|
||||
Called when `usercmd_t` is being created to let `client.dll` record user commands before they are being sent over the network.
|
||||
|
||||
* `frametime` is the delta time between previous and current frames.
|
||||
* `cmd` is the pointer to `usercmd_t` object, where player's intentions and impulses are added.
|
||||
* `active` is set to `1` when client is finished signing on to the server (as movement commands are being sent even if client is not fully spawned yet).
|
||||
|
||||
### `void IN_ActivateMouse( void )`
|
||||
|
||||
Called from similarly named NQ/QW function.
|
||||
|
||||
### `void IN_DeactivateMouse( void )`
|
||||
|
||||
Called from similarly named NQ/QW function.
|
||||
|
||||
### `void IN_MouseEvent( int mstate )`
|
||||
|
||||
Called from similarly named NQ/QW function.
|
||||
|
||||
### `void IN_Accumulate( void )`
|
||||
|
||||
Called from similarly named NQ/QW function.
|
||||
|
||||
### `void IN_ClearStates( void )`
|
||||
|
||||
Called from similarly named NQ/QW function.
|
||||
|
||||
### `void V_CalcRefdef( struct ref_params_s *params )`
|
||||
|
||||
Called each frame before rendering starts. This is close to the similarly named function found in NQ/QW and lets `client.dll` to run custom view logic.
|
||||
|
||||
* `params` is the refdef parameters object. It is also used as return value and might request from the engine to not draw anything (by `onlyClientDraws` field) or to run this multiple times (by `nextview` field)
|
||||
|
||||
### `kbutton_t *KB_Find( const char *name )`
|
||||
|
||||
Called by engine to find extra keys and their state.
|
||||
|
||||
Only few are really used by the engine:
|
||||
* `in_mlook` for mouse look
|
||||
* `in_jlook` for joystick look
|
||||
* `in_graph` for net_graph toggle
|
||||
|
||||
Return value: returns pointer to `kbutton_t` if found. `kbutton_t` structure matches the same structure that can be found in NQ and QW.
|
||||
|
||||
### `void HUD_DirectorMessage( int size, void *buf )`
|
||||
|
||||
> [!IMPORTANT]
|
||||
> This function is optional.
|
||||
|
||||
Called to notify `client.dll` about an `svc_director` message. This feature is used for HLTV, though mods use it to spawn text messages or execute commands (bypassing `svc_stufftext` filter in old `client.dll`) but `svc_director` message structure isn't enforced by engine, so it in theory mods might modify it for their own needs.
|
||||
|
||||
* `size` is the size of the payload
|
||||
* `buf` raw `svc_director` payload
|
||||
|
||||
### `void HUD_VoiceStatus( int entindex, qboolean talking )`
|
||||
|
||||
> [!IMPORTANT]
|
||||
> This function is optional.
|
||||
|
||||
Called to notify `client.dll` about a client status of using voice chat.
|
||||
* `entindex` an entity index (client index plus one, because zero is always world). When set to -1, notifies `client.dll` about local client recording. When set to -2, notifies `client.dll` about a loopback (i.e. local client's voice message was sent to server and received back)
|
||||
* `talking` if true, this client is talking
|
||||
|
||||
### `void HUD_ChatInputPosition( int *x, int *y )`
|
||||
|
||||
> [!IMPORTANT]
|
||||
> This function is optional.
|
||||
|
||||
When called, returns desired X and Y positions of chat box.
|
||||
9
Documentation/api/client/README.md
Normal file
9
Documentation/api/client/README.md
Normal file
@@ -0,0 +1,9 @@
|
||||
# What is client.dll in GoldSource?
|
||||
|
||||
One of technical differences a programmer working with Quake engine might notice is the client.dll file. Historically, it appeared somewhere in between Alpha 0.52 and NetTest1 development and judging by Half-Life SDK 1.0 was meant to handle HUD rendering. The time moved forward, SDK 2.0 finalized `client.dll` API at version 7, added an in-game UI, custom input processing, player movement and weapon prediction, very basic rendering through TriAPI. SDK 2.1 added ability to re-define studio model rendering, and so on.
|
||||
|
||||
It somewhat resembles `cgame` module from Quake 3, but more crudely designed and sometimes feels like an afterthought, considering how many engine internal structures it exposes and the main point of incompatibilities with mods, which these days sometimes use `client.dll` as a way to inject custom rendering into the game.
|
||||
|
||||
In this document I will try to go through each step, letting you, dear reader, implement your own GoldSrc compatible API in your Quake fork, targetting vanilla Half-Life `client.dll` from latest update, which at the time of writing, is 25-th anniversary update.
|
||||
|
||||
Despite that we call it `client.dll`, since SDK 2.4 (unofficial naming, it's the first SDK Valve published on GitHub) it is considered portable and only has SDL2 and VGUI libraries in it's external dependences. It's only called this way to avoid possible misunderstandings with engine developers, who might interpret client as `cl_` prefixed part of Quake engine.
|
||||
120
Documentation/api/client/xx-structs.md
Normal file
120
Documentation/api/client/xx-structs.md
Normal file
@@ -0,0 +1,120 @@
|
||||
# `client.dll` shared structs and enums
|
||||
|
||||
GoldSource exposes a lot of structs to `client.dll`. Some of them are specific to `client.dll` and only used for passing data between engine and client, some of them are used in the engine everywhere, but still exposed in the public SDK. However, many mods rely on internal structs as well, and I will try to shed light on them as well.
|
||||
|
||||
When implementing them in C, consider the default to 32-bit systems alignment of 4 bytes and ILP32 data type model.
|
||||
|
||||
This file won't have API structs, for that, there should be separate chapters.
|
||||
|
||||
## Enums
|
||||
|
||||
### Entity types enum
|
||||
|
||||
This enum has no real name.
|
||||
|
||||
| Value | Description |
|
||||
|-------|-----------------|
|
||||
| `0` | Normal entities |
|
||||
| `1` | Players |
|
||||
| `2` | Temp entities |
|
||||
| `3` | Beams |
|
||||
| `4` | Fragmented entities. |
|
||||
|
||||
### edict->solid
|
||||
|
||||
It matches QuakeWorld definition.
|
||||
|
||||
## `client_data_t`
|
||||
|
||||
Used only to pass data to `client.dll` through `HUD_UpdateClientData`.
|
||||
|
||||
| Type | Name | Description |
|
||||
|----------|---------------|--------------------------------------------------------------|
|
||||
| `vec3_t` | `origin` | Local client origin. Cannot be changed by `client.dll` here. |
|
||||
| `vec3_t` | `viewangles` | Local client viewangles. This and next fields can be changed by `client.dll` |
|
||||
| `int` | `iWeaponBits` | Bit vector of weapons held by client. |
|
||||
| `float` | `fov` | Local client's field of view. |
|
||||
|
||||
## `netadr_t`
|
||||
|
||||
Matches Quake-2 structure with the similar name.
|
||||
|
||||
## `local_state_t`
|
||||
|
||||
Only consists of another structs. All of these structs are used to store prediction data, so one `local_state_t` for each predicted frame.
|
||||
|
||||
| Type | Name | Description |
|
||||
|---------------------|---------------|--------------------------------------|
|
||||
| `entity_state_t` | `playerstate` | Contains local player's entity state |
|
||||
| `clientdata_t` | `client` | Additional information about local client. _Do not get confused with `client_data_t`, note the underscore._ |
|
||||
| `weapon_data_t[64]` | `weapondata` | Array of 64 predictable weapons. |
|
||||
|
||||
## `entity_state_t`
|
||||
|
||||
This structure is similar to the one that can be found in QW, but contains much more data, though most of these fields are not used by the engine, but might be used by mods.
|
||||
|
||||
| Type | Name | Description |
|
||||
|-------------|----------------|------------------------------------------------------|
|
||||
| `int` | `entityType` | Entity type (see entity type enum above) |
|
||||
| `int` | `number` | Index of this entity on the server |
|
||||
| `float` | `msg_time` | Server time at which this entity had been updated |
|
||||
| `int` | `messagenum` | `parsecount` at which this entity had been updated |
|
||||
| `vec3_t` | `origin` | Non-interpolated entity position |
|
||||
| `vec3_t` | `angles` | Non-interpolated entity angles |
|
||||
| `int` | `modelindex` | Server model index |
|
||||
| `int` | `sequence` | Model animation sequence |
|
||||
| `int` | `frame` | Model animation frame |
|
||||
| `int` | `colormap` | Texture's top and bottom colors, like Quake |
|
||||
| `short` | `skin` | Texture number |
|
||||
| `short` | `solid` | `edict->solid` enum |
|
||||
| `int` | `effects` | Bitmask of entity effects |
|
||||
| `float` | `scale` | Entity scale value |
|
||||
| `byte` | `eflags` | |
|
||||
| `int` | `eflags` | |
|
||||
| `int` | `eflags` | |
|
||||
| `color24` | `eflags` | |
|
||||
| `int` | `eflags` | |
|
||||
| `int` | `eflags` | |
|
||||
| `float` | `eflags` | |
|
||||
| `float` | `eflags` | |
|
||||
| `int` | `eflags` | |
|
||||
| `byte[4]` | `eflags` | |
|
||||
| `byte[4]` | `eflags` | |
|
||||
| `vec3_t` | `eflags` | |
|
||||
| `vec3_t` | `eflags` | |
|
||||
| `vec3_t` | `eflags` | |
|
||||
| `vec3_t` | `maxs` | |
|
||||
| `int` | `eflags` | |
|
||||
| `int` | `eflags` | |
|
||||
| `float` | `eflags` | |
|
||||
| `float` | `eflags` | |
|
||||
| `int` | `eflags` | |
|
||||
| `int` | `eflags` | |
|
||||
| `int` | `eflags` | |
|
||||
| `qboolean` | `eflags` | |
|
||||
| `int` | `eflags` | |
|
||||
| `int` | `eflags` | |
|
||||
| `vec3_t` | `eflags` | |
|
||||
| `int` | `eflags` | |
|
||||
| `int` | `eflags` | |
|
||||
| `int` | `eflags` | |
|
||||
| `int` | `eflags` | |
|
||||
| `float` | `eflags` | |
|
||||
| `float` | `eflags` | |
|
||||
| `int` | `eflags` | |
|
||||
| `vec3_t` | `eflags` | |
|
||||
| `vec3_t` | `eflags` | |
|
||||
| `float` | `eflags` | |
|
||||
| `float` | `eflags` | |
|
||||
| `int` | `iuser1` | Few more extra fields for mods |
|
||||
| `int` | `iuser2` | |
|
||||
| `int` | `iuser3` | |
|
||||
| `int` | `iuser4` | |
|
||||
| `float` | `fuser1` | |
|
||||
| `float` | `fuser2` | |
|
||||
| `float` | `fuser3` | |
|
||||
| `float` | `fuser4` | |
|
||||
| `vec3_t` | `vuser1` | |
|
||||
| `vec3_t` | `vuser2` | |
|
||||
| `vec3_t` | `vuser3` | |
|
||||
| `vec3_t` | `vuser4` | |
|
||||
@@ -2,7 +2,7 @@
|
||||
[](https://builds.sr.ht/~a1batross/xash3d-fwgs?) [](https://github.com/FWGS/xash3d-fwgs/actions/workflows/c-cpp.yml) [](https://cirrus-ci.com/github/FWGS/xash3d-fwgs) [](http://fwgsdiscord.mentality.rip/) \
|
||||
[](https://github.com/FWGS/xash3d-fwgs/releases/latest) [](https://github.com/FWGS/xash3d-fwgs/releases/tag/continuous)
|
||||
|
||||
Xash3D (pronounced `[ksɑʂ]`) FWGS is a game engine, aimed to provide compatibility with Half-Life Engine and extend it, as well as to give game developers well known workflow.
|
||||
Xash3D ([pronounced](https://ipa-reader.com/?text=ks%C9%91%CA%82) `[ksɑʂ]`) FWGS is a game engine, aimed to provide compatibility with Half-Life Engine and extend it, as well as to give game developers well known workflow.
|
||||
|
||||
Xash3D FWGS is a heavily modified fork of an original [Xash3D Engine](https://www.moddb.com/engines/xash3d-engine) by Unkle Mike.
|
||||
|
||||
|
||||
@@ -30,6 +30,18 @@ public class XashActivity extends SDLActivity {
|
||||
AndroidBug5497Workaround.assistActivity(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy()
|
||||
{
|
||||
super.onDestroy();
|
||||
|
||||
// Now that we don't exit from native code, we need to exit here, resetting
|
||||
// application state (actually global variables that we don't cleanup on exit)
|
||||
//
|
||||
// When the issue with global variables will be resolved, remove that exit() call
|
||||
System.exit(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String[] getLibraries() {
|
||||
return new String[]{"SDL2", "xash"};
|
||||
|
||||
@@ -153,6 +153,7 @@ static void CL_WriteErrorMessage( int current_count, sizebuf_t *msg )
|
||||
|
||||
FS_Write( fp, &cls.starting_count, sizeof( int ));
|
||||
FS_Write( fp, ¤t_count, sizeof( int ));
|
||||
FS_Write( fp, &cls.legacymode, sizeof( cls.legacymode ));
|
||||
FS_Write( fp, MSG_GetData( msg ), MSG_GetMaxBytes( msg ));
|
||||
FS_Close( fp );
|
||||
|
||||
@@ -168,7 +169,7 @@ list last 32 messages for debugging net troubleshooting
|
||||
*/
|
||||
void CL_WriteMessageHistory( void )
|
||||
{
|
||||
oldcmd_t *old, *failcommand;
|
||||
oldcmd_t *old;
|
||||
sizebuf_t *msg = &net_message;
|
||||
int i, thecmd;
|
||||
|
||||
@@ -192,9 +193,8 @@ void CL_WriteMessageHistory( void )
|
||||
thecmd++;
|
||||
}
|
||||
|
||||
failcommand = &cls_message_debug.oldcmd[thecmd];
|
||||
Con_Printf( "BAD: %3i:%s\n", MSG_GetNumBytesRead( msg ) - 1, CL_MsgInfo( failcommand->command ));
|
||||
if( host_developer.value >= DEV_EXTENDED )
|
||||
CL_WriteErrorMessage( MSG_GetNumBytesRead( msg ) - 1, msg );
|
||||
old = &cls_message_debug.oldcmd[thecmd];
|
||||
Con_Printf( S_RED "BAD: " S_DEFAULT "%i %04i %s\n", old->frame_number, old->starting_offset, CL_MsgInfo( old->command ));
|
||||
CL_WriteErrorMessage( old->starting_offset, msg );
|
||||
cls_message_debug.parsing = false;
|
||||
}
|
||||
|
||||
@@ -624,11 +624,10 @@ static void CL_ReadDemoUserCmd( qboolean discard )
|
||||
|
||||
if( !discard )
|
||||
{
|
||||
usercmd_t nullcmd;
|
||||
const usercmd_t nullcmd = { 0 };
|
||||
sizebuf_t buf;
|
||||
demoangle_t *a;
|
||||
|
||||
memset( &nullcmd, 0, sizeof( nullcmd ));
|
||||
MSG_Init( &buf, "UserCmd", data, sizeof( data ));
|
||||
|
||||
// a1ba: I have no proper explanation why
|
||||
|
||||
@@ -2408,9 +2408,8 @@ CL_FindModelIndex
|
||||
*/
|
||||
static int GAME_EXPORT CL_FindModelIndex( const char *m )
|
||||
{
|
||||
char filepath[MAX_QPATH];
|
||||
static float lasttimewarn;
|
||||
int i;
|
||||
char filepath[MAX_QPATH];
|
||||
int i;
|
||||
|
||||
if( !COM_CheckString( m ))
|
||||
return 0;
|
||||
@@ -2427,13 +2426,6 @@ static int GAME_EXPORT CL_FindModelIndex( const char *m )
|
||||
return i+1;
|
||||
}
|
||||
|
||||
if( lasttimewarn < host.realtime )
|
||||
{
|
||||
// tell user about problem (but don't spam console)
|
||||
Con_DPrintf( S_ERROR "Could not find index for model %s: not precached\n", filepath );
|
||||
lasttimewarn = host.realtime + 1.0f;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -147,11 +147,6 @@ qboolean CL_IsRecordDemo( void )
|
||||
return cls.demorecording;
|
||||
}
|
||||
|
||||
qboolean CL_IsTimeDemo( void )
|
||||
{
|
||||
return cls.timedemo;
|
||||
}
|
||||
|
||||
qboolean CL_DisableVisibility( void )
|
||||
{
|
||||
return cls.envshot_disable_vis;
|
||||
@@ -598,7 +593,7 @@ CL_CreateCmd
|
||||
*/
|
||||
static void CL_CreateCmd( void )
|
||||
{
|
||||
usercmd_t nullcmd, *cmd;
|
||||
usercmd_t nullcmd = { 0 }, *cmd;
|
||||
runcmd_t *pcmd;
|
||||
qboolean active;
|
||||
double accurate_ms;
|
||||
@@ -650,7 +645,6 @@ static void CL_CreateCmd( void )
|
||||
}
|
||||
else
|
||||
{
|
||||
memset( &nullcmd, 0, sizeof( nullcmd ));
|
||||
cmd = &nullcmd;
|
||||
}
|
||||
|
||||
@@ -825,7 +819,7 @@ static void CL_WritePacket( void )
|
||||
buf.pData[key] = CRC32_BlockSequence( &buf.pData[key + 1], size, cls.netchan.outgoing_sequence );
|
||||
COM_Munge( &buf.pData[key + 1], Q_min( size, 255 ), cls.netchan.outgoing_sequence );
|
||||
}
|
||||
else
|
||||
else if( !Host_IsLocalClient( ))
|
||||
{
|
||||
int size = MSG_GetRealBytesWritten( &buf ) - key - 1;
|
||||
buf.pData[key] = CRC32_BlockSequence( &buf.pData[key + 1], size, cls.netchan.outgoing_sequence );
|
||||
@@ -1761,8 +1755,8 @@ static size_t NONNULL CL_BuildMasterServerScanRequest( char *buf, size_t size, u
|
||||
// let master know about client version
|
||||
Info_SetValueForKey( info, "clver", XASH_VERSION, remaining );
|
||||
Info_SetValueForKey( info, "nat", nat ? "1" : "0", remaining );
|
||||
Info_SetValueForKey( info, "commit", Q_buildcommit(), remaining );
|
||||
Info_SetValueForKey( info, "branch", Q_buildbranch(), remaining );
|
||||
Info_SetValueForKey( info, "commit", g_buildcommit, remaining );
|
||||
Info_SetValueForKey( info, "branch", g_buildbranch, remaining );
|
||||
Info_SetValueForKey( info, "os", Q_buildos(), remaining );
|
||||
Info_SetValueForKey( info, "arch", Q_buildarch(), remaining );
|
||||
|
||||
|
||||
@@ -534,7 +534,7 @@ void CL_ParseGoldSrcServerMessage( sizebuf_t *msg )
|
||||
{
|
||||
if( MSG_CheckOverflow( msg ))
|
||||
{
|
||||
Host_Error( "CL_ParseServerMessage: overflow!\n" );
|
||||
Host_Error( "%s: overflow!\n", __func__ );
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -567,57 +567,54 @@ R_FizzEffect
|
||||
Create a fizz effect
|
||||
==============
|
||||
*/
|
||||
void GAME_EXPORT R_FizzEffect( cl_entity_t *pent, int modelIndex, int density )
|
||||
void GAME_EXPORT R_FizzEffect( cl_entity_t *ent, int modelIndex, int density )
|
||||
{
|
||||
TEMPENTITY *pTemp;
|
||||
int i, width, depth;
|
||||
float angle, maxHeight, speed;
|
||||
float xspeed, yspeed, zspeed;
|
||||
vec3_t origin;
|
||||
model_t *mod;
|
||||
const float base_time = cl.time - 0.1f;
|
||||
model_t *mod = CL_ModelHandle( modelIndex );
|
||||
vec3_t volume, mins, maxs;
|
||||
vec2_t speed;
|
||||
int i;
|
||||
|
||||
if( !pent || !pent->model || !modelIndex )
|
||||
if( !ent || !ent->model || !modelIndex || !mod )
|
||||
return;
|
||||
|
||||
if(( mod = CL_ModelHandle( modelIndex )) == NULL )
|
||||
return;
|
||||
VectorCopy( ent->model->mins, mins );
|
||||
VectorCopy( ent->model->maxs, maxs );
|
||||
|
||||
maxHeight = pent->model->maxs[2] - pent->model->mins[2];
|
||||
width = pent->model->maxs[0] - pent->model->mins[0];
|
||||
depth = pent->model->maxs[1] - pent->model->mins[1];
|
||||
if( ent->angles[1] != 0.0f )
|
||||
{
|
||||
const float base_speed = ( ent->curstate.rendercolor.b ? -1.0f : 1.0f ) * ( ent->curstate.rendercolor.r * 256.0f + ent->curstate.rendercolor.g );
|
||||
SinCos( DEG2RAD( ent->angles[1] ), &speed[1], &speed[0] );
|
||||
speed[0] *= base_speed;
|
||||
speed[1] *= base_speed;
|
||||
}
|
||||
else speed[0] = speed[1] = 0.0f;
|
||||
|
||||
speed = ( pent->curstate.rendercolor.r<<8 | pent->curstate.rendercolor.g );
|
||||
if( pent->curstate.rendercolor.b )
|
||||
speed = -speed;
|
||||
|
||||
angle = DEG2RAD( pent->angles[YAW] );
|
||||
SinCos( angle, &yspeed, &xspeed );
|
||||
|
||||
xspeed *= speed;
|
||||
yspeed *= speed;
|
||||
VectorSubtract( maxs, mins, volume );
|
||||
|
||||
for( i = 0; i <= density; i++ )
|
||||
{
|
||||
origin[0] = mod->mins[0] + COM_RandomLong( 0, width - 1 );
|
||||
origin[1] = mod->mins[1] + COM_RandomLong( 0, depth - 1 );
|
||||
origin[2] = mod->mins[2];
|
||||
pTemp = CL_TempEntAlloc( origin, mod );
|
||||
TEMPENTITY *tent;
|
||||
vec3_t origin;
|
||||
|
||||
if ( !pTemp ) return;
|
||||
VectorCopy( mins, origin );
|
||||
origin[0] += COM_RandomLong( 0, (int)volume[0] - 1 );
|
||||
origin[1] += COM_RandomLong( 0, (int)volume[1] - 1 );
|
||||
|
||||
pTemp->flags |= FTENT_SINEWAVE;
|
||||
if( !( tent = CL_TempEntAlloc( origin, mod )))
|
||||
return;
|
||||
|
||||
pTemp->x = origin[0];
|
||||
pTemp->y = origin[1];
|
||||
tent->x = origin[0];
|
||||
tent->y = origin[1];
|
||||
tent->die = base_time;
|
||||
tent->flags |= FTENT_SINEWAVE;
|
||||
tent->entity.curstate.rendermode = kRenderTransAlpha;
|
||||
Vector2Copy( speed, tent->entity.baseline.origin );
|
||||
|
||||
zspeed = COM_RandomLong( 80, 140 );
|
||||
VectorSet( pTemp->entity.baseline.origin, xspeed, yspeed, zspeed );
|
||||
pTemp->die = cl.time + ( maxHeight / zspeed ) - 0.1f;
|
||||
pTemp->entity.curstate.frame = COM_RandomLong( 0, pTemp->frameMax );
|
||||
// Set sprite scale
|
||||
pTemp->entity.curstate.scale = 1.0f / COM_RandomFloat( 2.0f, 5.0f );
|
||||
pTemp->entity.curstate.rendermode = kRenderTransAlpha;
|
||||
pTemp->entity.curstate.renderamt = 255;
|
||||
tent->entity.baseline.origin[2] = COM_RandomLong( 80, 140 );
|
||||
tent->die += volume[2] / tent->entity.baseline.origin[2];
|
||||
tent->entity.curstate.frame = COM_RandomLong( 0, tent->frameMax );
|
||||
tent->entity.curstate.scale = 1.0f / COM_RandomFloat( 2.0f, 5.0f );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -266,7 +266,7 @@ static qboolean Touch_DumpConfig( const char *name, const char *profilename )
|
||||
}
|
||||
|
||||
FS_Printf( f, "//=======================================================================\n");
|
||||
FS_Printf( f, "//\tGenerated by "XASH_ENGINE_NAME" (%i, %s, %s, %s-%s)\n", Q_buildnum(), Q_buildcommit(), Q_buildbranch(), Q_buildos(), Q_buildarch());
|
||||
FS_Printf( f, "//\tGenerated by "XASH_ENGINE_NAME" (%i, %s, %s, %s-%s)\n", Q_buildnum(), g_buildcommit, g_buildbranch, Q_buildos(), Q_buildarch());
|
||||
FS_Printf( f, "//\t\t\ttouchscreen config\n" );
|
||||
FS_Printf( f, "//=======================================================================\n" );
|
||||
FS_Printf( f, "\ntouch_config_file \"%s\"\n", profilename );
|
||||
|
||||
@@ -301,7 +301,6 @@ typedef struct host_parm_s
|
||||
poolhandle_t mempool; // static mempool for misc allocations
|
||||
poolhandle_t imagepool; // imagelib mempool
|
||||
poolhandle_t soundpool; // soundlib mempool
|
||||
string finalmsg; // server shutdown final message
|
||||
string downloadfile; // filename to be downloading
|
||||
int downloadcount; // how many files remain to downloading
|
||||
char deferred_cmd[128];// deferred commands
|
||||
@@ -560,6 +559,7 @@ void Host_Error( const char *error, ... ) FORMAT_CHECK( 1 );
|
||||
void Host_ValidateEngineFeatures( uint32_t mask, uint32_t features );
|
||||
void Host_Frame( double time );
|
||||
void Host_Credits( void );
|
||||
void Host_ExitInMain( void );
|
||||
|
||||
//
|
||||
// host_state.c
|
||||
@@ -578,11 +578,19 @@ CLIENT / SERVER SYSTEMS
|
||||
|
||||
==============================================================
|
||||
*/
|
||||
#if !XASH_DEDICATED
|
||||
void CL_Init( void );
|
||||
void CL_Shutdown( void );
|
||||
void Host_ClientBegin( void );
|
||||
void Host_ClientFrame( void );
|
||||
int CL_Active( void );
|
||||
#else
|
||||
static inline void CL_Init( void ) { }
|
||||
static inline void CL_Shutdown( void ) { }
|
||||
static inline void Host_ClientBegin( void ) { Cbuf_Execute(); }
|
||||
static inline void Host_ClientFrame( void ) { }
|
||||
static inline int CL_Active( void ) { return 0; }
|
||||
#endif
|
||||
|
||||
void SV_Init( void );
|
||||
void SV_Shutdown( const char *finalmsg );
|
||||
@@ -703,13 +711,32 @@ typedef enum connprotocol_e
|
||||
struct physent_s;
|
||||
struct sv_client_s;
|
||||
typedef struct sizebuf_s sizebuf_t;
|
||||
int SV_GetMaxClients( void );
|
||||
|
||||
#if !XASH_DEDICATED
|
||||
qboolean CL_Initialized( void );
|
||||
qboolean CL_IsInGame( void );
|
||||
qboolean CL_IsInConsole( void );
|
||||
qboolean CL_IsIntermission( void );
|
||||
qboolean CL_Initialized( void );
|
||||
qboolean CL_DisableVisibility( void );
|
||||
qboolean CL_IsRecordDemo( void );
|
||||
qboolean CL_IsPlaybackDemo( void );
|
||||
qboolean UI_CreditsActive( void );
|
||||
int CL_GetMaxClients( void );
|
||||
#else
|
||||
static inline qboolean CL_Initialized( void ) { return false; }
|
||||
static inline qboolean CL_IsInGame( void ) { return false; }
|
||||
static inline qboolean CL_IsInConsole( void ) { return false; }
|
||||
static inline qboolean CL_IsIntermission( void ) { return false; }
|
||||
static inline qboolean CL_DisableVisibility( void ) { return false; }
|
||||
static inline qboolean CL_IsRecordDemo( void ) { return false; }
|
||||
static inline qboolean CL_IsPlaybackDemo( void ) { return false; }
|
||||
static inline qboolean UI_CreditsActive( void ) { return false; }
|
||||
static inline int CL_GetMaxClients( void ) { return SV_GetMaxClients(); }
|
||||
#endif
|
||||
|
||||
char *CL_Userinfo( void );
|
||||
void CL_CharEvent( int key );
|
||||
qboolean CL_DisableVisibility( void );
|
||||
byte *COM_LoadFile( const char *filename, int usehunk, int *pLength ) MALLOC_LIKE( free, 1 );
|
||||
struct cmd_s *Cmd_GetFirstFunctionHandle( void );
|
||||
struct cmd_s *Cmd_GetNextFunctionHandle( struct cmd_s *cmd );
|
||||
@@ -727,13 +754,7 @@ const char *CL_MsgInfo( int cmd );
|
||||
void SV_DrawDebugTriangles( void );
|
||||
void SV_DrawOrthoTriangles( void );
|
||||
double CL_GetDemoFramerate( void );
|
||||
qboolean UI_CreditsActive( void );
|
||||
void CL_StopPlayback( void );
|
||||
int CL_GetMaxClients( void );
|
||||
int SV_GetMaxClients( void );
|
||||
qboolean CL_IsRecordDemo( void );
|
||||
qboolean CL_IsTimeDemo( void );
|
||||
qboolean CL_IsPlaybackDemo( void );
|
||||
qboolean SV_Initialized( void );
|
||||
void CL_ProcessFile( qboolean successfully_received, const char *filename );
|
||||
int SV_GetSaveComment( const char *savename, char *comment );
|
||||
|
||||
@@ -1395,7 +1395,7 @@ void Host_WriteConfig( void )
|
||||
{
|
||||
Con_Reportf( "%s()\n", __func__ );
|
||||
FS_Printf( f, "//=======================================================================\n");
|
||||
FS_Printf( f, "//\tGenerated by "XASH_ENGINE_NAME" (%i, %s, %s, %s-%s)\n", Q_buildnum(), Q_buildcommit(), Q_buildbranch(), Q_buildos(), Q_buildarch());
|
||||
FS_Printf( f, "//\tGenerated by "XASH_ENGINE_NAME" (%i, %s, %s, %s-%s)\n", Q_buildnum(), g_buildcommit, g_buildbranch, Q_buildos(), Q_buildarch());
|
||||
FS_Printf( f, "//\t\tconfig.cfg - archive of cvars\n" );
|
||||
FS_Printf( f, "//=======================================================================\n" );
|
||||
Key_WriteBindings( f );
|
||||
@@ -1443,7 +1443,7 @@ void GAME_EXPORT Host_WriteServerConfig( const char *name )
|
||||
if(( f = FS_Open( newconfigfile, "w", false )) != NULL )
|
||||
{
|
||||
FS_Printf( f, "//=======================================================================\n" );
|
||||
FS_Printf( f, "//\tGenerated by "XASH_ENGINE_NAME" (%i, %s, %s, %s-%s)\n", Q_buildnum(), Q_buildcommit(), Q_buildbranch(), Q_buildos(), Q_buildarch());
|
||||
FS_Printf( f, "//\tGenerated by "XASH_ENGINE_NAME" (%i, %s, %s, %s-%s)\n", Q_buildnum(), g_buildcommit, g_buildbranch, Q_buildos(), Q_buildarch());
|
||||
FS_Printf( f, "//\t\tgame.cfg - multiplayer server temporare config\n" );
|
||||
FS_Printf( f, "//=======================================================================\n" );
|
||||
|
||||
@@ -1478,7 +1478,7 @@ void Host_WriteOpenGLConfig( void )
|
||||
{
|
||||
Con_Reportf( "%s()\n", __func__ );
|
||||
FS_Printf( f, "//=======================================================================\n" );
|
||||
FS_Printf( f, "//\tGenerated by "XASH_ENGINE_NAME" (%i, %s, %s, %s-%s)\n", Q_buildnum(), Q_buildcommit(), Q_buildbranch(), Q_buildos(), Q_buildarch());
|
||||
FS_Printf( f, "//\tGenerated by "XASH_ENGINE_NAME" (%i, %s, %s, %s-%s)\n", Q_buildnum(), g_buildcommit, g_buildbranch, Q_buildos(), Q_buildarch());
|
||||
FS_Printf( f, "//\t\t%s - archive of renderer implementation cvars\n", name );
|
||||
FS_Printf( f, "//=======================================================================\n" );
|
||||
FS_Printf( f, "\n" );
|
||||
@@ -1508,7 +1508,7 @@ void Host_WriteVideoConfig( void )
|
||||
{
|
||||
Con_Reportf( "%s()\n", __func__ );
|
||||
FS_Printf( f, "//=======================================================================\n" );
|
||||
FS_Printf( f, "//\tGenerated by "XASH_ENGINE_NAME" (%i, %s, %s, %s-%s)\n", Q_buildnum(), Q_buildcommit(), Q_buildbranch(), Q_buildos(), Q_buildarch());
|
||||
FS_Printf( f, "//\tGenerated by "XASH_ENGINE_NAME" (%i, %s, %s, %s-%s)\n", Q_buildnum(), g_buildcommit, g_buildbranch, Q_buildos(), Q_buildarch());
|
||||
FS_Printf( f, "//\t\tvideo.cfg - archive of renderer variables\n");
|
||||
FS_Printf( f, "//=======================================================================\n" );
|
||||
Cvar_WriteVariables( f, FCVAR_RENDERINFO );
|
||||
@@ -1534,7 +1534,7 @@ void Key_EnumCmds_f( void )
|
||||
if( f )
|
||||
{
|
||||
FS_Printf( f, "//=======================================================================\n");
|
||||
FS_Printf( f, "//\tGenerated by "XASH_ENGINE_NAME" (%i, %s, %s, %s-%s)\n", Q_buildnum(), Q_buildcommit(), Q_buildbranch(), Q_buildos(), Q_buildarch());
|
||||
FS_Printf( f, "//\tGenerated by "XASH_ENGINE_NAME" (%i, %s, %s, %s-%s)\n", Q_buildnum(), g_buildcommit, g_buildbranch, Q_buildos(), Q_buildarch());
|
||||
FS_Printf( f, "//\t\thelp.txt - xash commands and console variables\n");
|
||||
FS_Printf( f, "//=======================================================================\n");
|
||||
|
||||
|
||||
@@ -49,52 +49,6 @@ const char *CL_MsgInfo( int cmd )
|
||||
return sz;
|
||||
}
|
||||
|
||||
int GAME_EXPORT CL_Active( void )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
qboolean CL_Initialized( void )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
qboolean CL_IsInGame( void )
|
||||
{
|
||||
return true; // always active for dedicated servers
|
||||
}
|
||||
|
||||
qboolean CL_IsInConsole( void )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
qboolean CL_IsIntermission( void )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
qboolean CL_IsPlaybackDemo( void )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
qboolean CL_IsRecordDemo( void )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
qboolean CL_DisableVisibility( void )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void CL_Init( void )
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void Key_Init( void )
|
||||
{
|
||||
|
||||
@@ -130,16 +84,6 @@ void CL_WriteMessageHistory( void )
|
||||
|
||||
}
|
||||
|
||||
void Host_ClientBegin( void )
|
||||
{
|
||||
Cbuf_Execute();
|
||||
}
|
||||
|
||||
void Host_ClientFrame( void )
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void Host_InputFrame( void )
|
||||
{
|
||||
}
|
||||
@@ -159,11 +103,6 @@ void GAME_EXPORT S_StopSound(int entnum, int channel, const char *soundname)
|
||||
|
||||
}
|
||||
|
||||
int GAME_EXPORT CL_GetMaxClients( void )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void IN_TouchInitConfig( void )
|
||||
{
|
||||
|
||||
@@ -174,11 +113,6 @@ void CL_Disconnect( void )
|
||||
|
||||
}
|
||||
|
||||
void CL_Shutdown( void )
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void R_ClearStaticEntities( void )
|
||||
{
|
||||
|
||||
@@ -189,11 +123,6 @@ void Host_Credits( void )
|
||||
|
||||
}
|
||||
|
||||
qboolean UI_CreditsActive( void )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void S_StopBackgroundTrack( void )
|
||||
{
|
||||
|
||||
@@ -204,11 +133,6 @@ void SCR_BeginLoadingPlaque( qboolean is_background )
|
||||
|
||||
}
|
||||
|
||||
int S_GetCurrentDynamicSounds( soundlist_t *pout, int size )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void S_StopAllSounds( qboolean ambient )
|
||||
{
|
||||
|
||||
|
||||
@@ -43,6 +43,27 @@ GNU General Public License for more details.
|
||||
static pfnChangeGame pChangeGame = NULL;
|
||||
host_parm_t host; // host parms
|
||||
|
||||
#if XASH_ANDROID
|
||||
static jmp_buf return_from_main_buf;
|
||||
|
||||
/*
|
||||
===============
|
||||
Host_ExitInMain
|
||||
|
||||
On some platforms (e.g. Android) we can't exit with exit(3) as calling it would
|
||||
kill wrapper process (e.g. app_process) too early, before all resources would
|
||||
be freed, contexts released, files closed, etc, etc...
|
||||
|
||||
To fix this, we create jmp_buf in Host_Main function, when jumping into with
|
||||
non-zero value will immediately return from it with `error_on_exit`.
|
||||
===============
|
||||
*/
|
||||
void Host_ExitInMain( void )
|
||||
{
|
||||
longjmp( return_from_main_buf, 1 );
|
||||
}
|
||||
#endif // XASH_ANDROID
|
||||
|
||||
#ifdef XASH_ENGINE_TESTS
|
||||
struct tests_stats_s tests_stats;
|
||||
#endif
|
||||
@@ -362,9 +383,8 @@ static void Host_NewInstance( const char *name, const char *finalmsg )
|
||||
if( !pChangeGame ) return;
|
||||
|
||||
host.change_game = true;
|
||||
Q_strncpy( host.finalmsg, finalmsg, sizeof( host.finalmsg ));
|
||||
|
||||
if( !Sys_NewInstance( name ))
|
||||
if( !Sys_NewInstance( name, finalmsg ))
|
||||
pChangeGame( name ); // call from hl.exe
|
||||
}
|
||||
|
||||
@@ -838,7 +858,6 @@ void GAME_EXPORT Host_Error( const char *error, ... )
|
||||
recursive = true;
|
||||
Q_strncpy( hosterror2, hosterror1, sizeof( hosterror2 ));
|
||||
host.errorframe = host.framecount; // to avoid multply calls per frame
|
||||
Q_snprintf( host.finalmsg, sizeof( host.finalmsg ), "Server crashed: %s", hosterror1 );
|
||||
|
||||
// clearing cmd buffer to prevent execute any commands
|
||||
COM_InitHostState();
|
||||
@@ -1214,7 +1233,7 @@ int EXPORT Host_Main( int argc, char **argv, const char *progname, int bChangeGa
|
||||
|
||||
Cvar_Getf( "buildnum", FCVAR_READ_ONLY, "returns a current build number", "%i", Q_buildnum_compat());
|
||||
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_ver", FCVAR_READ_ONLY, "detailed info about this build", "%i " XASH_VERSION " %s %s %s", Q_buildnum(), Q_buildos(), Q_buildarch(), g_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();
|
||||
@@ -1321,6 +1340,11 @@ int EXPORT Host_Main( int argc, char **argv, const char *progname, int bChangeGa
|
||||
// check after all configs were executed
|
||||
HPAK_CheckIntegrity( hpk_custom_file.string );
|
||||
|
||||
#if XASH_ANDROID
|
||||
if( setjmp( return_from_main_buf ))
|
||||
return error_on_exit;
|
||||
#endif // XASH_ANDROID
|
||||
|
||||
// main window message loop
|
||||
while( !host.crashed )
|
||||
{
|
||||
@@ -1359,9 +1383,6 @@ void Host_ShutdownWithReason( const char *reason )
|
||||
if( host.status != HOST_ERR_FATAL )
|
||||
host.status = HOST_SHUTDOWN; // prepare host to normal shutdown
|
||||
|
||||
if( !host.change_game )
|
||||
Q_strncpy( host.finalmsg, "Server shutdown", sizeof( host.finalmsg ));
|
||||
|
||||
#if !XASH_DEDICATED
|
||||
if( host.type == HOST_NORMAL && !error )
|
||||
Host_WriteConfig();
|
||||
@@ -1384,5 +1405,5 @@ void Host_ShutdownWithReason( const char *reason )
|
||||
|
||||
// restore filter
|
||||
Sys_RestoreCrashHandler();
|
||||
Sys_CloseLog();
|
||||
Sys_CloseLog( reason );
|
||||
}
|
||||
|
||||
@@ -104,7 +104,7 @@ static void HPAK_CreatePak( const char *filename, resource_t *pResource, byte *p
|
||||
string pakname;
|
||||
byte md5[16];
|
||||
file_t *fout;
|
||||
MD5Context_t ctx;
|
||||
MD5Context_t ctx = { 0 };
|
||||
|
||||
if( !COM_CheckString( filename ))
|
||||
return;
|
||||
@@ -125,7 +125,6 @@ static void HPAK_CreatePak( const char *filename, resource_t *pResource, byte *p
|
||||
}
|
||||
|
||||
// let's hash it.
|
||||
memset( &ctx, 0, sizeof( MD5Context_t ));
|
||||
MD5Init( &ctx );
|
||||
|
||||
if( pData == NULL )
|
||||
@@ -214,7 +213,7 @@ void HPAK_AddLump( qboolean bUseQueue, const char *name, resource_t *pResource,
|
||||
file_t *file_src;
|
||||
file_t *file_dst;
|
||||
byte md5[16];
|
||||
MD5Context_t ctx;
|
||||
MD5Context_t ctx = { 0 };
|
||||
|
||||
if( pData == NULL && pFile == NULL )
|
||||
return;
|
||||
@@ -226,7 +225,6 @@ void HPAK_AddLump( qboolean bUseQueue, const char *name, resource_t *pResource,
|
||||
}
|
||||
|
||||
// hash it
|
||||
memset( &ctx, 0, sizeof( MD5Context_t ));
|
||||
MD5Init( &ctx );
|
||||
|
||||
if( !pData )
|
||||
|
||||
@@ -611,7 +611,7 @@ void GAME_EXPORT ID_SetCustomClientID( const char *id )
|
||||
|
||||
void ID_Init( void )
|
||||
{
|
||||
MD5Context_t hash = {0};
|
||||
MD5Context_t hash = { 0 };
|
||||
byte md5[16];
|
||||
int i;
|
||||
|
||||
|
||||
@@ -326,7 +326,7 @@ static int HTTP_FileConnect( httpfile_t *file )
|
||||
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( ));
|
||||
XASH_ENGINE_NAME, XASH_VERSION, Q_buildos( ), Q_buildarch( ), Q_buildnum( ), g_buildcommit );
|
||||
}
|
||||
else Q_strncpy( useragent, http_useragent.string, sizeof( useragent ));
|
||||
|
||||
|
||||
@@ -109,44 +109,44 @@ void Sys_InitLog( void )
|
||||
|
||||
// fit to 80 columns for easier read on standard terminal
|
||||
fputs( "================================================================================\n", s_ld.logfile );
|
||||
fprintf( s_ld.logfile, "%s (%i, %s, %s, %s-%s)\n", s_ld.title, Q_buildnum(), Q_buildcommit(), Q_buildbranch(), Q_buildos(), Q_buildarch());
|
||||
fprintf( s_ld.logfile, "%s (%i, %s, %s, %s-%s)\n", s_ld.title, Q_buildnum(), g_buildcommit, g_buildbranch, Q_buildos(), Q_buildarch());
|
||||
fprintf( s_ld.logfile, "Game started at %s\n", Q_timestamp( TIME_FULL ));
|
||||
fputs( "================================================================================\n", s_ld.logfile );
|
||||
fflush( s_ld.logfile );
|
||||
}
|
||||
}
|
||||
|
||||
void Sys_CloseLog( void )
|
||||
void Sys_CloseLog( const char *finalmsg )
|
||||
{
|
||||
char event_name[64];
|
||||
|
||||
// continue logged
|
||||
switch( host.status )
|
||||
{
|
||||
case HOST_CRASHED:
|
||||
Q_strncpy( event_name, "crashed", sizeof( event_name ));
|
||||
break;
|
||||
case HOST_ERR_FATAL:
|
||||
Q_strncpy( event_name, "stopped with error", sizeof( event_name ));
|
||||
break;
|
||||
default:
|
||||
if( !host.change_game ) Q_strncpy( event_name, "stopped", sizeof( event_name ));
|
||||
else Q_strncpy( event_name, host.finalmsg, sizeof( event_name ));
|
||||
break;
|
||||
}
|
||||
|
||||
Sys_FlushStdout(); // flush to stdout to ensure all data was written
|
||||
|
||||
if( s_ld.logfile )
|
||||
if( !s_ld.logfile )
|
||||
return;
|
||||
|
||||
// continue logged
|
||||
if( !finalmsg )
|
||||
{
|
||||
fputc( '\n', s_ld.logfile );
|
||||
fputs( "================================================================================\n", s_ld.logfile );
|
||||
fprintf( s_ld.logfile, "%s (%i, %s, %s, %s-%s)\n", s_ld.title, Q_buildnum(), Q_buildcommit(), Q_buildbranch(), Q_buildos(), Q_buildarch());
|
||||
fprintf( s_ld.logfile, "Stopped with reason \"%s\" at %s\n", event_name, Q_timestamp( TIME_FULL ));
|
||||
fputs( "================================================================================\n", s_ld.logfile );
|
||||
fclose( s_ld.logfile );
|
||||
s_ld.logfile = NULL;
|
||||
switch( host.status )
|
||||
{
|
||||
case HOST_CRASHED:
|
||||
finalmsg = "crashed";
|
||||
break;
|
||||
case HOST_ERR_FATAL:
|
||||
finalmsg = "stopped with error";
|
||||
break;
|
||||
default:
|
||||
finalmsg = "stopped";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
fputc( '\n', s_ld.logfile );
|
||||
fputs( "================================================================================\n", s_ld.logfile );
|
||||
fprintf( s_ld.logfile, "%s (%i, %s, %s, %s-%s)\n", s_ld.title, Q_buildnum(), g_buildcommit, g_buildbranch, Q_buildos(), Q_buildarch());
|
||||
fprintf( s_ld.logfile, "Stopped with reason \"%s\" at %s\n", finalmsg, Q_timestamp( TIME_FULL ));
|
||||
fputs( "================================================================================\n", s_ld.logfile );
|
||||
fclose( s_ld.logfile );
|
||||
s_ld.logfile = NULL;
|
||||
}
|
||||
|
||||
#if XASH_COLORIZE_CONSOLE
|
||||
|
||||
@@ -420,6 +420,12 @@ void Sys_Error( const char *error, ... )
|
||||
_exit->_Exit->asm._exit->_exit
|
||||
As we do not need atexit(), just throw hidden exception
|
||||
*/
|
||||
|
||||
// Hey, you, making an Emscripten port!
|
||||
// What if we're not supposed to use exit() on Emscripten and instead we should
|
||||
// exit from the main() function? Would this fix this bug? Test this case, pls.
|
||||
#error "Read the comment above"
|
||||
|
||||
#include <emscripten.h>
|
||||
#define exit my_exit
|
||||
void my_exit(int ret)
|
||||
@@ -438,7 +444,11 @@ Sys_Quit
|
||||
void Sys_Quit( const char *reason )
|
||||
{
|
||||
Host_ShutdownWithReason( reason );
|
||||
#if XASH_ANDROID
|
||||
Host_ExitInMain();
|
||||
#else
|
||||
exit( error_on_exit );
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -529,7 +539,7 @@ but since engine will be unloaded during this call
|
||||
it explicitly doesn't use internal allocation or string copy utils
|
||||
==================
|
||||
*/
|
||||
qboolean Sys_NewInstance( const char *gamedir )
|
||||
qboolean Sys_NewInstance( const char *gamedir, const char *finalmsg )
|
||||
{
|
||||
#if XASH_NSWITCH
|
||||
char newargs[4096];
|
||||
@@ -540,7 +550,7 @@ qboolean Sys_NewInstance( const char *gamedir )
|
||||
// just restart the entire thing
|
||||
printf( "envSetNextLoad exe: `%s`\n", exe );
|
||||
printf( "envSetNextLoad argv:\n`%s`\n", newargs );
|
||||
Host_ShutdownWithReason( "changing game" );
|
||||
Host_ShutdownWithReason( finalmsg );
|
||||
envSetNextLoad( exe, newargs );
|
||||
exit( 0 );
|
||||
#else
|
||||
@@ -578,7 +588,7 @@ qboolean Sys_NewInstance( const char *gamedir )
|
||||
#if XASH_PSVITA
|
||||
// under normal circumstances it's always going to be the same path
|
||||
exe = strdup( "app0:/eboot.bin" );
|
||||
Host_ShutdownWithReason( "changing game" );
|
||||
Host_ShutdownWithReason( finalmsg );
|
||||
sceAppMgrLoadExec( exe, newargs, NULL );
|
||||
#else
|
||||
exelen = wai_getExecutablePath( NULL, 0, NULL );
|
||||
@@ -586,7 +596,7 @@ qboolean Sys_NewInstance( const char *gamedir )
|
||||
wai_getExecutablePath( exe, exelen, NULL );
|
||||
exe[exelen] = 0;
|
||||
|
||||
Host_ShutdownWithReason( "changing game" );
|
||||
Host_ShutdownWithReason( finalmsg );
|
||||
|
||||
execv( exe, newargs );
|
||||
#endif
|
||||
|
||||
@@ -56,11 +56,8 @@ void Sys_DebugBreak( void );
|
||||
qboolean _Sys_GetParmFromCmdLine( const char *parm, char *out, size_t size );
|
||||
qboolean Sys_GetIntFromCmdLine( const char *parm, int *out );
|
||||
void Sys_Print( const char *pMsg );
|
||||
void Sys_PrintLog( const char *pMsg );
|
||||
void Sys_InitLog( void );
|
||||
void Sys_CloseLog( void );
|
||||
void Sys_Quit( const char *reason ) NORETURN;
|
||||
qboolean Sys_NewInstance( const char *gamedir );
|
||||
qboolean Sys_NewInstance( const char *gamedir, const char *finalmsg );
|
||||
void *Sys_GetNativeObject( const char *obj );
|
||||
|
||||
//
|
||||
@@ -68,7 +65,7 @@ void *Sys_GetNativeObject( const char *obj );
|
||||
//
|
||||
char *Sys_Input( void );
|
||||
void Sys_DestroyConsole( void );
|
||||
void Sys_CloseLog( void );
|
||||
void Sys_CloseLog( const char *finalmsg );
|
||||
void Sys_InitLog( void );
|
||||
void Sys_PrintLog( const char *pMsg );
|
||||
int Sys_LogFileNo( void );
|
||||
|
||||
@@ -113,7 +113,7 @@ static void Sys_Crash( int signal, siginfo_t *si, void *context)
|
||||
|
||||
// safe actions first, stack and memory may be corrupted
|
||||
len = Q_snprintf( message, sizeof( message ), "Ver: " XASH_ENGINE_NAME " " XASH_VERSION " (build %i-%s, %s-%s)\n",
|
||||
Q_buildnum(), Q_buildcommit(), Q_buildos(), Q_buildarch() );
|
||||
Q_buildnum(), g_buildcommit, Q_buildos(), Q_buildarch() );
|
||||
|
||||
#if !XASH_FREEBSD && !XASH_NETBSD && !XASH_OPENBSD
|
||||
len += Q_snprintf( message + len, sizeof( message ) - len, "Crash: signal %d errno %d with code %d at %p %p\n", signal, si->si_errno, si->si_code, si->si_addr, si->si_ptr );
|
||||
|
||||
@@ -588,7 +588,7 @@ void Wcon_DestroyConsole( void )
|
||||
// last text message into console or log
|
||||
Con_Reportf( "%s: Unloading xash.dll\n", __func__ );
|
||||
|
||||
Sys_CloseLog();
|
||||
Sys_CloseLog( NULL );
|
||||
|
||||
if( !s_wcd.attached )
|
||||
{
|
||||
|
||||
@@ -138,7 +138,7 @@ static void Sys_StackTrace( PEXCEPTION_POINTERS pInfo )
|
||||
#endif
|
||||
|
||||
len = Q_snprintf( message, sizeof( message ), "Ver: " XASH_ENGINE_NAME " " XASH_VERSION " (build %i-%s, %s-%s)\n",
|
||||
Q_buildnum(), Q_buildcommit(), Q_buildos(), Q_buildarch() );
|
||||
Q_buildnum(), g_buildcommit, Q_buildos(), Q_buildarch() );
|
||||
|
||||
len += Q_snprintf( message + len, 1024 - len, "Sys_Crash: address %p, code %p\n",
|
||||
pInfo->ExceptionRecord->ExceptionAddress, (void*)pInfo->ExceptionRecord->ExceptionCode );
|
||||
@@ -213,14 +213,14 @@ static void Sys_GetMinidumpFileName( const char *processName, char *mdmpFileName
|
||||
struct tm *currentLocalTime = localtime( ¤tUtcTime );
|
||||
|
||||
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);
|
||||
processName,
|
||||
g_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)
|
||||
|
||||
@@ -498,10 +498,24 @@ qboolean SV_ProcessUserAgent( netadr_t from, const char *useragent );
|
||||
qboolean SV_InitGame( void );
|
||||
void SV_ActivateServer( int runPhysics );
|
||||
qboolean SV_SpawnServer( const char *server, const char *startspot, qboolean background );
|
||||
model_t *SV_ModelHandle( int modelindex );
|
||||
void SV_DeactivateServer( void );
|
||||
void SV_FreeTestPacket( void );
|
||||
|
||||
/*
|
||||
================
|
||||
SV_ModelHandle
|
||||
|
||||
get model by handle
|
||||
================
|
||||
*/
|
||||
static inline model_t *GAME_EXPORT SV_ModelHandle( int modelindex )
|
||||
{
|
||||
if( modelindex < 0 || modelindex >= MAX_MODELS )
|
||||
return NULL;
|
||||
return sv.models[modelindex];
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// sv_phys.c
|
||||
//
|
||||
@@ -673,7 +687,6 @@ void SV_ClearGameState( void );
|
||||
// sv_pmove.c
|
||||
//
|
||||
void SV_InitClientMove( void );
|
||||
qboolean SV_PlayerIsFrozen( edict_t *pClient );
|
||||
void SV_RunCmd( sv_client_t *cl, usercmd_t *ucmd, int random_seed );
|
||||
|
||||
//
|
||||
|
||||
@@ -477,7 +477,7 @@ static void SV_ConnectClient( netadr_t from )
|
||||
|
||||
// reset stats
|
||||
newcl->next_checkpingtime = -1.0;
|
||||
newcl->packet_loss = 0.0f;
|
||||
newcl->packet_loss = 0;
|
||||
|
||||
// if this was the first client on the server, or the last client
|
||||
// the server can hold, send a heartbeat to the master.
|
||||
@@ -1170,7 +1170,7 @@ SV_EstablishTimeBase
|
||||
Finangles latency and the like.
|
||||
===================
|
||||
*/
|
||||
static void SV_EstablishTimeBase( sv_client_t *cl, usercmd_t *cmds, int dropped, int numbackup, int numcmds )
|
||||
static void SV_EstablishTimeBase( sv_client_t *cl, const usercmd_t *cmds, int dropped, int numbackup, int numcmds )
|
||||
{
|
||||
double runcmd_time = 0.0;
|
||||
int i, cmdnum = dropped;
|
||||
@@ -2226,7 +2226,7 @@ SV_SendBuildInfo_f
|
||||
static qboolean SV_SendBuildInfo_f( sv_client_t *cl )
|
||||
{
|
||||
SV_ClientPrintf( cl, "Server running " XASH_ENGINE_NAME " " XASH_VERSION " (build %i-%s, %s-%s)\n",
|
||||
Q_buildnum(), Q_buildcommit(), Q_buildos(), Q_buildarch() );
|
||||
Q_buildnum(), g_buildcommit, Q_buildos(), Q_buildarch() );
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -3212,6 +3212,20 @@ void SV_ConnectionlessPacket( netadr_t from, sizebuf_t *msg )
|
||||
}
|
||||
}
|
||||
|
||||
static qboolean SV_PlayerIsFrozen( const edict_t *pClient )
|
||||
{
|
||||
if( sv_background_freeze.value && sv.background )
|
||||
return true;
|
||||
|
||||
if( FBitSet( host.features, ENGINE_QUAKE_COMPATIBLE ))
|
||||
return false;
|
||||
|
||||
if( FBitSet( pClient->v.flags, FL_FROZEN ))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
SV_ParseClientMove
|
||||
@@ -3226,29 +3240,20 @@ each of the backup packets.
|
||||
*/
|
||||
static void SV_ParseClientMove( sv_client_t *cl, sizebuf_t *msg )
|
||||
{
|
||||
client_frame_t *frame;
|
||||
int key, size, checksum1, checksum2;
|
||||
int i, numbackup, totalcmds, numcmds;
|
||||
usercmd_t nullcmd, *to, *from;
|
||||
usercmd_t cmds[CMD_BACKUP];
|
||||
float packet_loss;
|
||||
edict_t *player;
|
||||
model_t *model;
|
||||
const usercmd_t nullcmd = { 0 }, *from = &nullcmd; // first cmd are starting from null-compressed usercmd_t
|
||||
client_frame_t *frame = &cl->frames[cl->netchan.incoming_acknowledged & SV_UPDATE_MASK];
|
||||
usercmd_t cmds[CMD_BACKUP] = { 0 }, *to;
|
||||
edict_t *player = cl->edict;
|
||||
model_t *model;
|
||||
|
||||
player = cl->edict;
|
||||
int key = MSG_GetRealBytesRead( msg );
|
||||
int checksum1 = MSG_ReadByte( msg );
|
||||
int packet_loss = MSG_ReadByte( msg );
|
||||
int numbackup = MSG_ReadByte( msg );
|
||||
int numcmds = MSG_ReadByte( msg );
|
||||
int totalcmds = numcmds + numbackup;
|
||||
int i;
|
||||
|
||||
frame = &cl->frames[cl->netchan.incoming_acknowledged & SV_UPDATE_MASK];
|
||||
memset( &nullcmd, 0, sizeof( usercmd_t ));
|
||||
memset( cmds, 0, sizeof( cmds ));
|
||||
|
||||
key = MSG_GetRealBytesRead( msg );
|
||||
checksum1 = MSG_ReadByte( msg );
|
||||
packet_loss = MSG_ReadByte( msg );
|
||||
|
||||
numbackup = MSG_ReadByte( msg );
|
||||
numcmds = MSG_ReadByte( msg );
|
||||
|
||||
totalcmds = numcmds + numbackup;
|
||||
net_drop -= (numcmds - 1);
|
||||
|
||||
if( totalcmds < 0 || totalcmds >= CMD_MASK )
|
||||
@@ -3258,8 +3263,6 @@ static void SV_ParseClientMove( sv_client_t *cl, sizebuf_t *msg )
|
||||
return;
|
||||
}
|
||||
|
||||
from = &nullcmd; // first cmd are starting from null-compressed usercmd_t
|
||||
|
||||
for( i = totalcmds - 1; i >= 0; i-- )
|
||||
{
|
||||
to = &cmds[i];
|
||||
@@ -3270,14 +3273,17 @@ static void SV_ParseClientMove( sv_client_t *cl, sizebuf_t *msg )
|
||||
if( cl->state != cs_spawned )
|
||||
return;
|
||||
|
||||
// if the checksum fails, ignore the rest of the packet
|
||||
size = MSG_GetRealBytesRead( msg ) - key - 1;
|
||||
checksum2 = CRC32_BlockSequence( msg->pData + key + 1, size, cl->netchan.incoming_sequence );
|
||||
|
||||
if( checksum2 != checksum1 )
|
||||
if( !Host_IsLocalClient( ))
|
||||
{
|
||||
Con_Reportf( S_ERROR "%s: failed command checksum for %s (%d != %d)\n", __func__, cl->name, checksum2, checksum1 );
|
||||
return;
|
||||
// if the checksum fails, ignore the rest of the packet
|
||||
int size = MSG_GetRealBytesRead( msg ) - key - 1;
|
||||
int checksum2 = CRC32_BlockSequence( msg->pData + key + 1, size, cl->netchan.incoming_sequence );
|
||||
|
||||
if( checksum2 != checksum1 )
|
||||
{
|
||||
Con_Reportf( S_ERROR "%s: failed command checksum for %s (%d != %d)\n", __func__, cl->name, checksum2, checksum1 );
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
cl->packet_loss = packet_loss;
|
||||
|
||||
@@ -492,14 +492,15 @@ SV_EmitPings
|
||||
*/
|
||||
static void SV_EmitPings( sizebuf_t *msg )
|
||||
{
|
||||
sv_client_t *cl;
|
||||
int packet_loss;
|
||||
int i, ping;
|
||||
sv_client_t *cl;
|
||||
int i;
|
||||
|
||||
MSG_BeginServerCmd( msg, svc_pings );
|
||||
|
||||
for( i = 0, cl = svs.clients; i < svs.maxclients; i++, cl++ )
|
||||
{
|
||||
int packet_loss, ping;
|
||||
|
||||
if( cl->state != cs_spawned )
|
||||
continue;
|
||||
|
||||
|
||||
@@ -273,20 +273,6 @@ int GAME_EXPORT SV_GenericIndex( const char *filename )
|
||||
return i;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
SV_ModelHandle
|
||||
|
||||
get model by handle
|
||||
================
|
||||
*/
|
||||
model_t *GAME_EXPORT SV_ModelHandle( int modelindex )
|
||||
{
|
||||
if( modelindex < 0 || modelindex >= MAX_MODELS )
|
||||
return NULL;
|
||||
return sv.models[modelindex];
|
||||
}
|
||||
|
||||
static resourcetype_t SV_DetermineResourceType( const char *filename )
|
||||
{
|
||||
if( !Q_strncmp( filename, DEFAULT_SOUNDPATH, sizeof( DEFAULT_SOUNDPATH ) - 1 ) && Sound_SupportedFileFormat( COM_FileExtension( filename )))
|
||||
|
||||
@@ -970,7 +970,7 @@ void SV_Init( void )
|
||||
MSG_Init( &net_message, "NetMessage", net_message_buffer, sizeof( net_message_buffer ));
|
||||
|
||||
Q_snprintf( versionString, sizeof( versionString ), XASH_ENGINE_NAME ": " XASH_VERSION "-%s(%s-%s),%i,%i",
|
||||
Q_buildcommit(), Q_buildos(), Q_buildarch(), PROTOCOL_VERSION, Q_buildnum() );
|
||||
g_buildcommit, Q_buildos(), Q_buildarch(), PROTOCOL_VERSION, Q_buildnum() );
|
||||
|
||||
Cvar_FullSet( "sv_version", versionString, FCVAR_READ_ONLY );
|
||||
|
||||
|
||||
@@ -23,19 +23,6 @@ GNU General Public License for more details.
|
||||
static qboolean has_update = false;
|
||||
static void SV_GetTrueOrigin( sv_client_t *cl, int edictnum, vec3_t origin );
|
||||
|
||||
qboolean SV_PlayerIsFrozen( edict_t *pClient )
|
||||
{
|
||||
if( sv_background_freeze.value && sv.background )
|
||||
return true;
|
||||
|
||||
if( FBitSet( host.features, ENGINE_QUAKE_COMPATIBLE ))
|
||||
return false;
|
||||
|
||||
if( FBitSet( pClient->v.flags, FL_FROZEN ))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
void SV_ClipPMoveToEntity( physent_t *pe, const vec3_t start, vec3_t mins, vec3_t maxs, const vec3_t end, pmtrace_t *tr )
|
||||
{
|
||||
Assert( tr != NULL );
|
||||
|
||||
@@ -57,6 +57,12 @@ static qboolean Platform_GetDirectoryCaseSensitivity( const char *dir )
|
||||
{
|
||||
#if XASH_WIN32 || XASH_PSVITA || XASH_NSWITCH
|
||||
return false;
|
||||
#elif XASH_ANDROID
|
||||
// on Android, doing code below causes crash in MediaProviderGoogle.apk!libfuse_jni.so
|
||||
// which in turn makes vold (Android's Volume Daemon) to umount /storage/emulated/0
|
||||
// and because you can't unmount a filesystem when there is file descriptors open
|
||||
// it has no other choice but to terminate and then kill our program
|
||||
return true;
|
||||
#elif XASH_LINUX && defined( FS_IOC_GETFLAGS )
|
||||
int flags = 0;
|
||||
int fd;
|
||||
@@ -66,7 +72,10 @@ static qboolean Platform_GetDirectoryCaseSensitivity( const char *dir )
|
||||
return true;
|
||||
|
||||
if( ioctl( fd, FS_IOC_GETFLAGS, &flags ) < 0 )
|
||||
{
|
||||
close( fd );
|
||||
return true;
|
||||
}
|
||||
|
||||
close( fd );
|
||||
|
||||
|
||||
@@ -529,7 +529,7 @@ static qboolean FS_WriteGameInfo( const char *filepath, gameinfo_t *GameInfo )
|
||||
if( !f )
|
||||
return false;
|
||||
|
||||
FS_Printf( f, "// generated by " XASH_ENGINE_NAME " " XASH_VERSION "-%s (%s-%s)\n\n\n", Q_buildcommit(), Q_buildos(), Q_buildarch() );
|
||||
FS_Printf( f, "// generated by " XASH_ENGINE_NAME " " XASH_VERSION "-%s (%s-%s)\n\n\n", g_buildcommit, Q_buildos(), Q_buildarch() );
|
||||
|
||||
if( COM_CheckStringEmpty( GameInfo->basedir ) )
|
||||
FS_Printf( f, "basedir\t\t\"%s\"\n", GameInfo->basedir );
|
||||
@@ -2705,25 +2705,20 @@ qboolean CRC32_File( dword *crcvalue, const char *filename )
|
||||
qboolean MD5_HashFile( byte digest[16], const char *pszFileName, uint seed[4] )
|
||||
{
|
||||
file_t *file;
|
||||
byte buffer[1024];
|
||||
MD5Context_t MD5_Hash;
|
||||
int bytes;
|
||||
MD5Context_t MD5_Hash = { 0 };
|
||||
|
||||
if(( file = FS_Open( pszFileName, "rb", false )) == NULL )
|
||||
return false;
|
||||
|
||||
memset( &MD5_Hash, 0, sizeof( MD5Context_t ));
|
||||
|
||||
MD5Init( &MD5_Hash );
|
||||
|
||||
if( seed )
|
||||
{
|
||||
MD5Update( &MD5_Hash, (const byte *)seed, 16 );
|
||||
}
|
||||
|
||||
while( 1 )
|
||||
{
|
||||
bytes = FS_Read( file, buffer, sizeof( buffer ));
|
||||
byte buffer[1024];
|
||||
int bytes = FS_Read( file, buffer, sizeof( buffer ));
|
||||
|
||||
if( bytes > 0 )
|
||||
MD5Update( &MD5_Hash, buffer, bytes );
|
||||
|
||||
@@ -239,29 +239,3 @@ const char *Q_buildarch( void )
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
Q_buildcommit
|
||||
|
||||
Returns a short hash of current commit in VCS as string
|
||||
XASH_BUILD_COMMIT must be passed in quotes
|
||||
=============
|
||||
*/
|
||||
const char *Q_buildcommit( void )
|
||||
{
|
||||
return XASH_BUILD_COMMIT;
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
Q_buildbranch
|
||||
|
||||
Returns current branch name in VCS as string
|
||||
XASH_BUILD_BRANCH must be passed in quotes
|
||||
=============
|
||||
*/
|
||||
const char *Q_buildbranch( void )
|
||||
{
|
||||
return XASH_BUILD_BRANCH;
|
||||
}
|
||||
|
||||
|
||||
18
public/build_vcs.c
Normal file
18
public/build_vcs.c
Normal file
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
build_vcs.c - info from VCS
|
||||
Copyright (C) 2025 Alibek Omarov
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
const char *g_buildcommit = XASH_BUILD_COMMIT;
|
||||
const char *g_buildbranch = XASH_BUILD_BRANCH;
|
||||
|
||||
@@ -62,8 +62,8 @@ const char *Q_PlatformStringByID( const int platform );
|
||||
const char *Q_buildos( void );
|
||||
const char *Q_ArchitectureStringByID( const int arch, const uint abi, const int endianness, const qboolean is64 );
|
||||
const char *Q_buildarch( void );
|
||||
const char *Q_buildcommit( void );
|
||||
const char *Q_buildbranch( void );
|
||||
extern const char *g_buildcommit;
|
||||
extern const char *g_buildbranch;
|
||||
|
||||
//
|
||||
// crtlib.c
|
||||
|
||||
@@ -67,8 +67,6 @@ def options(opt):
|
||||
def configure(conf):
|
||||
# private to libpublic
|
||||
conf.load('gitversion')
|
||||
conf.define('XASH_BUILD_COMMIT', conf.env.GIT_VERSION if conf.env.GIT_VERSION else 'unknown-commit')
|
||||
conf.define('XASH_BUILD_BRANCH', conf.env.GIT_BRANCH if conf.env.GIT_BRANCH else 'unknown-branch')
|
||||
conf.env.VALIDATE_TARGET = conf.options.VALIDATE_TARGET
|
||||
|
||||
# need to expose it for everyone using libpublic headers
|
||||
@@ -120,9 +118,14 @@ def build(bld):
|
||||
export_includes = '. ../common ../pm_shared ../engine',
|
||||
export_defines = bld.env.EXPORT_DEFINES_LIST)
|
||||
|
||||
bld.stlib(source = bld.path.ant_glob('*.c'),
|
||||
target = 'public',
|
||||
use = 'sdk_includes werror')
|
||||
# build it separately to slightly improve rebuild times
|
||||
bld.stlib(source = 'build_vcs.c',
|
||||
target = 'build_vcs',
|
||||
defines = ['XASH_BUILD_COMMIT=\"%s\"' % bld.env.GIT_VERSION, 'XASH_BUILD_BRANCH=\"%s\"' % bld.env.GIT_BRANCH])
|
||||
|
||||
bld.stlib(source = bld.path.ant_glob('*.c', excl='build_vcs.c'),
|
||||
target = 'public',
|
||||
use = 'sdk_includes werror build_vcs')
|
||||
|
||||
if bld.env.TESTS:
|
||||
if bld.env.VALIDATE_TARGET:
|
||||
|
||||
@@ -1855,7 +1855,7 @@ typedef struct vbodecaldata_s
|
||||
// gl_decals.c
|
||||
extern decal_t gDecalPool[MAX_RENDER_DECALS];
|
||||
|
||||
struct vbo_static_s
|
||||
static struct vbo_static_s
|
||||
{
|
||||
// quickly free all allocations on map change
|
||||
poolhandle_t mempool;
|
||||
@@ -1891,7 +1891,7 @@ struct vbo_static_s
|
||||
qboolean enabled;
|
||||
} vbos;
|
||||
|
||||
struct multitexturestate_s
|
||||
static struct multitexturestate_s
|
||||
{
|
||||
int tmu_gl; // texture tmu
|
||||
int tmu_dt; // detail tmu
|
||||
|
||||
@@ -11,7 +11,8 @@ fi
|
||||
|
||||
# NOTE: to build with other version use --msvc_version during configuration
|
||||
# NOTE: sometimes you may need to add WinSDK to %PATH%
|
||||
./waf.bat configure -s "SDL2_VC" -T release --enable-utils --enable-tests --enable-lto $AMD64 || die_configure
|
||||
# NOTE: --enable-msvcdeps only used for CI builds, enabling it non-English versions of MSVC causes useless console spam
|
||||
./waf.bat configure -s "SDL2_VC" -T release --enable-utils --enable-tests --enable-lto --enable-msvcdeps $AMD64 || die_configure
|
||||
./waf.bat build || die
|
||||
./waf.bat install --destdir=. || die
|
||||
|
||||
|
||||
4
wscript
4
wscript
@@ -162,6 +162,7 @@ def options(opt):
|
||||
|
||||
# a1ba: special option for me
|
||||
grp.add_option('--debug-all-servers', action='store_true', dest='ALL_SERVERS', default=False, help='')
|
||||
grp.add_option('--enable-msvcdeps', action='store_true', dest='MSVCDEPS', default=False, help='')
|
||||
|
||||
grp = opt.add_option_group('Renderers options')
|
||||
|
||||
@@ -200,6 +201,9 @@ def configure(conf):
|
||||
# Load compilers early
|
||||
conf.load('xshlib xcompile compiler_c compiler_cxx gccdeps')
|
||||
|
||||
if conf.options.MSVCDEPS:
|
||||
conf.load('msvcdeps')
|
||||
|
||||
if conf.options.NSWITCH:
|
||||
conf.load('nswitch')
|
||||
|
||||
|
||||
Reference in New Issue
Block a user