Add strict validation for `StrToInts` function. Because this function should only be used with trusted internal strings, assertions are added to ensure that the string is not truncated. Some buffer sizes are adjusted accordingly, so truncation cannot happen.
Add less strict validation for `IntsToStr` function. An additional argument specifying the size of the output buffer is added to assert that the size of the output buffer is sufficient. However, because this function is used to decode data sent by the server and read from maps and ghosts, invalid input data should never result in crashes or invalid UTF-8 strings. The function will now unpack an empty string and return `false`, if the string contains invalid UTF-8.
The inline definition of the functions is not wanted, because it requires adding a `system.h` include in `gamecore.h`. Therefore the tools now have to depend on game-shared, which previously only worked because the functions were inline.
Tests are added to ensure the function still behaves the same as before for valid inputs and correctly handles invalid inputs.
`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.
Show completion options for key names for all bind commands (`bind`, `binds`, `bind_reset`) in the local console.
At the moment this only works for completing the first key name but not for composite binds that use `+`, which would work differently than other console argument completion.
Unnamed keys (starting with `&`) are not shown as completion options.
Refactor console argument completion to reduce duplicate code.
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`.
Prevent the `tune_zone` command from being shown and used in the local console, which could cause issues with prediction, by only registering it as a game setting but not as a client command. The command callback is still correctly called when map settings are loaded in the `CGameClient::LoadMapSettings` function.
Previously:
```
2024-03-03 12:17:40 I git-revision: 885ae7ecae
2024-03-03 12:17:40 I server: version 18.0.3 on linux amd64
2024-03-03 12:17:40 I server: git revision hash: 885ae7ecae
```
The color selection should only be shown for normal envelope points but not for bezier control points, because it always changes the previously selected normal envelope point. This caused the client to crash when right-clicking a bezier control point when no normal envelope point was previously selected.
Closes#8020.
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.
Only building the switch entities layer when the current map has a switch layer (#8011) also does not work, because the entities textures are cached for each type and not reloaded unless the entities are changed manually. First joining a server with a map that does not have a switch layer will cause the textures for the type of that server to be built without the switch entities layer, so the switch entities texture will be missing when joining a server of that type with a map that does have a switch layer.
Instead, the switch entities layer textures are always built now, so the cached entities textures are can be used on all maps of the respective server type. This is expected to slightly increase the total memory usage after joining multiple servers of different types. As before, tiles which are unused are masked unless `m_DontMaskEntities` is set.
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
Assert on failures in all `thread_*` and `sphore_*` functions on all operating systems instead of only printing log messages on Unix, as these functions are only expected to fail when used with incorrect arguments or in some cases when a dead-lock is detected.
On macOS, `sphore_wait` was not correctly calling `sem_wait` in a loop to repeat the wait operation if it is interrupted by a signal.
On Windows, the AIO tests were failing with the additional assertions. The maximum count that semaphores on Windows could be incremented to was previously, arbitrarily limited to 10000, which was causing the `ReleaseSemaphore` call to fail as the AIO semaphore is signaled 65536 times (for each write operation) in multiple of the AIO tests.
- Remove `ValidateFCurve` function because it's small and only used once.
- Remove unnecessary checks in `SolveBezier`, as all of these conditions are already checked before the function is called.
- Remove unnecessary double negation of `InTang` to improve readability.
- Use `double` literals for `double` comparisons instead of `float` literals.
- Fix comments.
There is no need to divide the times by 1000 when evaluating bezier curves, as all times are relative and the division adds significant inaccuracy, to the point where evaluation of bezier curves goes completely wrong in some cases.
Closes#8005.
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.
Instead of only building the switch entities when the server uses the DDNet/DDrace type. Fix switch entities not being shown anymore on servers which do not mask entities. Regression from #7979.
Call `EnvelopeEval` functions directly instead of passing them and their arguments to `CRenderTools::RenderTilemap` and `CRenderTools::RenderTileRectangle`.
Only evaluate color envelopes for tiles layers once instead of separately for the opaque and transparent passes.
Only evaluate relevant number of envelope channels instead of always evaluating all channels.
Avoid unnecessary calculations by only evaluating position envelopes for quads which are not fully transparent.
Fully ignore layer color and envelope color for entities layers, as these cannot be specified in the editor and should not be changeable.
Remove duplicate and insufficient checks for invalid envelope index before calling `EnvelopeEval`. Instead, set the correct default for all channels before calling `EnvelopeEval` and only change the result on success. Now, white color will consistently be assumed for invalid color envelopes, zero positions and rotations for invalid position envelopes, and full volume for invalid sound envelopes.
Validate number of envelope channels to prevent crashes. When loading maps containing envelopes with invalid number of channels (not equal to 1, 3 or 4), the number of channels of these envelopes is reset to 4 and an error message is displayed, so the mapper can examine all channels' data and transfer it to another envelope if necessary. Closes#7985.
Use consistent margins for all settings pages and titles (except the Appearance settings, which will be covered in the future).
Fix checkbox UI element ID variable `s_LowerRefreshRate` not being `static`.
Improve readability of layout code.
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.
If the own ghost is the last element in the vector and deleted due to using the `cl_race_ghost_save_best 1` setting then the following accesses with index `Own` were out-of-bounds. Closes#8003.
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.
The check before calling `normalize` incorrectly excludes skins containing zero in any color component instead of excluding only skins with zero in all components. The check can be removed entirely, because it is already checked inside the `normalize` function whether the length of the `vec3` is zero, in which case a zero `vec3` will be returned.
For very large skins which use large color values in at least one component, the `int` used for calculating the blood color could overflow.
Prevent skins with invalid names from being loaded/downloaded.
Improve log messages when skins cannot be loaded.
Remove obsolete check for duplicate skins, as the storage handles duplicate files already.
Instead of adding the placeholder skin to the list of skins only when no skins have been loaded, always create the placeholder skin and use it only when no other skin is available.
Use reasonable values for skin metrics of placeholder skin to improve its rendering.
This adds highlighting color when hovering the main menu buttons (File, Tools, Settings), which was previously missing for these buttons. This also reduced duplicate code.
Extract font size for menu buttons into constant `MENU` in new namespace `EditorFontSizes`.
Use `DoButton_FontIcon` with `FONT_ICON_MINUS`/`FONT_ICON_PLUS` consistently instead of using `DoButton_ButtonDec/Inc` with text labels `+`/`-`.
For yes/no buttons, use `DoButton_Ex` and specify the button corners explicitly instead of using `DoButton_ButtonDec/Inc`.
Reset dragging operation when the dragged button has been unset and reset dragged button when operation has been reset, to prevent the editor from being stuck in either of two inconsistent states. This could be reproduced easily by clicking very quickly while moving the mouse up and down over the groups/layers list.
Do not call `CheckActiveItem` on a UI element (the dragged button) which might not be in view, as this prevents the UI from detecting the invalid active item, when groups/layers are dragged very far and quickly outside the scrollregion.
Closes#6855.
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.
The combined entities texture for all layers except the switch layer was only built when the gametype has a front, speedup, tele or tune layer, which is only the case for servers declaring DDNet or DDRace type in their gameinfo. Now this entities layer is always built, as the game layer is always present.
Expose UI element ID for the main map editor as member variable so the select layer by tile funtionality can correctly be enabled when the map editor is the hot item.
Add/update doxygen comments for all `shell_*`, `os_*`, `secure_*`, `cmdline_*`, `windows_*` and related functions.
Move `open_link` and `open_file` declarations to shell group, to the same relative position as their function definitions.
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.
It was possible to create a community/country/type filter excluding all entries when the list only contains one entry and right-click is used to deselect it.
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".
Directly use the bounding box which has already been calculated for the text containers, instead of calculating the text width again for every info message text.
Reduce duplicate code by moving screen remapping and validation of the info message into the `AddInfoMsg` function.
Check for valid kill message before creating text containers, so they are not created and deleted unnecessarily.
Assign info message type directly instead of passing it as a separate parameter.
Combine `CreateNamesIfNotCreated` and `CreateFinishTextContainersIfNotCreated` functions to `CreateTextContainersIfNotCreated` function to reduce duplicate code on usage.
Extract duplicate code for determining name color in info messages as lambda function.
For consistency between 0.6 and 0.7 clients, also show kill messages for 0.7 clients, now that DDNet client also supports finish messages.
Closes#5623.
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.
Add `CGameClient::RefreshSkins` function to refresh skins. This function reloads all skins by calling `CSkins::Refresh` and then notifies all gameclient components about the skins being refreshed by calling the new `CComponent::OnRefreshSkins` function, so the components can properly invalidate their current skin texture handles. The existing `RefindSkins` functions are changed to `OnRefreshSkins`.
Additionally, `OnRefreshSkins` is overridden in `CMenus` to set the flag so the skin list will be updated before it is rendered the next time, to fix the client crashing when changing skin related config variables via the console. Closes#7891.
Reduce height and empty space and make margins consistent. Slightly increase width for better round corner drawing and to support longer vote descriptions.
Auto-scale description and reason labels and show ellipsis if they don't fit.
Show circular progress indicator for remaining vote time.
The functionality to draw text on the voting bars is never used, so the parameter `Text` is always `false`.
Remove unused variable `PassArea`. The remaining area of the voting bars is unused.
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.
Use `IGraphics::CORNER_NONE` instead of `0`.
Use `nullptr` instead of `NULL`.
Remove arguments identical to defaults.
Use loops for tab bars with several tabs.