Skip to content

Commit

Permalink
Implement player model glow preview
Browse files Browse the repository at this point in the history
  • Loading branch information
danielkrupinski committed Jan 23, 2025
1 parent ad5aa75 commit 9da59db
Show file tree
Hide file tree
Showing 49 changed files with 864 additions and 32 deletions.
11 changes: 11 additions & 0 deletions Source/CS2/Classes/Entities/C_CSGO_PreviewPlayer.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#pragma once

#include "C_CSPlayerPawn.h"

namespace cs2
{

struct C_CSGO_PreviewPlayer : C_CSPlayerPawn {
};

}
4 changes: 3 additions & 1 deletion Source/CS2/Constants/EntityClasses.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#pragma once

#include <CS2/Classes/Entities/CBaseAnimGraph.h>
#include <CS2/Classes/Entities/C_CSGO_PreviewPlayer.h>
#include <CS2/Classes/Entities/C_CSPlayerPawn.h>
#include <CS2/Classes/Entities/C_Hostage.h>
#include <CS2/Classes/Entities/GrenadeProjectiles.h>
Expand Down Expand Up @@ -58,7 +59,8 @@ constexpr auto kEntityClassNames = TypedStaticStringPool{}
.add<C_C4>("C_C4")
.add<CPlantedC4>("C_PlantedC4")
.add<C_Hostage>("C_Hostage")
.add<C_Item_Healthshot>("C_Item_Healthshot");
.add<C_Item_Healthshot>("C_Item_Healthshot")
.add<C_CSGO_PreviewPlayer>("C_CSGO_PreviewPlayer");

using EntityClasses = decltype(kEntityClassNames)::TypeList;

Expand Down
15 changes: 15 additions & 0 deletions Source/CS2/Panorama/CUI_MapPlayerPreviewPanel.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#pragma once

#include <CS2/Classes/EntitySystem/CEntityHandle.h>
#include <CS2/Classes/CUtlVector.h>

#include "CPanel2D.h"

namespace cs2
{

struct CUI_MapPlayerPreviewPanel : CPanel2D {
using EntityHandles = CUtlVector<CEntityHandle>;
};

}
19 changes: 12 additions & 7 deletions Source/Entities/BaseEntity.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@
#include <CS2/Constants/SceneObjectAttributeNames.h>
#include <FeatureHelpers/LifeState.h>
#include <FeatureHelpers/TeamNumber.h>
#include <MemoryPatterns/PatternTypes/EntityPatternTypes.h>
#include <OutlineGlow/GlowSceneObjects.h>

#include <GameClasses/EntityIdentity.h>
#include <GameClasses/GameSceneNode.h>
#include "RenderComponent.h"

Expand All @@ -24,17 +26,20 @@ class BaseEntity {
return *this;
}

[[nodiscard]] EntityTypeInfo classify() const noexcept
[[nodiscard]] decltype(auto) entityIdentity() const noexcept
{
if (entity)
return hookContext.entityClassifier().classifyEntity(entity->identity->entityClass);
return {};
return hookContext.template make<EntityIdentity>(entity ? entity->identity : nullptr);
}

[[nodiscard]] decltype(auto) classify() const noexcept
{
return entityIdentity().classify();
}

template <template <typename...> typename T>
[[nodiscard]] decltype(auto) as() const noexcept
template <template <typename...> typename T, typename... Args>
[[nodiscard]] decltype(auto) as(Args&&... args) const noexcept
{
return hookContext.template make<T<HookContext>>(static_cast<typename T<HookContext>::RawType*>(entity));
return hookContext.template make<T<HookContext>>(static_cast<typename T<HookContext>::RawType*>(entity), std::forward<Args>(args)...);
}

template <template <typename...> typename EntityType>
Expand Down
2 changes: 2 additions & 0 deletions Source/Entities/BaseWeapon.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

#include <CS2/Classes/Entities/C_CSWeaponBase.h>
#include <CS2/Classes/CCSWeaponBaseVData.h>
#include <MemoryPatterns/PatternTypes/WeaponPatternTypes.h>
#include <MemoryPatterns/PatternTypes/WeaponVDataPatternTypes.h>
#include "BaseEntity.h"

