Skip to content
Open
2 changes: 2 additions & 0 deletions Source/CS2/Classes/Entities/CCSPlayerController.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

#include <cstdint>

#include <CS2/Classes/CUtlString.h>
#include <CS2/Classes/EntitySystem/CEntityHandle.h>
#include <Platform/Macros/PlatformSpecific.h>

Expand All @@ -25,6 +26,7 @@ struct CCSPlayerController : C_BaseEntity {

using m_hPawn = CEntityHandle;
using m_iCompTeammateColor = PlayerColorIndex;
using m_sSanitizedPlayerName = CUtlString;
};

}
2 changes: 2 additions & 0 deletions Source/Config/ConfigSchema.h
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,8 @@ class ConfigSchema {
configConversion.uint(u8"ColorMode", loadVariable<player_info_vars::PlayerPositionArrowColorMode>(), saveVariable<player_info_vars::PlayerPositionArrowColorMode>());
configConversion.endObject();

configConversion.boolean(u8"PlayerName", loadVariable<player_info_vars::PlayerNameEnabled>(), saveVariable<player_info_vars::PlayerNameEnabled>());

configConversion.beginObject(u8"Health");
configConversion.boolean(u8"Enabled", loadVariable<player_info_vars::PlayerHealthEnabled>(), saveVariable<player_info_vars::PlayerHealthEnabled>());
configConversion.uint(u8"ColorMode", loadVariable<player_info_vars::PlayerHealthColorMode>(), saveVariable<player_info_vars::PlayerHealthColorMode>());
Expand Down
1 change: 1 addition & 0 deletions Source/Config/ConfigVariableTypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ using ConfigVariableTypes = TypeList<
player_info_vars::OnlyEnemies,
player_info_vars::PlayerPositionArrowEnabled,
player_info_vars::PlayerPositionArrowColorMode,
player_info_vars::PlayerNameEnabled,
player_info_vars::PlayerHealthEnabled,
player_info_vars::PlayerHealthColorMode,
player_info_vars::ActiveWeaponIconEnabled,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ CONFIG_VARIABLE(Enabled, bool, false);
CONFIG_VARIABLE(OnlyEnemies, bool, false);
CONFIG_VARIABLE(PlayerPositionArrowEnabled, bool, true);
CONFIG_VARIABLE(PlayerPositionArrowColorMode, PlayerPositionArrowColorType, PlayerPositionArrowColorType::PlayerOrTeamColor);
CONFIG_VARIABLE(PlayerNameEnabled, bool, true);
CONFIG_VARIABLE(PlayerHealthEnabled, bool, true);
CONFIG_VARIABLE(PlayerHealthColorMode, PlayerHealthTextColor, PlayerHealthTextColor::HealthBased);
CONFIG_VARIABLE(ActiveWeaponIconEnabled, bool, true);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
#include "PlayerHealth/PlayerHealthPanel.h"
#include "PlayerHealth/PlayerHealthPanelParams.h"
#include "PlayerInfoContainerPanelParams.h"
#include "PlayerNamePanel.h"
#include "PlayerNamePanelParams.h"
#include "PlayerPositionArrow/PlayerPositionArrowPanel.h"
#include "PlayerPositionArrow/PlayerPositionArrowPanelParams.h"
#include "PlayerStateIcons/PlayerStateIconsPanel.h"
Expand Down Expand Up @@ -56,6 +58,18 @@ class PlayerInfoInWorldPanelFactory {
}.applyTo(uiPanel);
}

void createPanel(std::type_identity<PlayerNamePanel<HookContext>>, auto&& containerPanel) const noexcept
{
using namespace player_name_panel_params;

auto&& label = hookContext.panelFactory().createLabelPanel(containerPanel).uiPanel();
label.setFont(kFont);
label.setAlign(kAlignment);
label.setMargin(kMargin);
label.setTextShadow(kShadowParams);
label.setColor(kColor);
}

