Skip to content
Open
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
4 changes: 3 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 3.8)

project("HitmanAbsolutionSDK" C CXX)
project("HitmanAbsolutionSDK" CXX)

set(CMAKE_CXX_STANDARD 23)
set(GAME_INSTALL_PATH "" CACHE PATH "Path of Hitman Absolution folder.")
Expand All @@ -25,7 +25,9 @@ set(MODS
Editor
Noclip
HUD
HUDPersist
Camera
LevelTimer
)

foreach(MOD IN LISTS MODS)
Expand Down
12 changes: 11 additions & 1 deletion HitmanAbsolutionSDK/include/Glacier/UI/EHUDItem.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,15 @@ enum EHUDItem
HUD_ITEM_DARE_TIMER = 11,
HUD_ITEM_PROFILE_DATA = 12,
HUD_ITEM_DEBUGLOG = 13,
HUD_ITEM_NUM = 14
HUD_ITEM_SCORE_INFO_MESSAGE = 14,
HUD_ITEM_RATING_TRACKER = 15,
HUD_ITEM_UNKNOWN_1 = 16,
HUD_ITEM_TARGET_TRACKER = 17,
HUD_ITEM_UNKNOWN_2 = 18,
HUD_ITEM_UNKNOWN_3 = 19,
HUD_ITEM_HEALTH_BAR = 20,
HUD_ITEM_OBJECTIVE_MESSAGE = 21,
HUD_ITEM_ITEM_HOTBAR = 22,
HUD_ITEM_NUM = 23,

};
29 changes: 29 additions & 0 deletions Mods/HUDPersist/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
cmake_minimum_required(VERSION 3.8)