template <typename HookContext>
Expand Down
1 change: 1 addition & 0 deletions Source/Entities/C4.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#pragma once

#include <CS2/Classes/Entities/WeaponEntities.h>
#include <MemoryPatterns/PatternTypes/C4PatternTypes.h>
#include "BaseWeapon.h"

template <typename HookContext>
Expand Down
1 change: 1 addition & 0 deletions Source/Entities/GlowProperty.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#pragma once

#include <CS2/Classes/CGlowProperty.h>
#include <MemoryPatterns/PatternTypes/GlowPropertyPatternTypes.h>

template <typename HookContext>
class GlowProperty {
Expand Down
1 change: 1 addition & 0 deletions Source/Entities/HostageServices.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

#include <CS2/Classes/CCSPlayer_HostageServices.h>
#include <GameClasses/EntitySystem.h>
#include <MemoryPatterns/PatternTypes/HostageServicesPatternTypes.h>

template <typename HookContext>
class HostageServices {
Expand Down
2 changes: 2 additions & 0 deletions Source/Entities/PlantedC4.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@

#include <optional>

#include <CS2/Classes/CPlantedC4.h>
#include <CS2/Constants/BombSiteIndex.h>
#include <CS2/Constants/EntityHandle.h>
#include <CS2/Constants/IconURLs.h>
#include <GameClasses/GlobalVars.h>
#include <MemoryPatterns/PatternTypes/PlantedC4PatternTypes.h>

#include "BaseEntity.h"

Expand Down
5 changes: 5 additions & 0 deletions Source/Entities/PlayerController.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,11 @@ class PlayerController {
return getPlayerColor(cs2::kPlayerColorsHalfSaturated);
}

[[nodiscard]] decltype(auto) playerColorIndex() const noexcept
{
return hookContext.clientPatternSearchResults().template get<OffsetToPlayerColor>().of(playerControllerPointer).toOptional();
}

private:
[[nodiscard]] std::optional<cs2::Color> getPlayerColor(std::span<const cs2::Color> playerColors) const noexcept
{
Expand Down
10 changes: 10 additions & 0 deletions Source/Entities/PlayerPawn.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@
#include <optional>

#include <CS2/Classes/Entities/C_CSPlayerPawn.h>
#include <CS2/Classes/ConVarTypes.h>
#include <CS2/Constants/EntityHandle.h>
#include <FeatureHelpers/LifeState.h>
#include <FeatureHelpers/TeamNumber.h>
#include <GameClasses/GameSceneNode.h>
#include <MemoryPatterns/PatternTypes/PlayerPawnPatternTypes.h>
#include <Utils/ColorUtils.h>

#include "BaseEntity.h"
Expand Down Expand Up @@ -37,6 +39,14 @@ class PlayerPawn {
return hookContext.template make<BaseEntity>(playerPawn);
}

template <template <typename...> typename EntityType>
[[nodiscard]] decltype(auto) cast() const noexcept
{
if (baseEntity().template is<EntityType>())
return hookContext.template make<EntityType<HookContext>>(static_cast<typename EntityType<HookContext>::RawType*>(playerPawn));
return hookContext.template make<EntityType<HookContext>>(nullptr);
}

[[nodiscard]] decltype(auto) weaponServices() const noexcept
{
return hookContext.template make<WeaponServices>(hookContext.clientPatternSearchResults().template get<OffsetToWeaponServices>().of(playerPawn).valueOr(nullptr));
Expand Down
30 changes: 30 additions & 0 deletions Source/Entities/PreviewPlayer.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#pragma once

#include <CS2/Classes/Entities/C_CSGO_PreviewPlayer.h>
#include "BaseEntity.h"

template <typename HookContext>
class PreviewPlayer {
public:
using RawType = cs2::C_CSGO_PreviewPlayer;

PreviewPlayer(HookContext& hookContext, cs2::C_CSGO_PreviewPlayer* previewPlayer) noexcept
: hookContext{hookContext}
, previewPlayer{previewPlayer}
{
}

[[nodiscard]] decltype(auto) baseEntity() const noexcept
{
return hookContext.template make<BaseEntity>(previewPlayer);
}

[[nodiscard]] operator cs2::C_CSGO_PreviewPlayer*() const noexcept
{
return previewPlayer;
}

private:
HookContext& hookContext;
cs2::C_CSGO_PreviewPlayer* previewPlayer;
};
1 change: 1 addition & 0 deletions Source/Entities/RenderComponent.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

#include <CS2/Classes/CRenderComponent.h>
#include <GameClasses/SceneObjectUpdaters.h>
#include <MemoryPatterns/PatternTypes/RenderComponentPatternTypes.h>

template <typename HookContext>
class RenderComponent {
Expand Down
1 change: 1 addition & 0 deletions Source/Entities/WeaponServices.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

#include <CS2/Classes/CCSPlayer_WeaponServices.h>
#include <CS2/Classes/Entities/C_CSWeaponBase.h>
#include <MemoryPatterns/PatternTypes/WeaponServicesPatternTypes.h>
#include "BaseWeapon.h"
#include "PlayerWeapons.h"

Expand Down
1 change: 0 additions & 1 deletion Source/FeatureHelpers/RenderingHookEntityLoop.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ class RenderingHookEntityLoop {
void run() const noexcept
{
hookContext.template make<EntitySystem>().forEachEntityIdentity([this](const auto& entityIdentity) { handleEntityIdentity(entityIdentity); });
hookContext.template make<ModelGlow>().onEntityListTraversed();
}

private:
Expand Down
6 changes: 6 additions & 0 deletions Source/Features/Visuals/ModelGlow/ModelGlow.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,12 @@ class ModelGlow {
hookContext.template make<WeaponModelGlow>().updateSceneObjectUpdaterHook(entity.template as<BaseWeapon>());
}

void updateSceneObjectUpdaterHook(auto&& playerPawnForModelGlowPreview) const noexcept
{
if (shouldUpdateSceneObjectUpdaterHook())
hookContext.template make<PlayerModelGlow>().updateSceneObjectUpdaterHook(playerPawnForModelGlowPreview);
}

void applyPlayerModelGlow(auto&& playerPawn) const noexcept
{
if (shouldRun())
Expand Down
1 change: 1 addition & 0 deletions Source/Features/Visuals/ModelGlow/ModelGlowState.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

#include <cstdint>
#include <CS2/Classes/Entities/C_CSPlayerPawn.h>
#include <CS2/Classes/Entities/C_CSWeaponBase.h>

enum class PlayerModelGlowColorType : std::uint8_t {
PlayerOrTeamColor,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
#pragma once

#include <algorithm>
#include <optional>

#include <CS2/Classes/Color.h>
#include <CS2/Constants/ColorConstants.h>
#include <FeatureHelpers/TeamNumber.h>
#include <Features/Visuals/ModelGlow/ModelGlowState.h>
#include <Utils/ColorUtils.h>

extern "C" std::uint64_t PlayerPawn_sceneObjectUpdater_asm(cs2::C_CSPlayerPawn* playerPawn, void* unknown, bool unknownBool) noexcept;

Expand Down Expand Up @@ -104,13 +111,46 @@ class PlayerModelGlow {
return getColorSaturated(playerPawn);
}

[[nodiscard]] std::optional<cs2::Color> getPlayerColor(auto playerColorIndex) const noexcept
{
return getPlayerColor(playerColorIndex, cs2::kPlayerColors);
}

[[nodiscard]] std::optional<cs2::Color> getPlayerColorSaturated(auto playerColorIndex) const noexcept
{
return getPlayerColor(playerColorIndex, cs2::kPlayerColorsSaturated);
}

[[nodiscard]] std::optional<cs2::Color> getPlayerColorHalfSaturated(auto playerColorIndex) const noexcept
{
return getPlayerColor(playerColorIndex, cs2::kPlayerColorsHalfSaturated);
}

[[nodiscard]] std::optional<cs2::Color> getPlayerColor(auto playerColorIndex, std::span<const cs2::Color> playerColors) const noexcept
{
if (playerColorIndex.hasValue() && playerColorIndex.value() >= 0 && std::cmp_less(playerColorIndex.value(), playerColors.size()))
return playerColors[playerColorIndex.value()];
return {};
}

[[nodiscard]] std::optional<cs2::Color> healthColor(auto&& playerPawn, float saturation = 0.7f) const noexcept
{
if (const auto healthValue = playerPawn.health(); healthValue.hasValue())
return getColorOfHealthFraction(saturation, std::clamp(healthValue.value(), 0, 100) / 100.0f);
return {};
}
[[nodiscard]] static cs2::Color getColorOfHealthFraction(float saturation, float healthFraction) noexcept
{
return color::HSBtoRGB(color::kRedHue + (color::kGreenHue - color::kRedHue) * healthFraction, saturation, 1.0f);
}

[[nodiscard]] cs2::Color getColorSaturated(auto&& playerPawn) const noexcept
{
if (state().playerModelGlowColorType == PlayerModelGlowColorType::HealthBased)
return playerPawn.healthColor(1.0f).value_or(cs2::kColorWhite);
return healthColor(playerPawn, 1.0f).value_or(cs2::kColorWhite);

if (state().playerModelGlowColorType == PlayerModelGlowColorType::PlayerOrTeamColor) {
if (const auto playerColor = playerPawn.playerController().getPlayerColorSaturated(); playerColor.has_value())
if (const auto playerColor = getPlayerColorSaturated(playerPawn.playerController().playerColorIndex()); playerColor.has_value())
return *playerColor;
}

Expand All @@ -124,10 +164,10 @@ class PlayerModelGlow {
[[nodiscard]] cs2::Color getColorHalfSaturated(auto&& playerPawn) const noexcept
{
if (state().playerModelGlowColorType == PlayerModelGlowColorType::HealthBased)
return playerPawn.healthColor(0.5f).value_or(cs2::kColorWhite);
return healthColor(playerPawn, 0.5f).value_or(cs2::kColorWhite);

if (state().playerModelGlowColorType == PlayerModelGlowColorType::PlayerOrTeamColor) {
if (const auto playerColor = playerPawn.playerController().getPlayerColorHalfSaturated(); playerColor.has_value())
if (const auto playerColor = getPlayerColorHalfSaturated(playerPawn.playerController().playerColorIndex()); playerColor.has_value())
return *playerColor;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#pragma once

#include <CS2/Classes/Entities/C_BaseEntity.h>
#include <Entities/BaseEntity.h>

template <typename HookContext>
class BaseEntityForModelGlowPreview {
public:
BaseEntityForModelGlowPreview(HookContext& hookContext, cs2::C_BaseEntity* baseEntity) noexcept
: hookContext{hookContext}
, baseEntity{baseEntity}
{
}

template <typename... Args>
void applySpawnProtectionEffectRecursively(Args&&... args) const noexcept
{
hookContext.template make<BaseEntity>(baseEntity).applySpawnProtectionEffectRecursively(std::forward<Args>(args)...);
}

private:
HookContext& hookContext;
cs2::C_BaseEntity* baseEntity;
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#pragma once

#include <CS2/Classes/Entities/CCSPlayerController.h>
#include <Utils/Optional.h>

template <typename HookContext>
class PlayerControllerForModelGlowPreview {
public:
explicit PlayerControllerForModelGlowPreview(HookContext& hookContext) noexcept
: hookContext{hookContext}
{
}

[[nodiscard]] Optional<cs2::CCSPlayerController::m_iCompTeammateColor> playerColorIndex() const noexcept
{
return hookContext.playerModelGlowPreviewState().previewPlayerColorIndex;
}

private:
HookContext& hookContext;
};
Loading

0 comments on commit 9da59db

Please sign in to comment.