фух заебался, давно панораму не трогал.
class CUIPanelRAII;
class CUIPanel : public VClass
{
public:
static CUIPanelRAII Create(const std::string_view& id);
void LoadLayout(const std::string_view& url, bool option)
{
CallVFunc<13>(url.data(), option);
}
std::string_view GetName() const noexcept
{
const auto result = Member<const char*>(0x10);
if (result)
return { result };
return {};
}
void RemoveAndDeleteChildren()
{
CallVFunc<50>();
}
};
class CUIPanelRAII
{
public:
CUIPanel& panel;
~CUIPanelRAII() noexcept
{
try {
panel.RemoveAndDeleteChildren();
}
catch (...) {}
}
};
class CPanel2D : public VClass
{
public:
auto& GetUI()
{
auto result = Member<CUIPanel*>(0x8);
if(!result)
throw std::runtime_error{ "CPanel2D::GetUI returned nullptr!" };
return *result;
}
};
class CTopLevelWindowSource2 : public VClass
{
public:
std::string_view GetName() const noexcept
{
const auto result = Member<const char*>(0x160);
if (result)
return { result };
return {};
}
CUIPanel& GetPanoramaView() const
{
if (const auto intermediate_result = Member<CUIPanel**>(0x88); intermediate_result)
if (const auto result = *intermediate_result; result)
return *result;
throw std::runtime_error{ "CTopLevelWindowSource2::GetPanoramaView is nullptr!" };
}
};
class CUIEngineSource2 : public VClass
{
public:
auto& GetTopLevelWindows() const noexcept
{
return Member<CUtlVector<CTopLevelWindowSource2*>>(0x60);
}
auto& GetDotaHUD()
{
const auto& windows = GetTopLevelWindows();
if (
const auto match = std::ranges::find_if(windows, [](const auto& window)
{
if(window)
return window->GetName() == "DotaHud";
return false;
});
match != windows.end() && match != nullptr
)
if(const auto ptr = *match; ptr)
return *ptr;
throw std::runtime_error{"DotaHud top level window not found!"};
}
auto MakeSymbol(const std::string_view& string) const
{
return CallVFunc<120, std::uint16_t>(string.data());
}
protected:
friend class CUIPanel;
auto& CreatePanel(const std::string_view& symbol_str, const std::string_view& id, const CUIPanel& parent)
{
const auto symbol = MakeSymbol(symbol_str);
auto result = CallVFunc<29, CPanel2D*>(&symbol, id.data(), &parent);
if(!result)
throw std::runtime_error{ "PanoramaUI::CreatePanel returned nullptr!" };
return *result;
}
};
class CPanoramaUIEngine : public VClass
{
public:
static auto& Create()
{
static auto ptr = CreateInterface<CPanoramaUIEngine*>("panorama.dll", "PanoramaUIEngine");
return *ptr;
}
CUIEngineSource2& GetPanoramaSource2()
{
auto result = Member<CUIEngineSource2*>(0x28);
if (!result)
throw std::runtime_error{"PanoramaUI::CUIEngineSource2 is nullptr!"};
return *result;
}
};
CUIPanelRAII CUIPanel::Create(const std::string_view& id)
{
auto& panorama = CPanoramaUIEngine::Create().GetPanoramaSource2();
return { panorama.CreatePanel("Panel", id, panorama.GetDotaHUD().GetPanoramaView()).GetUI() };
}
инит
Logger::Create();
Logger::LogMessage("Injected at %s\n", FormatCurrentTime().data());
BenchmarkTimePoint Init{};
BenchmarkTimePoint patterns{};
PatternDB::ScanPatterns();
Logger::LogTiming("Pattern scan took %sms\n", patterns.GetElapsedMillisecondsAsString().data());
auto& panorama = CPanoramaUIEngine::Create().GetPanoramaSource2();
Logger::LogInfo("CPanoramaUIEngine: 0x%p\n", &CPanoramaUIEngine::Create());
Logger::LogInfo("CUIEngineSource2: 0x%p\n", &panorama);
CTopLevelWindowSource2& dotahud = panorama.GetDotaHUD();
Logger::LogInfo("DotaHUD CTopLevelWindowSource2: 0x%p\n", &dotahud);
Logger::LogInfo("DotaHUD CUIPanel: 0x%p\n", &dotahud.GetPanoramaView());
auto my_panel_raii = CUIPanel::Create("MyTestPanel");
Logger::LogInfo("MyTestPanel CUIPanel: 0x%p\n", &my_panel_raii.panel);
my_panel_raii.panel.LoadLayout(R"xml(file://{resources}/mypanel.xml)xml", false);
Logger::LogTiming("Initialization took %sms\n", Init.GetElapsedMillisecondsAsString().c_str());
AwaitEjection();
Logger::LogMessage("Ejected at %s\n", FormatCurrentTime().c_str());
Посмотреть вложение 196601
через файлики решил грузиться. файлик(mypanel.vxml_c) положил в dota 2 beta\game\dota\panorama(это {resources}).
компилил так(не знаю есть ли способы легче не занимался особо этой хуйней, так для теста):
скачал воркшоп тулс в стиме(это длс для доты)
скачал
шаблонную кастомку кр4(и закинул файлы куда надо из архива), потом зашел в dota 2 beta\content\dota_addons\barebones\panorama, закинул туда свой файлик(mypanel.xml)(<root><Panel><Label text="GayPanel"/></Panel></root>), потом зашел в dota 2 beta\content\dota_addons\barebones\panorama\layout\custom_game\custom_ui_manifest.xml там ближе к концу добавил строчку
<CustomUIElement type="Hud" layoutfile="file://{resources}/mypanel.xml" />
она подгружает мой хмл файлик в кастомку(нужно чтобы он скомпилился иначе его заингорит габен при сборке кастомки)
потом запускаю доту с тулсами(со стима) выбираю barebones, захожу в хаммер, file->open->dota 2 beta\content\dota_addons\barebones\maps\playground.vmap, дальше f9(или file->build map...) жду
дальше забираю свое говно из C:\Users\user\Desktop\Programs\Steam\steamapps\common\dota 2 beta\game\dota_addons\barebones\panorama
кидаю в dota 2 beta\game\dota\panorama