file(GLOB_RECURSE HEADER_FILES
CONFIGURE_DEPENDS
include/*.h
)

file(GLOB_RECURSE SRC_FILES
CONFIGURE_DEPENDS
src/*.cpp
src/*.c
)

add_library(HUDPersist SHARED
${HEADER_FILES}
${SRC_FILES}
)

target_include_directories(HUDPersist PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/include
)

target_link_libraries(HUDPersist PRIVATE
HitmanAbsolutionSDK
)

install(TARGETS HUDPersist
RUNTIME DESTINATION bin/mods
)
22 changes: 22 additions & 0 deletions Mods/HUDPersist/include/HUDPersist.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#pragma once

#include <Glacier/SGameUpdateEvent.h>

#include <ModInterface.h>

class HUDPersist : public ModInterface
{
public:
HUDPersist();
~HUDPersist();

void OnEngineInitialized() override;
void OnDrawMenu() override;

private:
void OnFrameUpdate(const SGameUpdateEvent& updateEvent);

bool isHUDPersistEnabled;
};

DECLARE_MOD(HUDPersist)
56 changes: 56 additions & 0 deletions Mods/HUDPersist/src/HUDPersist.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
#include <IconsMaterialDesign.h>

#include "imgui.h"

#include "Glacier/ZGameLoopManager.h"
#include "Glacier/ZLevelManager.h"
#include "Glacier/UI/ZHUDManager.h"
#include "Glacier/UI/EHUDFadeReason.h"
#include "Glacier/Player/ZHitman5.h"

#include "Hooks.h"
#include "HUDPersist.h"

// Bitmask covering all HUD_ITEM_NUM elements
static constexpr unsigned int ALL_HUD_ELEMENTS = (1u << HUD_ITEM_NUM) - 1;

HUDPersist::HUDPersist() :
isHUDPersistEnabled(true)
{
}

HUDPersist::~HUDPersist()
{
const ZMemberDelegate<HUDPersist, void(const SGameUpdateEvent&)> delegate(this, &HUDPersist::OnFrameUpdate);

GameLoopManager->UnregisterForFrameUpdate(delegate);
}

void HUDPersist::OnEngineInitialized()
{
const ZMemberDelegate<HUDPersist, void(const SGameUpdateEvent&)> delegate(this, &HUDPersist::OnFrameUpdate);

GameLoopManager->RegisterForFrameUpdate(delegate, 1);
}

void HUDPersist::OnDrawMenu()
{
ImGui::Checkbox(ICON_MD_SELF_IMPROVEMENT " HUD Persist", &isHUDPersistEnabled);
}

void HUDPersist::OnFrameUpdate(const SGameUpdateEvent& updateEvent)
{
ZHitman5* hitman = LevelManager->GetHitman().GetRawPointer();

if (!isHUDPersistEnabled || !hitman)
{
return;
}

for (int reason = 0; reason < HUD_FADE_REASON_NUM; ++reason)
{
HUDManager->FadeHUDElements(ALL_HUD_ELEMENTS, static_cast<EHUDFadeReason>(reason), true, 0.0f);
}
}

DEFINE_MOD(HUDPersist);
29 changes: 29 additions & 0 deletions Mods/LevelTimer/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
cmake_minimum_required(VERSION 3.8)

file(GLOB_RECURSE HEADER_FILES
CONFIGURE_DEPENDS
include/*.h
)

file(GLOB_RECURSE SRC_FILES
CONFIGURE_DEPENDS
src/*.cpp
src/*.c
)

add_library(LevelTimer SHARED
${HEADER_FILES}
${SRC_FILES}
)

target_include_directories(LevelTimer PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/include
)

target_link_libraries(LevelTimer PRIVATE
HitmanAbsolutionSDK
)

install(TARGETS LevelTimer
RUNTIME DESTINATION bin/mods
)
31 changes: 31 additions & 0 deletions Mods/LevelTimer/include/LevelTimer.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#pragma once

#include <Glacier/SGameUpdateEvent.h>
#include <Glacier/Scene/ZEntitySceneContext.h>
#include <ModInterface.h>

void __fastcall ZEntitySceneContext_CreateSceneHook(ZEntitySceneContext* pThis, int edx, const ZString& sStreamingState);
void __fastcall ZEntitySceneContext_ClearSceneHook(ZEntitySceneContext* pThis, int edx, bool bFullyUnloadScene);

class LevelTimer : public ModInterface
{
public:
LevelTimer();
~LevelTimer();

void Initialize() override;
void OnEngineInitialized() override;
void OnDrawMenu() override;
void OnDrawUI(bool hasFocus) override;

void OnCreateScene(ZEntitySceneContext* entitySceneContext, const ZString& streamingState);
void OnClearScene(ZEntitySceneContext* entitySceneContext, bool fullyUnloadScene);

private:
void OnFrameUpdate(const SGameUpdateEvent& updateEvent);

float m_elapsedSeconds;
bool isLevelTimerEnabled;
};

DECLARE_MOD(LevelTimer)
91 changes: 91 additions & 0 deletions Mods/LevelTimer/src/LevelTimer.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
#include <IconsMaterialDesign.h>

#include "imgui.h"
#include "Glacier/ZGameLoopManager.h"
#include "Glacier/ZLevelManager.h"
#include "Glacier/UI/ZHUDManager.h"

#include "Hooks.h"
#include "LevelTimer.h"

LevelTimer::LevelTimer() : m_elapsedSeconds(0.f), isLevelTimerEnabled(true) {}

LevelTimer::~LevelTimer()
{
const ZMemberDelegate<LevelTimer, void(const SGameUpdateEvent&)> delegate(this, &LevelTimer::OnFrameUpdate);
GameLoopManager->UnregisterForFrameUpdate(delegate);

Hooks::ZEntitySceneContext_CreateScene.RemoveHook();
Hooks::ZEntitySceneContext_ClearScene.RemoveHook();
}

void LevelTimer::Initialize()
{
ModInterface::Initialize();

Hooks::ZEntitySceneContext_CreateScene.CreateHook("ZEntitySceneContext::CreateScene", 0x4479E0, ZEntitySceneContext_CreateSceneHook);
Hooks::ZEntitySceneContext_ClearScene.CreateHook("ZEntitySceneContext::ClearScene", 0x265A80, ZEntitySceneContext_ClearSceneHook);

Hooks::ZEntitySceneContext_CreateScene.EnableHook();
Hooks::ZEntitySceneContext_ClearScene.EnableHook();
}

void LevelTimer::OnEngineInitialized()
{
const ZMemberDelegate<LevelTimer, void(const SGameUpdateEvent&)> delegate(this, &LevelTimer::OnFrameUpdate);
GameLoopManager->RegisterForFrameUpdate(delegate, 1);
}

void LevelTimer::OnFrameUpdate(const SGameUpdateEvent& updateEvent)
{
m_elapsedSeconds += static_cast<float>(updateEvent.m_GameTimeDelta.ToSeconds());
}

void LevelTimer::OnCreateScene(ZEntitySceneContext* entitySceneContext, const ZString& streamingState)
{
m_elapsedSeconds = 0.f;
}

void LevelTimer::OnClearScene(ZEntitySceneContext* entitySceneContext, bool fullyUnloadScene)
{
}

void LevelTimer::OnDrawMenu()
{
ImGui::Checkbox(ICON_MD_SELF_IMPROVEMENT " Level timer", &isLevelTimerEnabled);
}

void LevelTimer::OnDrawUI(bool hasFocus)
{
ZHitman5* hitman = LevelManager->GetHitman().GetRawPointer();
bool isPaused = HUDManager->IsPauseMenuActive();

if (!isLevelTimerEnabled || !hitman || isPaused)
{
return;
}

int minutes = static_cast<int>(m_elapsedSeconds) / 60;
int seconds = static_cast<int>(m_elapsedSeconds) % 60;

auto& io = ImGui::GetIO();
ImGui::SetNextWindowPos(ImVec2(io.DisplaySize.x * 0.25f, io.DisplaySize.y * 0.012f), ImGuiCond_Always);
ImGui::Begin("Timer", nullptr, ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoBackground);
ImGui::SetWindowFontScale(3.5f);
ImGui::Text("%02d:%02d", minutes, seconds);
ImGui::End();
}

DEFINE_MOD(LevelTimer)

void __fastcall ZEntitySceneContext_CreateSceneHook(ZEntitySceneContext* pThis, int edx, const ZString& sStreamingState)
{
GetModInstance()->OnCreateScene(pThis, sStreamingState);
Hooks::ZEntitySceneContext_CreateScene.CallOriginalFunction(pThis, sStreamingState);
}

void __fastcall ZEntitySceneContext_ClearSceneHook(ZEntitySceneContext* pThis, int edx, bool bFullyUnloadScene)
{
GetModInstance()->OnClearScene(pThis, bFullyUnloadScene);
Hooks::ZEntitySceneContext_ClearScene.CallOriginalFunction(pThis, bFullyUnloadScene);
}
Loading