void createPanel(std::type_identity<PlayerActiveWeaponAmmoPanel<HookContext>>, auto&& containerPanel) const noexcept
{
auto&& ammoPanel = createActiveWeaponAmmoContainerPanel(containerPanel);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@

#include "ActiveWeaponAmmo/PlayerActiveWeaponAmmoPanel.h"
#include "PlayerHealth/PlayerHealthPanel.h"
#include "PlayerNamePanel.h"
#include "PlayerPositionArrow/PlayerPositionArrowPanel.h"
#include "PlayerStateIcons/PlayerStateIconsPanel.h"
#include "PlayerWeaponIcon/PlayerWeaponIconPanel.h"

template <typename HookContext>
using PlayerInfoPanelTypes = std::tuple<
PlayerPositionArrowPanel<HookContext>,
PlayerNamePanel<HookContext>,
PlayerHealthPanel<HookContext>,
PlayerWeaponIconPanel<HookContext>,
PlayerActiveWeaponAmmoPanel<HookContext>,
Expand Down
64 changes: 64 additions & 0 deletions Source/Features/Visuals/PlayerInfoInWorld/PlayerNamePanel.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
#pragma once

#include <utility>

#include <CS2/Panorama/CUIPanel.h>
#include <Features/Visuals/PlayerInfoInWorld/PlayerInfoInWorldConfigVariables.h>
#include <GameClient/Panorama/PanoramaLabel.h>
#include <GameClient/Panorama/PanoramaUiPanel.h>

#include "PlayerNamePanelParams.h"

template <typename HookContext>
class PlayerNamePanelContext {
public:
PlayerNamePanelContext(HookContext& hookContext, cs2::CUIPanel* panel, auto&) noexcept
: _hookContext{hookContext}
, _panel{panel}
{
}

[[nodiscard]] decltype(auto) config() const noexcept
{
return _hookContext.config();
}

[[nodiscard]] decltype(auto) panel() const noexcept
{
return _hookContext.template make<PanoramaUiPanel>(_panel);
}

private:
HookContext& _hookContext;
cs2::CUIPanel* _panel;
};

template <typename HookContext, typename Context = PlayerNamePanelContext<HookContext>>
class PlayerNamePanel {
public:
template <typename... Args>
explicit PlayerNamePanel(Args&&... args) noexcept
: context{std::forward<Args>(args)...}
{
}

void update(auto&& playerPawn) const noexcept
{
if (!context.config().template getVariable<player_info_vars::PlayerNameEnabled>()) {
context.panel().setVisible(false);
return;
}

const auto playerName = playerPawn.playerController().getName();
if (!playerName || !*playerName) {
context.panel().setVisible(false);
return;
}

context.panel().setVisible(true);
context.panel().clientPanel().template as<PanoramaLabel>().setText(playerName);
}

private:
Context context;
};
31 changes: 31 additions & 0 deletions Source/Features/Visuals/PlayerInfoInWorld/PlayerNamePanelParams.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#pragma once

#include <CS2/Constants/ColorConstants.h>
#include <CS2/Panorama/CUILength.h>
#include <CS2/Panorama/StyleEnums.h>
#include <GameClient/Panorama/PanelAlignmentParams.h>
#include <GameClient/Panorama/PanelFontParams.h>
#include <GameClient/Panorama/PanelMarginParams.h>
#include <GameClient/Panorama/PanelShadowParams.h>

namespace player_name_panel_params
{
static constexpr auto kFont = PanelFontParams{
.fontFamily = "Stratum2, 'Arial Unicode MS'",
.fontSize = 20,
.fontWeight = cs2::k_EFontWeightBold
};
static constexpr auto kAlignment = PanelAlignmentParams{
.horizontalAlignment = cs2::k_EHorizontalAlignmentCenter,
.verticalAlignment = cs2::k_EVerticalAlignmentTop
};
static constexpr auto kMargin = PanelMarginParams{.marginBottom = cs2::CUILength::pixels(1)};
static constexpr auto kColor = cs2::kColorWhite;
static constexpr auto kShadowParams = PanelShadowParams{
.horizontalOffset{cs2::CUILength::pixels(0)},
.verticalOffset{cs2::CUILength::pixels(0)},
.blurRadius{cs2::CUILength::pixels(3)},
.strength = 3,
.color{cs2::kColorBlack}
};
}
9 changes: 9 additions & 0 deletions Source/GameClient/Entities/PlayerController.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#pragma once

#include <cstddef>
#include <optional>
#include <span>
#include <utility>
Expand Down Expand Up @@ -51,6 +52,14 @@ class PlayerController {
return hookContext.patternSearchResults().template get<OffsetToPlayerColor>().of(playerControllerPointer).toOptional();
}

[[nodiscard]] const char* getName() const noexcept
{
constexpr auto kOffsetFromPlayerColorToSanitizedName{0x18};
if (const auto playerColor = hookContext.patternSearchResults().template get<OffsetToPlayerColor>().of(playerControllerPointer).get())
return reinterpret_cast<cs2::CUtlString*>(reinterpret_cast<std::byte*>(playerColor) + kOffsetFromPlayerColorToSanitizedName)->m_pString;
Comment thread
starnotes-xj marked this conversation as resolved.
Outdated
return static_cast<const char*>(nullptr);
Comment thread
starnotes-xj marked this conversation as resolved.
Outdated
}

private:
HookContext& hookContext;
cs2::CCSPlayerController* playerControllerPointer;
Expand Down
3 changes: 3 additions & 0 deletions Source/UI/Panorama/CreateGUI.js
Original file line number Diff line number Diff line change
Expand Up @@ -499,6 +499,9 @@ u8R"(
separator(playerPosition);
createDropDown(playerPosition, "Player Position Arrow Color", 'visuals', 'player_info_position_color', ['Player / Team Color', 'Team Color']);

var playerName = createSection(playerInfoTab, 'Player Name');
createYesNoDropDown(playerName, "Show Player Name", 'visuals', 'player_info_name');

var playerHealth = createSection(playerInfoTab, 'Player Health');
createYesNoDropDown(playerHealth, "Show Player Health", 'visuals', 'player_info_health');
separator(playerHealth);
Expand Down
2 changes: 2 additions & 0 deletions Source/UI/Panorama/VisualsTab.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ class VisualsTab {
initDropDown<PlayerInfoInWorldDropdownSelectionChangeHandler<HookContext>>(guiPanel, "player_information_through_walls");
initDropDown<OnOffDropdownSelectionChangeHandler<HookContext, player_info_vars::PlayerPositionArrowEnabled>>(guiPanel, "player_info_position");
initDropDown<PlayerInfoInWorldPlayerPositionArrowColorModeDropdownSelectionChangeHandler<HookContext>>(guiPanel, "player_info_position_color");
initDropDown<OnOffDropdownSelectionChangeHandler<HookContext, player_info_vars::PlayerNameEnabled>>(guiPanel, "player_info_name");
initDropDown<OnOffDropdownSelectionChangeHandler<HookContext, player_info_vars::PlayerHealthEnabled>>(guiPanel, "player_info_health");
initDropDown<PlayerInfoInWorldPlayerHealthColorModeDropdownSelectionChangeHandler<HookContext>>(guiPanel, "player_info_health_color");
initDropDown<OnOffDropdownSelectionChangeHandler<HookContext, player_info_vars::ActiveWeaponIconEnabled>>(guiPanel, "player_info_weapon");
Expand Down Expand Up @@ -148,6 +149,7 @@ class VisualsTab {
setDropDownSelectedIndex(mainMenu, "player_information_through_walls", playerInfoDropDownIndex());
setDropDownSelectedIndex(mainMenu, "player_info_position", !GET_CONFIG_VAR(player_info_vars::PlayerPositionArrowEnabled));
setDropDownSelectedIndex(mainMenu, "player_info_position_color", static_cast<int>(GET_CONFIG_VAR(player_info_vars::PlayerPositionArrowColorMode)));
setDropDownSelectedIndex(mainMenu, "player_info_name", !GET_CONFIG_VAR(player_info_vars::PlayerNameEnabled));
setDropDownSelectedIndex(mainMenu, "player_info_health", !GET_CONFIG_VAR(player_info_vars::PlayerHealthEnabled));
setDropDownSelectedIndex(mainMenu, "player_info_health_color", static_cast<int>(GET_CONFIG_VAR(player_info_vars::PlayerHealthColorMode)));
setDropDownSelectedIndex(mainMenu, "player_info_weapon", !GET_CONFIG_VAR(player_info_vars::ActiveWeaponIconEnabled));
Expand Down
2 changes: 1 addition & 1 deletion Tests/Configs/config_current.cfg
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"Combat":{"NoScopeInaccuracyVis":{"Enabled":true}},"Hud":{"BombTimer":{"Enabled":true},"BombDefuseAlert":{"Enabled":true},"PreserveKillfeed":{"Enabled":true},"PostRoundTimer":{"Enabled":true},"BombPlantAlert":{"Enabled":true}},"Visuals":{"ModelGlow":{"Enabled":true,"Players":{"Enabled":true,"OnlyEnemies":true,"ColorMode":0},"Weapons":true,"DroppedBomb":false,"TickingBomb":false,"DefuseKits":true,"GrenadeProjectiles":true,"Hues":{"PlayerBlue":203,"PlayerGreen":133,"PlayerYellow":48,"PlayerOrange":13,"PlayerPurple":269,"TeamT":30,"TeamCT":220,"LowHealth":311,"HighHealth":256,"Enemy":353,"Ally":74,"Molotov":37,"Flashbang":205,"HEGrenade":333,"SmokeGrenade":116,"DroppedBomb":69,"TickingBomb":303,"DefuseKit":227}},"OutlineGlow":{"Enabled":true,"Players":{"Enabled":true,"OnlyEnemies":false,"ColorMode":2},"Weapons":true,"DroppedBomb":true,"TickingBomb":false,"DefuseKits":true,"Hostages":true,"GrenadeProjectiles":true,"Hues":{"PlayerBlue":200,"PlayerGreen":134,"PlayerYellow":57,"PlayerOrange":12,"PlayerPurple":256,"TeamT":37,"TeamCT":227,"LowHealth":287,"HighHealth":171,"Enemy":304,"Ally":103,"Molotov":60,"Flashbang":250,"HEGrenade":300,"SmokeGrenade":140,"DroppedBomb":302,"TickingBomb":26,"DefuseKit":160,"Hostage":334}},"PlayerInfoInWorld":{"Enabled":true,"OnlyEnemies":true,"PlayerPositionArrow":{"Enabled":true,"ColorMode":0},"Health":{"Enabled":true,"ColorMode":0},"ActiveWeaponIcon":true,"BombCarrierIcon":true,"BombPlantIcon":true,"ActiveWeaponAmmo":false,"BombDefuseIcon":true,"HostagePickupIcon":true,"HostageRescueIcon":true,"BlindedIcon":true},"ViewmodelMod":{"Enabled":true,"ModifyFov":true,"Fov":90}},"Sound":{"Visualizations":{"Footsteps":{"Enabled":true},"BombPlant":{"Enabled":true},"BombBeep":{"Enabled":true},"BombDefuse":{"Enabled":true},"WeaponScope":{"Enabled":true},"WeaponReload":{"Enabled":true}}}}
{"Combat":{"NoScopeInaccuracyVis":{"Enabled":true}},"Hud":{"BombTimer":{"Enabled":true},"BombDefuseAlert":{"Enabled":true},"PreserveKillfeed":{"Enabled":true},"PostRoundTimer":{"Enabled":true},"BombPlantAlert":{"Enabled":true}},"Visuals":{"ModelGlow":{"Enabled":true,"Players":{"Enabled":true,"OnlyEnemies":true,"ColorMode":0},"Weapons":true,"DroppedBomb":false,"TickingBomb":false,"DefuseKits":true,"GrenadeProjectiles":true,"Hues":{"PlayerBlue":203,"PlayerGreen":133,"PlayerYellow":48,"PlayerOrange":13,"PlayerPurple":269,"TeamT":30,"TeamCT":220,"LowHealth":311,"HighHealth":256,"Enemy":353,"Ally":74,"Molotov":37,"Flashbang":205,"HEGrenade":333,"SmokeGrenade":116,"DroppedBomb":69,"TickingBomb":303,"DefuseKit":227}},"OutlineGlow":{"Enabled":true,"Players":{"Enabled":true,"OnlyEnemies":false,"ColorMode":2},"Weapons":true,"DroppedBomb":true,"TickingBomb":false,"DefuseKits":true,"Hostages":true,"GrenadeProjectiles":true,"Hues":{"PlayerBlue":200,"PlayerGreen":134,"PlayerYellow":57,"PlayerOrange":12,"PlayerPurple":256,"TeamT":37,"TeamCT":227,"LowHealth":287,"HighHealth":171,"Enemy":304,"Ally":103,"Molotov":60,"Flashbang":250,"HEGrenade":300,"SmokeGrenade":140,"DroppedBomb":302,"TickingBomb":26,"DefuseKit":160,"Hostage":334}},"PlayerInfoInWorld":{"Enabled":true,"OnlyEnemies":true,"PlayerPositionArrow":{"Enabled":true,"ColorMode":0},"PlayerName":true,"Health":{"Enabled":true,"ColorMode":0},"ActiveWeaponIcon":true,"BombCarrierIcon":true,"BombPlantIcon":true,"ActiveWeaponAmmo":false,"BombDefuseIcon":true,"HostagePickupIcon":true,"HostageRescueIcon":true,"BlindedIcon":true},"ViewmodelMod":{"Enabled":true,"ModifyFov":true,"Fov":90}},"Sound":{"Visualizations":{"Footsteps":{"Enabled":true},"BombPlant":{"Enabled":true},"BombBeep":{"Enabled":true},"BombDefuse":{"Enabled":true},"WeaponScope":{"Enabled":true},"WeaponReload":{"Enabled":true}}}}
8 changes: 7 additions & 1 deletion Tests/FunctionalTests/Config/ConfigCompatibilityTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -171,9 +171,15 @@ class ConfigCompatibilityTest : public testing::Test {
get<BombPlantAlertEnabled>() = true;
}

void setVariableExpectationsCurrent()
void setVariableExpectationsV11()
{
setVariableExpectationsV10();
get<player_info_vars::PlayerNameEnabled>() = true;
}

void setVariableExpectationsCurrent()
{
setVariableExpectationsV11();
}

struct VariableChecker {
Expand Down
1 change: 1 addition & 0 deletions Tests/Mocks/MockPlayerController.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,6 @@ struct MockBaseEntity;

struct MockPlayerController {
MOCK_METHOD(Optional<cs2::CCSPlayerController::m_iCompTeammateColor>, playerColorIndex, ());
MOCK_METHOD(const char*, getName, ());
MOCK_METHOD(MockBaseEntity&, pawn, ());
};