Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 41 additions & 10 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -417,7 +417,9 @@ if(NOT MSVC AND NOT HAIKU)
add_cxx_compiler_flag_if_supported(OUR_FLAGS_OWN -Wdynamic-class-memaccess) # clang
add_cxx_compiler_flag_if_supported(OUR_FLAGS_OWN -Wlogical-op)
add_cxx_compiler_flag_if_supported(OUR_FLAGS_OWN -Wno-missing-field-initializers)
add_cxx_compiler_flag_if_supported(OUR_FLAGS_OWN -Wno-nullability-completeness) # Mac OS build on github
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
add_cxx_compiler_flag_if_supported(OUR_FLAGS_OWN -Wno-nullability-completeness) # Mac OS build on GitHub
endif()
add_cxx_compiler_flag_if_supported(OUR_FLAGS_OWN -Wno-psabi) # parameter passing for argument of type ‘__gnu_cxx::__normal_iterator<CCommandProcessorFragment_Vulkan::SMemoryBlock<1>*, std::vector<CCommandProcessorFragment_Vulkan::SMemoryBlock<1>, std::allocator<CCommandProcessorFragment_Vulkan::SMemoryBlock<1> > > >’ changed in GCC 7.1
add_cxx_compiler_flag_if_supported(OUR_FLAGS_OWN -Wno-unused-parameter)
add_cxx_compiler_flag_if_supported(OUR_FLAGS_OWN -Wrestrict)
Expand Down Expand Up @@ -614,6 +616,14 @@ find_package(Python3)
find_package(Rust)
find_package(SDL2)
find_package(SQLite3)
if(CLIENT AND TARGET_OS STREQUAL "linux")
# The Music Player reads MPRIS sessions over D-Bus and uses PulseAudio or
# PipeWire's PulseAudio compatibility server for its realtime visualizer.
# Both integrations remain optional so minimal Linux installations keep
# building with the passive player fallback.
find_package(DBus)
find_package(PulseAudio)
endif()
if(DISCORD)
find_package(DiscordSdk)
endif()
Expand Down Expand Up @@ -2479,6 +2489,7 @@ set_src(GAME_SHARED GLOB src/game
team_state.h
teamscore.cpp
teamscore.h
tune_zone_colors.h
tuning.h
version.h
voting.h
Expand Down Expand Up @@ -2781,12 +2792,19 @@ if(CLIENT)
components/tclient/fast_practice.h
components/tclient/inputs.cpp
components/tclient/inputs.h
components/tclient/menus_tclient.cpp
components/tclient/mod.cpp
components/tclient/mod.h
components/tclient/moving_tiles.cpp
components/tclient/moving_tiles.h
components/tclient/mumble.cpp
components/tclient/mumble.h
components/tclient/music_player/media_decoder.cpp
components/tclient/music_player/media_decoder.h
components/tclient/music_player/music_player.cpp
components/tclient/music_player/music_player.h
components/tclient/music_player/music_player_lyrics.cpp
components/tclient/music_player/music_player_lyrics.h
components/tclient/music_player/media_decoder.cpp
components/tclient/music_player/media_decoder.h
components/tclient/music_player/visualizer/analyzer.cpp
components/tclient/music_player/visualizer/analyzer.h
components/tclient/music_player/visualizer/service.cpp
Expand All @@ -2799,13 +2817,6 @@ if(CLIENT)
components/tclient/music_player/visualizer/source_pulse.cpp
components/tclient/music_player/visualizer/source_wasapi.cpp
components/tclient/music_player/visualizer/types.h
components/tclient/menus_tclient.cpp
components/tclient/mod.cpp
components/tclient/mod.h
components/tclient/moving_tiles.cpp
components/tclient/moving_tiles.h
components/tclient/mumble.cpp
components/tclient/mumble.h
components/tclient/outlines.cpp
components/tclient/outlines.h
components/tclient/pet.cpp
Expand Down Expand Up @@ -3030,6 +3041,15 @@ if(CLIENT)
${LIBS}
)

