Opening links and files with the `open_link` and `open_file` functions does not work on Android, as the `open_link` function uses `fork` which is not supported on Android. This also seems to cause a strange bug where client networking partially breaks. Currently, after trying to open any link, connecting to servers is not possible anymore but the server browser still works, with the connection getting stuck randomly in the connecting/loading state.
SDL implements URL opening, including of file URIs, with the `SDL_OpenURL` function for most systems including Android. However, using `SDL_OpenURL` for all systems has several downsides:
1. The `SDL_OpenURL` function is only available since SDL 2.0.14, in particular not for the Ubuntu 20 CI runner. Hence, we would either have to conditionally compile the link opening function to a null-implementation or fallback to using the existing `open_link` function.
2. We would be undoing some additional fixes in the `open_link` function for Windows, which are not included in the Windows implementation of `SDL_OpenURL`.
3. This would also replace the use of `open` on UNIX with `xdg-open`.
4. This would move the functionality to open links and files from the base to the engine client, so we could not have tools or the server potentially making use of this functionality in the future (e.g. open a folder for convenience).
Implementing link and file opening for Android ourselves is too much effort and potentially made even harder by SDL already managing all the unique JVM resources in the `SDLActivity`.
Therefore, the `SDL_OpenURL` function is only used for Android, which is always based on the latest SDL2 version. The original `open_link` functionality is kept for the other systems. For this purpose, the `IClient::ViewLink` and `ViewFile` functions are added to wrap `open_link` and `open_file` for the client and also reduce some duplicate code for error logging.
Unfortunately, testing also revealed that `SDL_OpenURL` does not currently support opening file URIs, at least not of files the internal storage location, which all the DDNet client's files would be located in. At least opening URLs works and neither breaks networking anymore.
Scoreboard title
- In teamplay, color the title background red/blue for the respective teams (like in 0.7).
- In teamplay, swap the score location for the blue team, so the scores line up in the center (like in 0.7).
- Use textrender ellipsis instead of cutting the title string manually and potentially creating broken UTF-8.
Game over title
- Render the game over message in the color of the winning team (or yellow in case of draws).
- Adjust size and spacing of the message to prevent overlap.
Player list
- Add player list size variant for 17-24 players with two columns of up to 12 players. This previously used the variant for 32 players.
Goals
- Use textrender for alignment and properly center the time limit goal.
- Change localization text from `Round` to `Round %d/%d` so the numbers and punctuation can be formatted more correctly in some languages (e.g. right-to-left languages, Korean, Chinese).
Spectators
- Render spectators title and spectators starting in the same line to use space more effectively.
- Render as many lines of spectators as fit instead of only 4 lines.
- Render a placeholder text at the end when there are more spectators than fit.
Refactoring
- Use correct class for `NETMSGTYPE_SV_RECORDLEGACY` instead of depending on the structs `CNetMsg_Sv_Record` and `CNetMsg_Sv_RecordLegacy` being identical.
- Use `CUIRect` and `DoLabel` when possible.
Add a question mark-button next to the x-button to open the Wiki page https://wiki.ddnet.org/wiki/Mapping in the default web browser. The link is localized so translators can replace it with the respective translated Wiki pages. The hotkey F1 is also added to activate this button.
Read the entire file into memory immediately when the line reader is initialized instead of using a fixed size buffer of size 32769, which leads to broken line reading for larger files (closes#8431).
Replace the `CLineReader::Init` function with the `CLineReader::OpenFile` function, which additionally checks whether the file contains any null bytes (indicates that the file is likely not a text file).
As the file will be read into memory entirely in the `OpenFile` function, is can also be closed immediately, since using the `io_read_all_str` function should ensure that nothing more can be read from the file. This also simplifies the usage of the `CLineReader` class, as manually closing the file is inconvenient and error-prone. In fact, the file handle for the `ddnet-serverlist-urls.cfg` file was previously not closed properly.
Benchmarking on Windows did not show any noticeable performance impact of this change both for smaller files (config and language files) and larger files (synthetic ~10 MiB files).
Let the `CLineReader::Get` function return `const char *` instead of `char *`, since users of this class should not modify the internal buffer. Also, since the entire file is read into memory now, the returned strings are now valid until the respective line reader object is destructed, instead of only until the `Get` function is called again. This simplifies the usage in some cases where all lines are handled, since additional temporary buffers are now unnecessary.
Remove the `IOFLAG_SKIP_BOM` flag from the `io_open` function, as this flag was only used together with the line reader. This was inconvenient to use, as any use of the `io_open` function specifically for line readers had to be used with `IOFLAG_SKIP_BOM`. Now, the line reader transparently skips the UTF-8 BOM internally. Skipping the UTF-8 BOM never worked with the `IStorage::ReadFileStr` function, because `io_length` is used in the `io_read_all` function, which rewinds the file position to before the UTF-8 BOM that was skipped by using `IOFLAG_SKIP_BOM`. In any case, as the `ReadFileStr` function is currently unused, this has/had no further effect. The respective test cases for `IOFLAG_SKIP_BOM` are removed.
Add more test cases for the `CLineReader` class. All test cases are checked both with and without the UTF-8 BOM. Additional tests with mixed new lines, empty lines with different new lines, and internal null bytes are added.
Consistently use the construct `while(const char *pLine = LineReader.Get())` to iterate over all lines of a line reader. In this case, the assignment inside the `while`-loop seems acceptable over the alternatives, e.g. `while(true)` with `break` or adding a function `CLineReader::ForAll(std::function<const char *> Consumer)`.
Add `sv_dnsbl_ban_reason` config variable with size 128 to specify the ban reason for `sv_dnsbl_ban`.
Increase the maximum size for ban reasons on the server from 64 to 128 to support this new config variable. Adjust buffer sizes for formatting ban messages accordingly.
Additionally, increase the size of the buffer for unpacking the connection closed message from 128 to 256. Due to this limitation, old clients will see truncated disconnect messages if the entire message is longer than 127, which can now happen with long ban reasons as the ban message additionally contains the duration (e.g. `You have been banned for 10 minutes (Reason)`).
Closes#8518.
Get start time as soon as possible and log time for gameclient initialization at the end of the `CGameClient::OnInit` function so this time measurement should cover the entire function.
Use `log_trace` and change spelling for consistency (`initialisation` -> `initialization`).
Avoid duplicate `Localize` calls while loading.
Start component counters at 1 instead of 0 since the value was always incremented by 1 before being used.
Extract variable `NumComponents` and also use it for the special loading message, so it should consistently be shown only for the first component (i.e. the last component being initialized) also when more components will be added.
Use `CUi::RenderProgressBar` function also for client loading, which means the filled progress bar background will also be rendered while loading.
Replace static variable `s_LastLoadRender` with member variable.
Encapsulate menu loading state in class `CLoadingState`.
After starting/stopping the local server from the main menu, refresh the LAN tab on its next activation, so it immediately shows/hides the started/stopped server without needing a manual refresh.
This is not a perfect solution, as the server would not show up when activating the LAN tab immediately after starting the server, because the server needs some time before it will respond to server info requests, but this works well enough unless the hotkeys are used.
When changing `ui_page` via the console while the start menu is active, the browser tab was not refreshed when clicking the Play-button, leading to the old server list being shown for the new browser tab.
Fix map sound loading warning being incorrectly shown when sound is disabled. Make map loading faster in this case by not unpacking the sound data and sound sources from the map at all if sound is disabled.
Closes#8450.
The assertion of #8262 can be reproduced when sound is disabled or failed to be initialized, as the sample indices where not being initialized properly in these cases. It is still necessary to initialized them so sounds can be loaded in the editor also when sound is disabled.
The potential thread-safety issues of the `CSound::AllocSample` function are not yet resolved so the issue remains open.
Avoid the `int Type` parameter by making `CGameConsole::Dump` a member function of `CGameConsole::CInstance`.
Use `log_*` functions instead of `IConsole` for logging.
Instead of relying on SDL to determine when a click is a double-click, implement double-click handling specifically for the UI, as double-clicks are only supposed to be used there. This allows us to ensure that double-clicks only activate UI elements if both clicks were performed on the same UI element. Previously, only the position of the second click was considered, so UI element would incorrectly activate when double-clicking close to them as long as the second click starts and ends on them.
Implementing double-clicking handling separately is also necessary to support double-clicking in the UI with touch events, as SDL does not provide the double-click information for touch events.
The newly added `CUi::DoDoubleClickLogic` function should be called after a UI element has been clicked. It will return `true` if the current click should be interpreted as a double-click, i.e. if the same UI element was clicked, the click was within 0.5 seconds of the previous click (the default duration for SDL and Windows) and the distance from the previous click is within 32 screen pixels (the default distance for SDL).
Only handle the double-click on the envelope editor when the second click is released instead of when it is pressed down already.
Remove unnecessary UI element `s_BoxSelectId`, the temporary activation of which was causing the tooltip to be missing for one frame when clicking the envelope editor.
The `CGameControllerDDRace::HandleCharacterTiles` function can kill the tee if the conditions for starting the race are not satisfied when touching a start tile. In this case, no further tiles should be handled in the `CCharacter::HandleTiles` function, else the effects of those tiles being handled may incorrectly be applied after the tee has respawned.
The ddnet buttons kill and pause do not fit in anymore if there is also
a join red/blue button.
This commit fixes that by hiding the buttons if
there is not enough space anymore.
Related prior work https://github.com/ddnet/ddnet/pull/2720
We assume that `char` is `signed` in various places in the code. In particular, the `Str.StrToInts` test will fail when `char` is not `signed` and names containing special characters will be displayed incorrectly on servers.
Therefore, the compiler flag `-fsigned-char` is set unconditionally instead of only for ARM and ARM64, as we expect `char` to be `signed` on all architectures.
A static assertion is added to ensure at compile time that `char` is `signed` independently from the flag added in `CMakeLists.txt`.
This is necessary at least for ARM, ARM64, PPC, PPC64, and PPC64LE. According to some sources, `char` may also be `unsigned` by default when compiling for Android, although this could not be confirmed with the current Android NDK using Clang.
For the PowerPC architectures, Compiler Explorer can be used to confirm that `char` is not `signed` by default by checking whether the static assertion compiles (see https://godbolt.org/z/9rn5Mrf59) and that the assembly is different with the `-fsigned-char` flag (see https://godbolt.org/z/138zTj3Wa).
Closes#8386.
Fix button logic being stuck when holding mouse button on UI elements with button logic in the menus/editor, switching between menus and editor with Ctrl+Shift+E, then using a UI element with button logic in the editor/menus and switching back.
Fix value selector text mode of color picker popups being deactivated when switching between menus and editor while the color picker popup is open in both.
Only update progress spinners once per frame in `CUi::Update` to ensure consistent rotation speed. Progress spinners in menus and editor now rotate independently.
In general, all `static` non-`const` variables in `CUi` are replaced with member variables, as the `static` variables are shared between the two `CUi` instances of the menus and the editor, causing the above issues.
The percentage of received console commands was not being shown with the progress spinner because the variable `ProgressProps` was not passed to the `RenderProgressSpinner` function.
Replace the last remaining usage of the `CUi::MouseButtonReleased` function with `!MouseButton(...)`. The `pMouseSelection->m_Selecting` flag is only set to `true` when the mouse button is already pressed down, so the additional check of `MouseButtonReleased` is unnecessary in this case. In general, this function is an anti-pattern in our UI, as only checking for the mouse button to be released does not guarantee that the mouse was also pressed down over the respective UI element. The `DoButtonLogic` function or similar code should be used instead of only handling the press or release of a mouse button.
Make value selector behavior consistent with the generic button logic. Consistently check for completed mouse clicks on the value selector UI element instead of handling some mouse down and mouse up events separately. Fix text mode being activated when moving the mouse over value selectors with held down mouse button. Fix text mode being deactivated immediately when the mouse leaves text area while holding down the mouse button, which is inconvenient when selecting text. Remove unnecessary usage of `CUi::MouseButtonReleased` function.
Support double-clicking value selectors to enter text edit mode in addition to right-clicking. This feels more intuitive to use and also makes it usable without a second mouse button.
Select all text when entering text mode also in the editor, which was previously only a feature in the menus.
Fix value selector edit state being `EDITING` by default instead of `NONE` in the editor and fix maps being marked as modified immediately when a value selector text input is activated. The map will now be marked as modified only when the editing operation is completed, which should be synchonized with the undo history action being added.
Use the `CUi::ConsumeHotkey` function instead of checking the enter keys manually.
Remove unnecessary and unused `CUi::m_ValueSelectorTextMode` variable and its accessors as well as the equivalent `s_TextMode` variable in the editor. This separate flag is unnecessary as we can use the existing `s_pLastTextId` variable instead.
The `.demo` extension is supposed to be removed from the target filename when slicing demos, but anything after the last dot was being removed instead, e.g. `test.abc.def` was incorrectly replaced with `test.abc`.
Remove separate handling of UI mouse position and delta in the editor and use the UI directly for this like in the gameclient. Raw cursor movements are redirected to the UI with the `CUi::OnCursorMove` function. The editor separately updates its world positions and delta after the mouse position was changed. The mouse world position for the editor is passed to the UI with the `CUi::Update` funtion as before, whereas the world position is unused in the gameclient.
Use `vec2`s for mouse positions and deltas instead of two separate floats.
Add `IInput::ConsumeEvents` function accepting a consumer `std::function` to replace the duplicate usage of the `IInput::NumEvents`, `IInput::GetEvent` and `IInput::IsEventValid` functions.
Use an `std::vector` to store the current input events to support any number of input events per client update instead of at most 32.
Use full `uint32_t` range for input counter instead of only using the range 0..0xFFFF. If the range is artificially reduced, then this can result in inputs being handled multiple times with high refresh rates, so the increased range should add future proofing for extremely fast devices.
Split `CInput::AddEvent` function into `CInput::AddKeyEvent` and `CInput::AddTextEvent` functions for readability and to make it easier to add additional input events (i.e. touch events).
Ensure double-click state is cleared at the end of each frame to prevent the double-click from being stored when no UI element consumes it.
Move member variables from `IInput` interface to `CInput` implementation.
Remove separate `CEditor::DispatchInputEvents` function.
Currently the per tee demos are only stopped when a character dies.
But the Reset() method in the gameworld destroys characters without
killing them.
This allows to do world resets without calling gamecontext shutdown
while sv_player_demo_record is active. Which is nice for round based
game modes.
```C++
void CGameWorld::Reset()
{
// reset all entities
for(auto *pEnt : m_apFirstEntityTypes)
for(; pEnt;)
{
m_pNextTraverseEntity = pEnt->m_pNextTypeEntity;
pEnt->Reset();
pEnt = m_pNextTraverseEntity;
}
RemoveEntities();
GameServer()->m_pController->OnReset();
RemoveEntities();
m_ResetRequested = false;
GameServer()->CreateAllEntities(false);
}
```
With some languages the buffers for the scoreboard recording notification were not large enough when recording all 4 types of demos at the same time.
Reduce duplicate code. Avoid unnecessary, slow `str_format` for concatenation. Use UI functions for drawing the background and text.
Fix crash when reading a translation file that ends unexpectedly after a context line.
Make error messages about malformed translation files more detailed.
Fix incorrect line numbers in the error message because context lines were not counted.
Use `log_error` for error messages.
Ignore language file config variable being set initially in the conchain (i.e. when `GlobalTime` still returns zero) and check whether the value changed before reloading the language.
```
/home/chiller/Desktop/git/ddnet/src/base/system.cpp:1989:10: error: The 1st argument to 'connect' is < 0 but should be >= 0 [clang-analyzer-unix.StdCLibraryFunctions,-warnings-as-errors]
1989 | return connect(sock->ipv4sock, (struct sockaddr *)&addr, sizeof(addr));
| ^
```
Split the user storage location and the data folder in the app specific external storage in the folders `data` and `user` instead of writing the user setting directly to the external storage.
Remove unnecessary storage permissions. The client only accesses files in its own external storage location, hence these permissions are not necessary for Android API 19 and higher, which is always given as we only target API 19 and higher.
Only unpack changed assets when their hash in the integrity index is different instead of unpacking all assets again, so the app starts faster after updates. Avoid unpacking the entire integrity index file unless it changed, by initially reading only the first hash directly from the asset, so the app starts faster when the data is up-to-date.
Add error handling for external storage not being accessible and other I/O errors during unpacking of assets.
Add `android_main.h` header to export the `InitAndroid` function and potentially other functions in the future. The `extern "C"` and `__attribute__((visibility("default")))` attributes seem to be unnecessary, as this function is only called directly from the native code like many other functions without these attributes.
Initialize the Android storage after the loggers, so the log message are printed properly.
Add documentation for the use of `std::exit` on Android, which is used to forcefully terminate the entire process, to ensure that static variables will be initialized correctly when the app is started again after quitting. Returning from the main function is not enough, as this only results in the native thread terminating, but the Java thread will continue. Java does not support unloading libraries once they have been loaded, so all static variables will not have their expected initial values anymore when the app is started again after quitting.
Use `fs_chdir` and `fs_makedir` instead of `chdir` and `mkdir`.
Remove unnecessary `fs_is_dir` check in the `fs_chdir` function. The `SetCurrentDirectoryW` and `chdir` functions would already include such necessary checks anyway.
Assert that `GetCurrentDirectoryW` was successful instead of logging an error message. This function should only potentially fail if the current working directory was changed by another thread between the two calls, which should not happen in our code.
This would make the function `str_from_int` unnecessary, at least
user-facing.
Advantage: User doesn't have to care about `str_from_int`/`str_format`
distinction.
Disadvantage: We're adding some template programming to `system.h`,
potentially slowing all compilation.
Time score will now always be used for any game with the flag `GAMEINFOFLAG_TIMESCORE` set in the `CNetObj_GameInfoEx` object. If the flag is not set, points score is used instead.
Backwards compatibility for old demos, that were recorded without this net object and flag, is removed. For old demos, points score is always assumed now.
Closes#6700.
This reverts commit caa062c88c.
As this decreased FPS and caused the background quad to be rendered twice when using a map background in entities mode.
Always force landscape orientation to be used for the game on Android.
Hide the title bar so it is not shown when starting the game. There is also a bug with SDL currently that leads to the title bar and status bar being shown permanently after minimizing and reopening the app, which is alleviated by hiding the title bar.
Always use black color to clear the window with all graphics backends, instead of using `cl_background_color` or `cl_background_entities_color`, respectively, as the clear color. The respective map background color is rendered using a quad in `CMapLayers` instead, so this should not affect appearance of maps. This does not have any noticeable effect on FPS. Previously, the unused part of the window (when it is resized smaller than 5:4 aspect ratio), was colored using the map background color, whereas now it will be cleared black consistently.
The color parameters of the `IGraphics::Clear` function and of the `SCommand_Clear` command are removed, as we always expect the screen to be cleared black now.
The parameter `ForceClearNow` of the `IGraphics::Clear` function was already unused previously and is also removed.
Interpret fast repeated presses of the back-button (3 times within 1 second) as a quit-event, so the app can be quit cleanly and quickly without using the UI. The client settings are otherwise not saved if the app is closed by minimizing it using the home button and waiting for the OS to kill it or by discarding it in the recent apps view.
Translate the Android back-button to the escape-key, so it can be used to navigate back in menus, open/close the ingame menu, close the editor etc.
Trap the Android back button by setting the `SDL_ANDROID_TRAP_BACK_BUTTON` hint, so it can be handled in our code reliably instead of letting the system handle it.
The graphics backends only support the RGBA format with the `SCommand_Texture_Create` and `SCommand_Texture_Update` commands, so the `TexFormatToOpenGLFormat`, `TextureFormatToVulkanFormat` and `TexFormatToNewOpenGLFormat` functions and the command member variables for the format are unnecessary. The `TexFormatToNewOpenGLFormat` function was unused.
Fix edit boxes, scrollbars, value selectors and the editor sound seekbar being activated by holding the left mouse button from outside the UI element and then hovering it, which is inconsistent with the behavior of the `DoButtonLogic` function.
Use the `DoButtonLogic` function directly for the key reader buttons in the controls settings. Now, the key reader will only be activated when the left click is initiated and completed inside the key reader button. Previously, the key reader would be activated immediately when holding the left mouse button from outside and then hovering the key reader, and the key reader was already activated by the press-event, whereas now it will only be activated by the release event of the left mouse button. The active key reader UI ID is now tracked as a member variable of `CMenusKeyBinder` to avoid using static variables for this purpose.
The scrollregion scrollbar was not being deactivated if the handle is continued to be hovered after releasing it, causing the handle to become offset with the position of the click on the next activation of the handle.
The seekbar is immediately activated if the mouse button is held while moving the mouse over the seekbar, which is inconsistent with the general `DoButtonLogic` behavior. This is problematic on Android, where the first mouse button is always pressed while the mouse is being moved, causing the seekbar to steal focus immediately when hovered.
The tooltip was not shown if the seekbar is the active item, i.e. when the first mouse button is held down and the seekbar is currently updating the demo player.
Assume every server that does not have ddnet or race in its gametype to be a pvp server.
This allows spectators to follow multiple players during a fng/ctf/gctf/ictf round.
Related issue #7509
The `-1` in the size calculation for the ringbuffer allocation of chat history entries was incorrect, so the entries potentially didn't fit the zero terminator. Because `mem_copy` was used, the string was also not zero terminated explicitly.
This reverts commit f319ed239a.
Initializing these variables with junk data doesn't seem to be an
improvement over not initializing them. It hides potential Valgrind
warnings about data accesses to uninitialized memory though.
f319ed239a (r1590801501)
Nudge the initial position for explosions' smoke particles slightly towards the edge of the closest non-solid tile, if it would otherwise be inside a solid tile, so the smoke particles do not get stuck inside solid tiles on explosion events happening at the edges of tiles but slightly inside them. The physical position of the explosion event is unchanged, so this does not affect physics. The explosion sprite is still rendered at the physical position of the explosion, to preserve the apprearance.
Add additional checks to ensure that the `CVideo::Stop` function and the functions called by it will correctly stop the current video also if the video was not started successfully, i.e. if `CVideo::Start` returned `false` from any of the error branches.
In the `CVideo::Stop` function, iterate over the vectors of video and audio threads directly instead of using `m_VideoThreads` and `m_AudioThreads`, which do not reflect the actual count if the initialization failed before the threads were created.
In the `CVideo::Stop` function, only call `av_write_trailer` if the video recording was stated successfully, i.e. only if `avformat_write_header` was called successfully, as this will otherwise cause the client to crash. Closes#6375.
In the `CVideo::Stop` function, only call `avio_closep` if the format context was allocated.
In the `CVideo::FinishFrames` function, ensure that the codec has been allocated and opened, otherwise using it is not allowed.
Add assertions to the `CVideo::Start` and `Stop` functions to ensure that the same video is not started/stopped multiple times.
Crash with assertion when the size of the graphics is different from the video currently being rendered, instead of causing weirder bugs and a corrupted video file.
The wrong sampling rate was being used for video recording if the client is not restarted after changing the `snd_rate` config variable.
Ensure that the correct bit rate is used if the sample rate was adjusted because the selected value is not supposed.
Use `log_error` for all errors and consistently format all error messages.
Handle all ffmpeg errors and output the formatted ffmpeg error message when possible.
Register a log callback for ffmpeg log messages to delegate them to our logging system, to fix the log messages being interleaved with our log messages and not using the correct line breaks on Windows.
Stop video and demo immediately and show an error message popup if the video could not be started successfully.
Remove unnecessary debug output from ffmpeg.
Removed member prefix m_ used for local variables.
Removed all b, c, i hungarian notation prefixes for boolean, const and integers.
Fixed local variables using lower_snake_case instead of UpperCamelCase.
Renamed all ``float wSearch = TextRender()->TextWidth..`` to ``float SearchWidth = ..``.
When using the `remove_vote` command, the entire heap of vote options is allocated again without the entry being removed. This allocation was not considering the required alignment for `CVoteOptionServer` objects and potentially wasting space by aligning with `alignof(std::max_align_t)`. When allocating the entries with the `add_vote` command, the alignment is already specified correctly.
Relevant upstream commit:
d2924b5ad6
Closes https://github.com/ChillerDragon/ddnet/issues/7
The snap item obj_character contains a field called m_TriggeredEvents
https://chillerdragon.github.io/teeworlds-protocol/07/snap_items.html#obj_character
It is responsible for effects and sounds. Those flags are set in the gamecore.
So if the servers gamecore ticks twice and resets the flags before a snap is
sent the client misses the information. Which is not too big of a
problem since the client has his own gamecore running (prediction) which
also sets those flags. But it is still wrong and teeworlds does always
include the triggered events in the snap.
So this commit fixes it using the same approach as teeworlds.
By not resetting the triggered events until a snap was sent.
Always use the server address from the network client to reconnect to the correct server after being disconnected due to wrong password. The password popup is only shown after being disconnected, so the server address of the network client should always the address of the server which the client should reconnect to with the password. Using `ui_server_address` was causing the wrong address to be used after being redirected to another server and if the config variable is changed while the password popup is open.
Closes#8260.
Fix leak of pending future logger log messages if the future logger is not set, in particular when the `logfile` config variable is not set or the file could not be opened, by setting a logger that discards all log messages in this case.
Closes#8265.
When changing the screen width, height or refresh rate config variables to 0 or negative values, which are not allowed by the backend, automatically revert the config variables to the actual values again to ensure that the config variables stay in sync with the state of the window. This fixes the client crashing in the graphics settings when setting the screen width and height to 0 via the console, which causes a division by zero when calculating the aspect ratio.
According to the documentation, this function returns `0` on success and a negative number (error code) otherwise, which would cause an allocation of an invalid size.
The third parameter of the `op_read` function specifies the remaining size of the buffer, but we always passed the total size of the buffer without respecting the position at which the data is written into the buffer.
Set the data pointer of the sample only when the sample has been loaded successfully, so the invalid sample data is not freed again when decoding fails.
Otherwise the snapshots may incorrectly be invalidated because a change of the `cl_dummy` variable is detected when connecting to another server after disconnecting while the dummy is active.
Send dummy ready and enter game when connection is online based on its state instead of when the security token is not unknown anymore, which should effectively be the same condition but more understandable. This is also how it's already done for the main connection so the `SecurityTokenUnknown` function can be removed as it's unused now.
The console was not keeping its current scoll position if entries from the backlog are removed due to being recycled when new entries are added. For this purpose, a callback function is added to the ringbuffer to handle popped items, so the scrolling position of the console can be updated based on the number of lines of the removed backlog entries.
Fix backlog corruption in `CConsole::PumpBacklogPending` when many backlog entries are allocated at the same time. When allocating many entries from the `m_Backlog` ringbuffer at the same time, the first entries being allocated may already have been recycled again, so the pointers to them being stored in the temporary vector of new backlog entries were pointing arbitrarily into the ringbuffer data, which could cause corruption of the structural and user data of the ringbuffer. Now, we iterate over the entire backlog and only update uninitialized entries instead of storing the new entries separately.
This was sometimes caught as a misaligned access with UBSan:
```
src/engine/shared/ringbuffer.cpp:160:14: runtime error: member access within misaligned address 0x00014126f4df for type 'struct CItem', which requires 8 byte alignment
0x00014126f4df: note: pointer points here
<memory cannot be printed>
0 0x5825349a6a1c in CRingBufferBase::Prev(void*) src/engine/shared/ringbuffer.cpp:160
1 0x5825334e8934 in CTypedRingBuffer<CGameConsole::CInstance::CBacklogEntry>::Prev(CGameConsole::CInstance::CBacklogEntry*) src/engine/shared/ringbuffer.h:59
2 0x5825334d13e6 in CGameConsole::OnRender() src/game/client/components/console.cpp:1259
3 0x582533bce058 in CGameClient::OnRender() src/game/client/gameclient.cpp:715
4 0x582532f3cc44 in CClient::Render() src/engine/client/client.cpp:894
5 0x582532f9d236 in CClient::Run() src/engine/client/client.cpp:2971
6 0x582533002e5e in main src/engine/client/client.cpp:4523
```
Fix out-of-bounds accesses when rendering ghost players, which use the client ID `-2`. This was causing the hook collision line of ghost players to be affected by real players, which is not correct, as ghosts do not interact with other characters.
Closes#8239.
Add optional filename argument to `start_video` command, to start recording to a video file with a specific filename, instead of always using the current timestamp.
Add log messages to `start_video` and `stop_video` commands to indicate success and errors.
Make the `CClient::StartVideo` function non-`static` and reduce duplicate code in the `Con_StartVideo` function.
Determine the video filename outside of the `CVideo` constructor, same as for demos.
Fix game times and prediction not being updated when only exactly two snapshots have been received, due to the conditions `m_aReceivedSnapshots[...] >= 3`. These specific condition are not necessary and replaced with simpler checks whether the current snapshot is set. Some duplicate nested conditions are also removed.
Pump the network first in `CClient::Update` before updating anything else, to ensure that snapshots are received from the network client before the game times and prediction are being updated based on the current snapshots.
Fix current and previous game tick always being `0` on the first call of `IGameClient::OnNewSnapshot` when two snapshot have been received. Now, the game ticks are properly initialized from the two initial snapshots.
Fix old inputs sometimes being used in prediction after changing map because inputs with tick `-1` were not being ignored.
Ensure all snapshots and game times are properly cleared when entering the game.
`GetConsoleMode` can fail with `ERROR_INVALID_HANDLE` when redirecting output to `nul`, which is considered a character file but cannot be used as a console.
The purpose of this condition is to only update the freeze time every 50 ticks so the freeze bar keeps being refilled after one second when standing in freeze, but it incorrectly prevented freeze from being applied during the first 50 ticks after the map has been loaded. Now, freeze is also applied if not currently frozen, so the behavior directly after changing the map is identical to subsequent respawns.
Clear current server info when playing demos to ensure that the score kind (points, time) is detected correctly. Previously, when playing a demo with points score kind and `cl_demo_assume_race 0`, the score was not shown as points when the last server that the client connected to had a race gametype.
Move the implementation for `cl_demo_assume_race` together with the rest of the demo server info initialization in the `CClient::DemoPlayer_Play` function.
The demo player needs to be rendered also when the menu is inactive, to handle the hotkeys for controlling the demo player and to render the play/pause and speed indicators.
Closes#8208.
These conditions are contained in an `if(State() == IClient::STATE_ONLINE)` branch and the state does not change while inside this branch, so these checks are unnecessary.
Previously, when connecting to servers repeatedly, the local tee would appear at the position it had on the previous server for a short time when joining.
This (and potentially other bugs) are fixed by clearing all game related `CGameClient` member variables in the `OnReset` function. Additionally, the `OnReset` function is now used in the `OnInit` function to ensure everything is initialized correctly when starting the client and to avoid duplicating the code.
In particular, this bug was limited to use of `cl_predict 1`, because the predicted gameworlds were not being reset when disconnecting, causing the predicted world and character from the previous server to be used. This bug was introduced in version 15.6, which added the predicted gameworlds in #1620. Closes#4339.
For the internet/favorite tabs, instead of combining the country/type filters of all communities in one view, track the country/type filters separately for these tabs using the new, reserved community name `all`. This should make the filters less confusing to use, as changing the country/type filters in one tab will not influence the other tabs anymore. Though the country/type filters of the internet and favorite tabs are still combined, as this is also the case for the community filter.
However, this made it possible to select country/type filters that exclude all servers, by first excluding some countries/types and then changing the selected communities so all selectable countries/types are excluded. To prevent this, the filters will now include all countries/types, if they would otherwise exclude all selectable countries/types.
To do this more efficiently, the community cache is moved from the menus to the engine serverbrowser. To avoid using the UI page in the engine serverbrowser, the serverbrowser type is instead used to detect if the community cache should be updated. This required additional changes in the menus to ensure that the UI page and the serverbrowser type stay in sync with each other, which would otherwise cause incorrect server entries to be shown for one frame when switching tabs. The serverbrowser type is now refreshed immediately when the menu page is changed with the `CMenus::SetMenuPage` function, which allowed removing duplicate code for the server browser tab buttons. The `CMenus::RefreshBrowserTab` function does not take the page to be refreshed as argument anymore, as it always was only used to refresh the current page. Instead, a `bool` argument is used to specify whether the refresh should be forced even if the server browser type has not changed.
Closes#8158.
Adding the snap to the demo is the last usage of `pTmpBuffer3`
all prior usages of it copy the data if needed.
So we can edit it in place. No need to copy it into a new buffer.
Remove unnecessary, inconsistent margin at the top of all settings menus.
Reserve space for restart message and button only when necessary, so more height is available for settings menus per default.
Improve vertical alignment of restart message and button with settings menus.
Ensure consistent margin on all sides of settings menus.
Use consistent margins for all settings pages and titles.
Fix chat preview overlapping with the restart warning.
Simplify layout code. Remove array of `CButtonContainer`s with arbitrary size and use individual variables instead.
Simply hide the favorite community tabs in the offline server browser with screen resolutions where not enough width is available.
The ingame server browser can always show at least 5 favorite community tabs with all screen resolutions.
Skip rendering various client components (players, ghosts, nameplates, HUD etc.) while not ingame to improve performance. This increases FPS when rendering the start menu by around 300-400 both in debug and release builds.
This also fixes potential crashes when components using the map data where rendered while the client is loading a new map.
The rcon username requirement was not reset correctly when disconnecting from a server while connecting/loading, at which point the `NETMSG_RCONTYPE` message has already been received.
Closes#4170.