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 = ..``.
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.
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.
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.
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.
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.
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.
Pass `CImageInfo` arguments to various graphics and text render functions instead of passing the components (data pointer, width, height, format/pixel size) of the image info separately.
Pass texture/file name to loading functions when available to improve error/warning messages.
Invalid UTF-8 will not be read from config files with `CLineReader` anymore and the local console never allowed entering invalid UTF-8, so this additional mangling of invalid UTF-8 string config variable values is unnecessary.
The engine graphics do not need to be involved with freeing image data.
The `Free` function now also ensures that all other member variables are cleared when freeing the image data.
The `unknown address` log message got printed very often because many servers have 0.6 and 0.7 addresses but only 0.6 addresses are considered valid by the client.
`CNetConsole` will now ignore received lines containing invalid UTF-8 codepoints. Previously, it was possible to crash the server on Windows with Econ commands like `exec <invalid UTF-8>`.
Previously, usage of `void *`, `unsigned char *` and `uint8_t *` was mixed in various places for pointers to raw image data and the pointers ended up being cast to `uint8_t *` at some point anyway. Now only `uint8_t *` is used consistently, which improves type safety and readability. Casts to `uint8_t *` are now only necessary when using `malloc` or when reading data from a map.
We want to change the state of the job from `STATE_QUEUED` to
`STATE_RUNNING`, but not from `STATE_ABORTED`. Previously, the code
usedd `exchange` to change the state and compared non-atomically
afterwards. This led to `STATE_ABORTED` being replaced by
`STATE_RUNNING` in a race. With `compare_exchange_strong`, this can no
longer happen.
Fixes#8044.
Fix HTTP client effectively shutting down by entering the `ERROR` state when a request cannot be added. Now only the invalid request is aborted immediately. The `ERROR` state is now only entered when a curl function fails in a way where recovery is not possible.
Fix occasional deadlock when HTTP client is shutting down after entering the `ERROR` state, by also immediately aborting new requests when the HTTP client is already in the `ERROR` state.
Remove unused `CHttp::EState::STOPPING`.
When image blitting is supported by the Vulkan backend, the color picker was reading incorrect pixel values, because the offset positions for the blitting region are the positions of the top-left and bottom-right corners, but instead the top-left offset and size (width, height) were passed as arguments.
Closes#8040.
Instead of defining the macro `WIN32_LEAN_AND_MEAN` and sometimes also the macro `_WIN32_WINNT` in each file that directly or indirectly includes `<windows.h>`, only define these macros once consistently in `CMakeLists.txt`.
Also define `NTDDI_VERSION`, which is the new macro to specify the minimum Windows version starting with Windows Vista. This macro needs to be defined in addition to old `_WIN32_WINNT` macro, according to the documentation.
See https://learn.microsoft.com/en-us/windows/win32/winprog/using-the-windows-headers
Add `IJob::Abortable(bool)` function which jobs can call to specify whether they can be aborted. Jobs are not abortable per default. Abortable jobs may have their state set to `IJob::STATE_ABORTED` at any point if the job was aborted. The job state should be checked periodically in the `IJob::Run` function and the job should terminate at the earliest, safe opportunity when aborted. Scheduled jobs which are not abortable are guaranteed to fully complete before the job pool is shut down. However, if the job pool is already shutting down, no additional jobs will be enqueue anymore and abortable jobs will immediately be aborted.
In particular, the sound loading, community icon loading, master chooser and host lookup jobs are specified as being abortable. Conversely, the jobs saving replay demos, editor maps and screenshots are expected to finish before the client is shut down.
When the client is quitting/restarting, it will now disconnect from the current server first, before saving the config, to ensure that any actions that happen on disconnect (demo recorders being stopped etc.) happen first. The shutdown message is rendered before disconnecting and waiting for background jobs to finish.
The HTTP client is now initialized later during server launch, after the network initialization. Error handling is added and the server stops if the HTTP client could not be initialized, same as the client.
The `RunBlocking` functions are removed, as they are not used anymore after curl-multi was added.
The function `IJob::Status` is renamed to `State` and `IJob::STATE_PENDING` is renamed to `STATE_QUEUED` for consistency with naming of the HTTP client.
The member variables of the engine interface are encapsulated and the `jobs.h` include is removed from `engine.h`, which removes transitive includes of `system.h`.
Documentation for all job and job pool API is added.
Matching the requester allows "reliable" and "unreliable" pings.
"Reliable" pings suffer from re-sends, thus might not accurately reflect
the latency, "unreliable" pings might not arrive at all.
Add mandatory Boolean attribute `has_finishes` to every community info, which specifies whether finishes can be shown for the community, regardless of whether any finishes are currently available for the player.
The community info must be adjusted when/before merging this, by adding the attribute `has_finishes` to every community object, with the value `true` for DDNet and `false` for all other communities.
Closes#7957.
Immediately cancel new HTTP requests instead of enqueuing them when already shutting down `CHttp`. Otherwise, `CChooseMaster` may wait forever for HTTP requests to be completed while the client is shutting down, if `CHttp` was shutdown while `CChooseMaster` is not waiting for an existing HTTP request.
Not directly caused by #7962, but it made it more likely to happen.
Closes#7980.
Instead of sending the message from the first client which is not ingame, choose the first client which is fully empty, to make it less likely that the message is sent from a currently connecting client.
Add a country "none" with tee flag (code `-1`) and a type "None" for all servers without community.
Previously, the country and type for these servers was unset and their handling special-cased, so any non-empty country/type filter would exclude servers without country/type information. Now individual countries/types can be excluded without also excluding all servers without community.
Closes#7961.
Shutdown `CHttp`, i.e. abort all HTTP requests, as early as possible when quitting/restarting the client, after the config has been saved but before shutting down the gameclient. Previously, this was delayed until the engine shutdown, so the requests would often finish entirely instead of being aborted by the callback.
Previously, HTTP requests being aborted due to `CHttp` shutting down were considered `EHttpState::ERROR`, which sometimes causes deadlocks during engine shutdown or destruction of `CHttp`. The state is now set to `ABORTED` by passing `CURLE_ABORTED_BY_CALLBACK` to `OnCompletionInternal`. The otherwise unused handling of internal errors is removed.
Previously, it was assumed `ResultJson` would return `nullptr` for HTTP requests which have been aborted or failed with an error, which would trigger the newly added assertion error "Request not done".
Instead of preventing the client from quitting/restarting while a warning is shown in the menus, add warnings that should be shown after quitting/restarting (i.e. the warning when the config could not be saved) to a separate list and show these warnings using an OS message box after the client has been closed. Otherwise, the client is prevented from closing if a warning is shown without being automatically hidden, which causes the client to hang indefinitely in the CI.
The message boxes for warnings must be shown after the client has already been completely shutdown, otherwise the regular shutdown with the Vulkan backend crashes because showing the message box has already partially deinitialized the backend.
The quitting/restarting client state is now checked after updating the FIFO component, so quitting/restarting initiated via FIFO is effective immediately, although this should have little effect in practice.
For completeness, a log message is added also for the case that the config was saved successfully.
The GitHub CI seems to automatically confirm/disable OS message boxes, so they should not block workflows.
Add assertions to ensure that the HTTP request result data and SHA256 are available when getting them instead of returning `nullptr` and `SHA256_ZEROED` when they are not.
Rename `CHttpRequest::Sha256` function to `ResultSha256`.
Because of incorrect index/size math, two favorite communities were removed when exceeding the maximum number of three favorite communities instead of only one. The check can be simplified because the maximum number of favorite communities can never be exceeded, so at most the first element needs to be removed from the vector.
Closes#7935.
Avoid many writes to disk each time the DDNet info is downloaded, i.e. each time the refresh button is pressed in the server browser, by first loading the DDNet info into memory and only writing it to disk when it differs from the current DDNet info based on the SHA256 hash.
The SHA256 is now also used to track whether the DDNet info was modified for the community filters and icons instead of using the current time for this purpose.
Closes#3941.
Initialize the HTTP client (start the HTTP thread) after initializing the network client instead of during the client interface construction. This ensures that config variables have been loaded already and the log output level is set correctly. This also means all library initialization log messages appear together in one block when starting the client.
Show an error message box and stop launching when the HTTP client could not be initialized, instead of launching but not being able to perform any HTTP requests, which causes bug reports about the serverlist being empty.
Both console and chat commands are sent to clients dynamically with respective messages, so the static lists of commands were only used for servers not making use of these messages. Instead of assuming potentially incorrect console and chat commands on those servers, the lists will now be empty for those servers.
Move the command registration from the `ddracecommands.h` and `ddracechat.h` header files to the `CGameContext::RegisterDDRaceCommands` and `CGameContext::RegisterChatCommands` functions and delete the header files. The `CHAT_COMMAND` and `CONSOLE_COMMAND` macros are removed, because they only add unnecessary indirection now. The strings `CHAT_COMMAND` and `CONSOLE_COMMAND` are simply replaced with `Console()->Register` and semicolons are added at the end of the lines.
Closes#7665.
Support adding up to three communities as favorites in the server browser. Favorites can be changed with favorite buttons which are shown in the community filter on the Internet and Favorites tabs. The commands `add_favorite_community` and `remove_favorite_community` are added to change the favorite communities via the console and for saving the favorite communities to the config file. For the favorite communities, additional tabs using the communities' icons are shown in the server browser next to the Internet, LAN and Favorites tabs. Each community tab shows only the servers from the respective community, hence the community filters UI is not shown on the community tabs but only on the Internet and Favorites tabs. The country and type filters on community tabs cover only the countries and types from the respective community. Favorite communities are added from left to right. When more than three favorite communities are added, the oldest (leftmost) favorite community will be removed from the list.
When starting the client for the first time, i.e. with `cl_show_welcome 1`, the DDNet tab will be created as the only favorite community and selected initially. The community, country and type filters are unset when starting for the first time, so the Internet tab now shows all servers per default.
When starting with a `ui_page` for a favorite community that is not configured, the page is reset to the Internet tab. This also affects those who upgrade from versions with the old DDNet and KoG tabs. The server browser is now also correctly updated when changing `ui_page` via the console.
Track country and type filters for every community separately, to avoid filters resetting when switching between community tabs or changing the community filter. The commands `add_excluded_community`, `remove_excluded_community`, `add_excluded_country`, `remove_excluded_country`, `add_excluded_type` and `remove_excluded_type` are added to change the exclusion filters via the console and for saving the exclusion filters to the config file.
Render community filters above the toolbox (filter, info and friends) tabs when on the Internet and Favorites tab, so this setting is more visible and can be changed also when the other toolbox tabs are selected.
Add icon for the none community, based on the tee country flag color. This icon is hard-coded in the client, as the none community also is, so fetching the icon from the server would be inconvenient. Load community icons already when rendering the menu instead of only when rendering the server browser, so the icons are immediately available when using the start menu.
Find tutorial server by searching for community type "Tutorial" instead of searching for "(Tutorial)" in the server name.
Avoid cleaning favorite communities and filters when there are no communities, i.e. when the DDNet info failed to be loaded or does not contain any communities, to avoid losing all favorite communities and filters in this case.
Closes#7774.
When empty PNG files are loaded, the `std::vector` for the file contents is resized to size 0, which results in undefined behavior when it is accessed with `front`.
When `io_tell` fails, i.e. returns `-1`, this was incorrectly cast to an `unsigned` and therefore caused a very large allocation and potentially crashes due to lack of memory.
Use error log level for error messages. Use info log level explicitly instead of using `dbg_msg`.
Log time taken for initialization in trace level message.
Add parameter to `shell_execute` to either start the process in the foreground or background on Windows. Previously, all processes were started in the background, because this is desired when starting the server from the client. However, this causes the graphics initialization to fail when restarting the client after updating or with the `restart` command when using Vulkan with windowed and windowed fullscreen mode.
Closes#6578.
The `bool AllowResizing` parameter is only passed to other `SetWindowParams` functions but never used in the end, as whether or not resizing is allowed is separately determined based on the value of the `int FullscreenMode` parameter.
Instead of cleaning the countries/types filters based on all available communities' countries/types, only consider the countries/types of currently selected communities. Ensure countries/types are always cleaned when updating the server browser filter in the UI. This fixes that countries/types which are not available for the selected communities were still affecting the server filtering, causing no servers to be shown in some cases.
Closes#7847.
To simplify the usage of the demo recorder, parameters are added to the `IDemoRecorder::Stop` function to control whether the demo file is removed or renamed when stopping the recording.
Ensure demo files of the replay recorder are always removed (except on crashes). The temporary replay demos were previously not removed when being disconnected from a server.
Fix auto demos being stopped and restarted when enabling replays in the settings menu. Now only the replay recorder is stopped/started when necessary.
Fix replay recorder being restarted when setting `cl_replay` variable with console without changing the value.
Remove unnecessary `CClient::m_ButtonRender` variable. Demo rendering is already stopped correctly when reaching the end of the demo without this additional variable.
Remove unused `CDemoRecorder::m_pMapData` variable.
Ensure that the `CHttpRequest::OnCompletion` function has finished before updating the state which is visible to other threads. Otherwise, threads may try to access the result of a completed HTTP request, before the result has been initialized/updated in the `OnCompletion` function.
Fixes warning due to invalid texture width/height being shown for downloaded skins, because the texture was loaded before the image data was initialized. Closes#7818.
Regression from #7683. Before this, the `OnCompletion` function could also modify the HTTP request's state, which was used to check if loading the skin PNG failed. Instead of doing this, a separate check is added for the skin download task to check that the PNG was loaded successfully.
Store X value (time) for all graph entries in addition to the Y value (FPS, prediction margin etc.). The `CGraph::Add` function adds values to the graph at the current time. The `CGraph::InsertAt` function allows specifying arbitrary X values, as long as the values are inserted in increasing order.
The entries are kept in a ringbuffer and old entries are recycled when it's full. The size of the ringbuffer is configurable for each graph, as the FPS graph needs significantly more buffer because values are added more often.
The scrolling speed of the graphs is fixed by specifying the maximum size of the window of values which should be displayed. For this purpose, a parameter is added to the `CGraph::Scale` function to specify the size of the window which should be rendered in the `CGraph::Render` function. For the FPS graph only the last second is rendered, so small spikes are still noticeable. For prediction and gametime margin graphs the last five seconds are rendered, which should result in a similar scrolling speed as before this change. The debug tuning graph is a special case, where the X values set manually and fixed to 0-127, same as before, instead of being based on the current time.
The graph rendering is made much more efficient by precalculating when the vertex colors need to be updated, to avoid all unnecessary calls to `SetColorVertex`. Additionally, line items are bundled together in an array to avoid calling `LinesDraw` for every individual line item.
The `CTextCursor::m_LineCount` variable is only updated after the cursor is rendered. For calculating the selection quads we need to check `LineCount` instead, which is updated while the cursor is being rendered. Regression from #7733.
Free up space for up to three more server browser tabs of the same size (on 5:4 resolutions), i.e. tabs for configurable communities.
Remove the additional server browser icon tab on the right side. Remove the purely visual Demo and News tabs which were only shown when the respective page is already active. Instead, always show all server browser tabs when offline.