if(TARGET_OS STREQUAL "linux")
if(DBus_FOUND)
list(APPEND LIBS_CLIENT ${DBUS_LIBRARIES})
endif()
if(PulseAudio_FOUND)
list(APPEND LIBS_CLIENT ${PULSEAUDIO_LIBRARIES})
endif()
endif()

if(DISCORD)
if(NOT DISCORD_DYNAMIC)
list(APPEND LIBS_CLIENT discord-shared)
Expand Down Expand Up @@ -3166,6 +3186,7 @@ if(CLIENT)

target_include_directories(game-client SYSTEM PRIVATE
# tidy-alphabetical-start
${DBUS_INCLUDE_DIRS}
${DISCORDSDK_INCLUDE_DIRS}
${FFMPEG_INCLUDE_DIRS}
${FREETYPE_INCLUDE_DIRS}
Expand All @@ -3174,6 +3195,7 @@ if(CLIENT)
${OPUSFILE_INCLUDE_DIRS}
${OPUS_INCLUDE_DIRS}
${PNG_INCLUDE_DIRS}
${PULSEAUDIO_INCLUDE_DIRS}
${SDL2_INCLUDE_DIRS}
${WAVPACK_INCLUDE_DIRS}
# tidy-alphabetical-end
Expand Down Expand Up @@ -3216,6 +3238,15 @@ if(CLIENT)
target_compile_definitions(game-client PRIVATE CONF_BACKEND_VULKAN)
endif()

if(TARGET_OS STREQUAL "linux")
if(DBus_FOUND)
target_compile_definitions(game-client PRIVATE BC_MUSICPLAYER_HAS_DBUS=1)
endif()
if(PulseAudio_FOUND)
target_compile_definitions(game-client PRIVATE BC_MUSICPLAYER_HAS_PULSE=1)
endif()
endif()

if(WIN32)
# Keep the updater a separately built, versioned executable. It is the
# only process that replaces DDNet.exe after the main client exits.
Expand Down
27 changes: 27 additions & 0 deletions cmake/FindDBus.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
if(NOT CMAKE_CROSSCOMPILING)
find_package(PkgConfig QUIET)
pkg_check_modules(PC_DBUS QUIET dbus-1)
endif()

find_library(DBUS_LIBRARY
NAMES dbus-1
HINTS ${PC_DBUS_LIBDIR} ${PC_DBUS_LIBRARY_DIRS}
${CROSSCOMPILING_NO_CMAKE_SYSTEM_PATH}
)
find_path(DBUS_INCLUDEDIR
NAMES dbus/dbus.h
HINTS ${PC_DBUS_INCLUDEDIR} ${PC_DBUS_INCLUDE_DIRS}
${CROSSCOMPILING_NO_CMAKE_SYSTEM_PATH}
)

include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(DBus DEFAULT_MSG DBUS_LIBRARY DBUS_INCLUDEDIR)

mark_as_advanced(DBUS_LIBRARY DBUS_INCLUDEDIR)

if(DBUS_FOUND)
set(DBUS_LIBRARIES ${DBUS_LIBRARY})
# dbus/dbus-arch-deps.h is architecture-specific and is not necessarily in
# the same include directory as dbus/dbus.h.
set(DBUS_INCLUDE_DIRS ${DBUS_INCLUDEDIR} ${PC_DBUS_INCLUDE_DIRS})
endif()
36 changes: 36 additions & 0 deletions cmake/FindPulseAudio.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
if(NOT CMAKE_CROSSCOMPILING)
find_package(PkgConfig QUIET)
pkg_check_modules(PC_PULSEAUDIO QUIET libpulse)
pkg_check_modules(PC_PULSEAUDIO_SIMPLE QUIET libpulse-simple)
endif()

find_library(PULSEAUDIO_LIBRARY
NAMES pulse
HINTS ${PC_PULSEAUDIO_LIBDIR} ${PC_PULSEAUDIO_LIBRARY_DIRS}
${CROSSCOMPILING_NO_CMAKE_SYSTEM_PATH}
)
find_library(PULSEAUDIO_SIMPLE_LIBRARY
NAMES pulse-simple
HINTS ${PC_PULSEAUDIO_SIMPLE_LIBDIR} ${PC_PULSEAUDIO_SIMPLE_LIBRARY_DIRS}
${CROSSCOMPILING_NO_CMAKE_SYSTEM_PATH}
)
find_path(PULSEAUDIO_INCLUDEDIR
NAMES pulse/pulseaudio.h
HINTS ${PC_PULSEAUDIO_INCLUDEDIR} ${PC_PULSEAUDIO_INCLUDE_DIRS}
${CROSSCOMPILING_NO_CMAKE_SYSTEM_PATH}
)

include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(PulseAudio DEFAULT_MSG
PULSEAUDIO_LIBRARY
PULSEAUDIO_SIMPLE_LIBRARY
PULSEAUDIO_INCLUDEDIR
)

mark_as_advanced(PULSEAUDIO_LIBRARY PULSEAUDIO_SIMPLE_LIBRARY PULSEAUDIO_INCLUDEDIR)

if(PulseAudio_FOUND)
# libpulse-simple depends on libpulse, so keep the dependent library first.
set(PULSEAUDIO_LIBRARIES ${PULSEAUDIO_SIMPLE_LIBRARY} ${PULSEAUDIO_LIBRARY})
set(PULSEAUDIO_INCLUDE_DIRS ${PULSEAUDIO_INCLUDEDIR} ${PC_PULSEAUDIO_INCLUDE_DIRS})
endif()
3 changes: 3 additions & 0 deletions docs/BUILDING.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@ FLUSH PRIVILEGES;
You need to install the [Vulkan SDK](https://vulkan.lunarg.com/sdk/home) and set the `VULKAN_SDK` environment flag accordingly.
Default value is ON for Linux, and OFF for Windows and macOS.

* **Linux Music Player support** <br>
The music player reads MPRIS-compatible players (such as Spotify, VLC, mpv, and browser media sessions) from the desktop session bus. Its realtime visualizer uses PulseAudio; this also works with PipeWire when its PulseAudio compatibility service is enabled. Install `libdbus-1-dev libpulse-dev` on Debian/Ubuntu, `dbus libpulse` on Arch Linux, or `dbus-devel pulseaudio-libs-devel` on Fedora. These are optional: when unavailable, the client still builds, but the music player uses its passive fallback.

* **-GNinja** <br>
Use the Ninja build system instead of Make. This automatically parallelizes the build and is generally faster. Compile with `ninja` instead of `make`. Install Ninja with `sudo apt install ninja-build` on Debian, `sudo pacman -S --needed ninja` on Arch Linux.

Expand Down
4 changes: 4 additions & 0 deletions src/engine/client/updater.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ void BuildReleasesUrl(char *pBuf, int BufSize)
str_format(pBuf, BufSize, "%s%ct=%lld", pSource, str_find(pSource, "?") ? '&' : '?', (long long)time_timestamp());
}

#if defined(CONF_FAMILY_WINDOWS)
bool StrEndsWithNoCase(const char *pStr, const char *pSuffix)
{
if(!pStr || !pSuffix)
Expand All @@ -42,6 +43,7 @@ bool StrEndsWithNoCase(const char *pStr, const char *pSuffix)
const int SuffixLen = str_length(pSuffix);
return SuffixLen <= StrLen && str_comp_nocase(pStr + StrLen - SuffixLen, pSuffix) == 0;
}
#endif

std::string ToLowerAscii(const char *pStr)
{
Expand Down Expand Up @@ -216,6 +218,7 @@ bool ParseLatestRelease(json_value *pJson, char *pVersion, int VersionSize, char
return true;
}

#if defined(CONF_FAMILY_WINDOWS)
void StripFilename(char *pPath)
{
for(int i = str_length(pPath) - 1; i >= 0; --i)
Expand Down Expand Up @@ -250,6 +253,7 @@ bool IsLegacyPortableDirectory(const char *pDirectory)
str_comp_nocase_num(pName, pPrefix, str_length(pPrefix)) == 0 &&
StrEndsWithNoCase(pName, pSuffix);
}
#endif
} // namespace

CUpdater::CUpdater()
Expand Down
12 changes: 7 additions & 5 deletions src/engine/shared/storage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -320,12 +320,14 @@ class CStorage : public IStorage
// Development builds place the executable in a configuration
// subdirectory (for example, build/release) and the data directory
// next to it (build/data).
fs_parent_dir(aDir);
str_format(aBuf, sizeof(aBuf), "%s/data/mapres", aDir);
if(fs_is_dir(aBuf))
if(fs_parent_dir(aDir) == 0)
{
str_format(m_aDatadir, sizeof(m_aDatadir), "%s/data", aDir);
return;
str_format(aBuf, sizeof(aBuf), "%s/data/mapres", aDir);
if(fs_is_dir(aBuf))
{
str_format(m_aDatadir, sizeof(m_aDatadir), "%s/data", aDir);
return;
}
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/game/client/components/chat.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -332,7 +332,7 @@ void CChat::ExecuteSmoothHudContextAction(int Action)

if(Action == 0) // Copy
{
char aText[MAX_NAME_LENGTH + MAX_LINE_LENGTH + 4];
char aText[static_cast<int>(MAX_NAME_LENGTH) + MAX_LINE_LENGTH + 4];
str_format(aText, sizeof(aText), "%s%s%s", Line.m_aName, Line.m_ClientId >= 0 ? ": " : "", Line.m_aText);
Input()->SetClipboardText(aText);
str_copy(m_aSmoothHudNotification, TCLocalize("Message copied", "AMF Client"), sizeof(m_aSmoothHudNotification));
Expand Down
6 changes: 3 additions & 3 deletions src/game/client/components/menus_settings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4749,9 +4749,9 @@ struct SAssetOrganizerPopupContext : public SPopupMenuId
const ColorRGBA PopupBorder = ColorRGBA(0.10f, 0.13f, 0.17f, 0.78f);
auto DoOrganizerPopupButton = [pUi, &PopupAccentPressed, &PopupAccentSoft, &PopupNeutral, &PopupNeutralHover, &PopupNeutralDisabled, &PopupBorder](CButtonContainer *pButton, const char *pText, const CUIRect *pRect, float FontSize, bool Enabled = true) {
const bool Hovered = Enabled && pUi->MouseHovered(pRect);
const bool Active = Enabled && pUi->CheckActiveItem(pButton);
const ColorRGBA Fill = !Enabled ? PopupNeutralDisabled : (Active ? PopupAccentPressed : (Hovered ? PopupNeutralHover : PopupNeutral));
const ColorRGBA Border = !Enabled ? PopupBorder : (Active ? PopupAccentPressed : (Hovered ? PopupAccentSoft : PopupBorder));
const bool IsActive = Enabled && pUi->CheckActiveItem(pButton);
const ColorRGBA Fill = !Enabled ? PopupNeutralDisabled : (IsActive ? PopupAccentPressed : (Hovered ? PopupNeutralHover : PopupNeutral));
const ColorRGBA Border = !Enabled ? PopupBorder : (IsActive ? PopupAccentPressed : (Hovered ? PopupAccentSoft : PopupBorder));
pRect->Draw(Border, IGraphics::CORNER_ALL, 3.0f);
CUIRect Inner = *pRect;
Inner.Margin(1.0f, &Inner);
Expand Down
1 change: 0 additions & 1 deletion src/game/client/components/scoreboard.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -982,7 +982,6 @@ void CScoreboard::RenderScoreboard(CUIRect Scoreboard, int Team, int CountStart,
CountryOffset, Row.y + (Spacing + TeeSizeMod * 5.0f) / 2.0f, CountryLength, Row.h - Spacing - TeeSizeMod * 5.0f);

// ping
ColorRGBA PingColor = TextRender()->DefaultTextColor();
if(g_Config.m_ClEnablePingColor)
{
TextRender()->TextColor(WithRenderAlpha(color_cast<ColorRGBA>(ColorHSLA((300.0f - std::clamp(pInfo->m_Latency, 0, 300)) / 1000.0f, 1.0f, 0.5f))));
Expand Down
40 changes: 17 additions & 23 deletions src/game/client/components/tclient/amf_hud_editor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -222,27 +222,27 @@ namespace
// the HUD element is very wide, tall or tiny.
DrawRoundedRectOutline(pGraphics, Rect, IGraphics::CORNER_NONE, 0.0f, Color);

const float ShortSide = std::min(Rect.w, Rect.h);
const float CornerSize = std::min(std::clamp(ShortSide * 0.14f, 0.8f, 5.0f), ShortSide * 0.25f);
const float Outset = std::min(CornerSize * 0.22f, 0.8f);
if(CornerSize <= 0.0f)
return;
const float ShortSide = std::min(Rect.w, Rect.h);
const float CornerSize = std::min(std::clamp(ShortSide * 0.14f, 0.8f, 5.0f), ShortSide * 0.25f);
const float Outset = std::min(CornerSize * 0.22f, 0.8f);
if(CornerSize <= 0.0f)
return;
const float Right = Rect.x + Rect.w;
const float Bottom = Rect.y + Rect.h;

pGraphics->TextureClear();
pGraphics->QuadsBegin();
pGraphics->SetColor(Color);
// Four identical, mirrored triangular markers. They are decoration only;
// no input state or resize hitbox is attached to any corner.
IGraphics::CFreeformItem aCorners[] = {
{Rect.x - Outset, Rect.y - Outset, Rect.x - Outset + CornerSize, Rect.y - Outset, Rect.x - Outset, Rect.y - Outset + CornerSize, Rect.x - Outset, Rect.y - Outset + CornerSize},
{Right + Outset, Rect.y - Outset, Right + Outset - CornerSize, Rect.y - Outset, Right + Outset, Rect.y - Outset + CornerSize, Right + Outset, Rect.y - Outset + CornerSize},
{Rect.x - Outset, Bottom + Outset, Rect.x - Outset + CornerSize, Bottom + Outset, Rect.x - Outset, Bottom + Outset - CornerSize, Rect.x - Outset, Bottom + Outset - CornerSize},
{Right + Outset, Bottom + Outset, Right + Outset - CornerSize, Bottom + Outset, Right + Outset, Bottom + Outset - CornerSize, Right + Outset, Bottom + Outset - CornerSize},
};
pGraphics->QuadsDrawFreeform(aCorners, sizeof(aCorners) / sizeof(aCorners[0]));
pGraphics->QuadsEnd();
pGraphics->QuadsBegin();
pGraphics->SetColor(Color);
// Four identical, mirrored triangular markers. They are decoration only;
// no input state or resize hitbox is attached to any corner.
IGraphics::CFreeformItem aCorners[] = {
{Rect.x - Outset, Rect.y - Outset, Rect.x - Outset + CornerSize, Rect.y - Outset, Rect.x - Outset, Rect.y - Outset + CornerSize, Rect.x - Outset, Rect.y - Outset + CornerSize},
{Right + Outset, Rect.y - Outset, Right + Outset - CornerSize, Rect.y - Outset, Right + Outset, Rect.y - Outset + CornerSize, Right + Outset, Rect.y - Outset + CornerSize},
{Rect.x - Outset, Bottom + Outset, Rect.x - Outset + CornerSize, Bottom + Outset, Rect.x - Outset, Bottom + Outset - CornerSize, Rect.x - Outset, Bottom + Outset - CornerSize},
{Right + Outset, Bottom + Outset, Right + Outset - CornerSize, Bottom + Outset, Right + Outset, Bottom + Outset - CornerSize, Right + Outset, Bottom + Outset - CornerSize},
};
pGraphics->QuadsDrawFreeform(aCorners, sizeof(aCorners) / sizeof(aCorners[0]));
pGraphics->QuadsEnd();
}

CUIRect ClampToBounds(CUIRect Rect, float Width, float Height)
Expand All @@ -252,12 +252,6 @@ namespace
return Rect;
}

float ChatInputBottomExtra(const CChat &Chat)
{
const float ScaledFontSize = Chat.FontSize() * (8.0f / 6.0f);
return std::max(2.25f * ScaledFontSize, std::max(ScaledFontSize + 4.0f, 16.0f));
}

} // namespace

void CAmfHudEditor::OnConsoleInit()
Expand Down
Loading