mirror of
https://github.com/goatcorp/Dalamud.git
synced 2025-12-12 10:17:22 +01:00
Merge branch 'master' into api13
This commit is contained in:
commit
ed5fa493f9
289 changed files with 2454 additions and 1264 deletions
32
.github/workflows/backup.yml
vendored
Normal file
32
.github/workflows/backup.yml
vendored
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
name: Back up code to other forges
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 2 * * *' # Run every day at 2 AM
|
||||
workflow_dispatch: # Allow manual trigger
|
||||
|
||||
jobs:
|
||||
push-to-forges:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.repository == 'goatcorp/Dalamud'
|
||||
|
||||
steps:
|
||||
- name: Checkout the repository
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- uses: webfactory/ssh-agent@a6f90b1f127823b31d4d4a8d96047790581349bd #v0.9.1
|
||||
with:
|
||||
ssh-private-key: |
|
||||
${{ secrets.MIRROR_GITLAB_SYNC_KEY }}
|
||||
${{ secrets.MIRROR_CODEBERG_SYNC_KEY }}
|
||||
|
||||
- name: Add remotes & push
|
||||
env:
|
||||
GIT_SSH_COMMAND: "ssh -o StrictHostKeyChecking=accept-new"
|
||||
run: |
|
||||
git remote add gitlab git@gitlab.com:goatcorp/Dalamud.git
|
||||
git push gitlab --all --force
|
||||
git remote add codeberg git@codeberg.org:goatcorp/Dalamud.git
|
||||
git push codeberg --all --force
|
||||
|
|
@ -26,6 +26,38 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
|
|||
|
||||
RT_MANIFEST_THEMES RT_MANIFEST "themes.manifest"
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// String Table
|
||||
//
|
||||
|
||||
STRINGTABLE
|
||||
BEGIN
|
||||
IDS_APPNAME "Dalamud Boot"
|
||||
IDS_MSVCRT_ACTION_OPENDOWNLOAD
|
||||
"Download Microsoft Visual C++ Redistributable 2022\nExit the game and download the latest setup file from Microsoft."
|
||||
IDS_MSVCRT_ACTION_IGNORE
|
||||
"Ignore and Continue\nAttempt to continue with the currently installed version.\nDalamud or plugins may fail to load."
|
||||
IDS_MSVCRT_DIALOG_MAININSTRUCTION
|
||||
"Outdated Microsoft Visual C++ Redistributable"
|
||||
IDS_MSVCRT_DIALOG_CONTENT
|
||||
"The Microsoft Visual C++ Redistributable version detected on this computer (v{0}.{1}.{2}.{3}) is out of date and may not work with Dalamud."
|
||||
IDS_MSVCRT_DOWNLOADURL "https://aka.ms/vs/17/release/vc_redist.x64.exe"
|
||||
IDS_INITIALIZEFAIL_ACTION_ABORT "Abort\nExit the game."
|
||||
IDS_INITIALIZEFAIL_ACTION_CONTINUE
|
||||
"Load game without Dalamud\nThe game will launch without Dalamud enabled."
|
||||
IDS_INITIALIZEFAIL_DIALOG_MAININSTRUCTION "Failed to load Dalamud."
|
||||
IDS_INITIALIZEFAIL_DIALOG_CONTENT
|
||||
"An error is preventing Dalamud from being loaded along with the game."
|
||||
END
|
||||
|
||||
STRINGTABLE
|
||||
BEGIN
|
||||
IDS_INITIALIZEFAIL_DIALOG_FOOTER
|
||||
"Last operation: {0}\nHRESULT: 0x{1:08X}\nDescription: {2}"
|
||||
END
|
||||
|
||||
#endif // English (United States) resources
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@
|
|||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<LanguageStandard>stdcpp20</LanguageStandard>
|
||||
<LanguageStandard>stdcpp23</LanguageStandard>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
<PreprocessorDefinitions>CPPDLLTEMPLATE_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
|
|
@ -65,7 +65,7 @@
|
|||
<ClCompile>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>false</IntrinsicFunctions>
|
||||
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
|
||||
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
|
||||
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Use</PrecompiledHeader>
|
||||
<DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">26812</DisableSpecificWarnings>
|
||||
|
|
@ -80,7 +80,7 @@
|
|||
<ClCompile>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
|
||||
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
|
||||
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Use</PrecompiledHeader>
|
||||
<DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Release|x64'">26812</DisableSpecificWarnings>
|
||||
|
|
@ -133,6 +133,10 @@
|
|||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">NotUsing</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<ClCompile Include="DalamudStartInfo.cpp" />
|
||||
<ClCompile Include="error_info.cpp">
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">NotUsing</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<ClCompile Include="hooks.cpp" />
|
||||
<ClCompile Include="logging.cpp">
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader>
|
||||
|
|
@ -176,6 +180,7 @@
|
|||
<ClInclude Include="..\lib\TsudaKageyu-minhook\src\trampoline.h" />
|
||||
<ClInclude Include="crashhandler_shared.h" />
|
||||
<ClInclude Include="DalamudStartInfo.h" />
|
||||
<ClInclude Include="error_info.h" />
|
||||
<ClInclude Include="hooks.h" />
|
||||
<ClInclude Include="logging.h" />
|
||||
<ClInclude Include="ntdll.h" />
|
||||
|
|
@ -206,4 +211,4 @@
|
|||
<Copy SourceFiles="$(OutDir)$(TargetName).pdb" DestinationFolder="..\bin\$(Configuration)\" />
|
||||
<Copy SourceFiles="$(OutDir)nethost.dll" DestinationFolder="..\bin\$(Configuration)\" />
|
||||
</Target>
|
||||
</Project>
|
||||
</Project>
|
||||
|
|
@ -76,6 +76,9 @@
|
|||
<ClCompile Include="ntdll.cpp">
|
||||
<Filter>Dalamud.Boot DLL</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="error_info.cpp">
|
||||
<Filter>Common Boot</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\lib\CoreCLR\CoreCLR.h">
|
||||
|
|
@ -146,6 +149,9 @@
|
|||
<ClInclude Include="ntdll.h">
|
||||
<Filter>Dalamud.Boot DLL</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="error_info.h">
|
||||
<Filter>Common Boot</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="Dalamud.Boot.rc" />
|
||||
|
|
|
|||
|
|
@ -9,10 +9,125 @@
|
|||
#include "utils.h"
|
||||
#include "veh.h"
|
||||
#include "xivfixes.h"
|
||||
#include "resource.h"
|
||||
|
||||
HMODULE g_hModule;
|
||||
HINSTANCE g_hGameInstance = GetModuleHandleW(nullptr);
|
||||
|
||||
static void CheckMsvcrtVersion() {
|
||||
// Commit introducing inline mutex ctor: tagged vs-2022-17.14 (2024-06-18)
|
||||
// - https://github.com/microsoft/STL/commit/22a88260db4d754bbc067e2002430144d6ec5391
|
||||
// MSVC Redist versions:
|
||||
// - https://github.com/abbodi1406/vcredist/blob/master/source_links/README.md
|
||||
// - 14.40.33810.0 dsig 2024-04-28
|
||||
// - 14.40.33816.0 dsig 2024-09-11
|
||||
|
||||
constexpr WORD RequiredMsvcrtVersionComponents[] = {14, 40, 33816, 0};
|
||||
constexpr auto RequiredMsvcrtVersion = 0ULL
|
||||
| (static_cast<uint64_t>(RequiredMsvcrtVersionComponents[0]) << 48)
|
||||
| (static_cast<uint64_t>(RequiredMsvcrtVersionComponents[1]) << 32)
|
||||
| (static_cast<uint64_t>(RequiredMsvcrtVersionComponents[2]) << 16)
|
||||
| (static_cast<uint64_t>(RequiredMsvcrtVersionComponents[3]) << 0);
|
||||
|
||||
constexpr const wchar_t* RuntimeDllNames[] = {
|
||||
#ifdef _DEBUG
|
||||
L"msvcp140d.dll",
|
||||
L"vcruntime140d.dll",
|
||||
L"vcruntime140_1d.dll",
|
||||
#else
|
||||
L"msvcp140.dll",
|
||||
L"vcruntime140.dll",
|
||||
L"vcruntime140_1.dll",
|
||||
#endif
|
||||
};
|
||||
|
||||
uint64_t lowestVersion = 0;
|
||||
for (const auto& runtimeDllName : RuntimeDllNames) {
|
||||
const utils::loaded_module mod(GetModuleHandleW(runtimeDllName));
|
||||
if (!mod) {
|
||||
logging::E("MSVCRT DLL not found: {}", runtimeDllName);
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto path = mod.path()
|
||||
.transform([](const auto& p) { return p.wstring(); })
|
||||
.value_or(runtimeDllName);
|
||||
|
||||
if (const auto versionResult = mod.get_file_version()) {
|
||||
const auto& versionFull = versionResult->get();
|
||||
logging::I("MSVCRT DLL {} has version {}.", path, utils::format_file_version(versionFull));
|
||||
|
||||
const auto version = 0ULL |
|
||||
(static_cast<uint64_t>(versionFull.dwFileVersionMS) << 32) |
|
||||
(static_cast<uint64_t>(versionFull.dwFileVersionLS) << 0);
|
||||
|
||||
if (version < RequiredMsvcrtVersion && (lowestVersion == 0 || lowestVersion > version))
|
||||
lowestVersion = version;
|
||||
} else {
|
||||
logging::E("Failed to detect MSVCRT DLL version for {}: {}", path, versionResult.error().describe());
|
||||
}
|
||||
}
|
||||
|
||||
if (!lowestVersion)
|
||||
return;
|
||||
|
||||
enum IdTaskDialogAction {
|
||||
IdTaskDialogActionOpenDownload = 101,
|
||||
IdTaskDialogActionIgnore,
|
||||
};
|
||||
|
||||
const TASKDIALOG_BUTTON buttons[]{
|
||||
{IdTaskDialogActionOpenDownload, MAKEINTRESOURCEW(IDS_MSVCRT_ACTION_OPENDOWNLOAD)},
|
||||
{IdTaskDialogActionIgnore, MAKEINTRESOURCEW(IDS_MSVCRT_ACTION_IGNORE)},
|
||||
};
|
||||
|
||||
const WORD lowestVersionComponents[]{
|
||||
static_cast<WORD>(lowestVersion >> 48),
|
||||
static_cast<WORD>(lowestVersion >> 32),
|
||||
static_cast<WORD>(lowestVersion >> 16),
|
||||
static_cast<WORD>(lowestVersion >> 0),
|
||||
};
|
||||
|
||||
const auto dialogContent = std::vformat(
|
||||
utils::get_string_resource(IDS_MSVCRT_DIALOG_CONTENT),
|
||||
std::make_wformat_args(
|
||||
lowestVersionComponents[0],
|
||||
lowestVersionComponents[1],
|
||||
lowestVersionComponents[2],
|
||||
lowestVersionComponents[3]));
|
||||
|
||||
const TASKDIALOGCONFIG config{
|
||||
.cbSize = sizeof config,
|
||||
.hInstance = g_hModule,
|
||||
.dwFlags = TDF_CAN_BE_MINIMIZED | TDF_ALLOW_DIALOG_CANCELLATION | TDF_USE_COMMAND_LINKS,
|
||||
.pszWindowTitle = MAKEINTRESOURCEW(IDS_APPNAME),
|
||||
.pszMainIcon = MAKEINTRESOURCEW(IDI_ICON1),
|
||||
.pszMainInstruction = MAKEINTRESOURCEW(IDS_MSVCRT_DIALOG_MAININSTRUCTION),
|
||||
.pszContent = dialogContent.c_str(),
|
||||
.cButtons = _countof(buttons),
|
||||
.pButtons = buttons,
|
||||
.nDefaultButton = IdTaskDialogActionOpenDownload,
|
||||
};
|
||||
|
||||
int buttonPressed;
|
||||
if (utils::scoped_dpi_awareness_context ctx;
|
||||
FAILED(TaskDialogIndirect(&config, &buttonPressed, nullptr, nullptr)))
|
||||
buttonPressed = IdTaskDialogActionOpenDownload;
|
||||
|
||||
switch (buttonPressed) {
|
||||
case IdTaskDialogActionOpenDownload:
|
||||
ShellExecuteW(
|
||||
nullptr,
|
||||
L"open",
|
||||
utils::get_string_resource(IDS_MSVCRT_DOWNLOADURL).c_str(),
|
||||
nullptr,
|
||||
nullptr,
|
||||
SW_SHOW);
|
||||
ExitProcess(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
HRESULT WINAPI InitializeImpl(LPVOID lpParam, HANDLE hMainThreadContinue) {
|
||||
g_startInfo.from_envvars();
|
||||
|
||||
|
|
@ -24,7 +139,7 @@ HRESULT WINAPI InitializeImpl(LPVOID lpParam, HANDLE hMainThreadContinue) {
|
|||
}
|
||||
|
||||
if (g_startInfo.BootShowConsole)
|
||||
ConsoleSetup(L"Dalamud Boot");
|
||||
ConsoleSetup(utils::get_string_resource(IDS_APPNAME).c_str());
|
||||
|
||||
logging::update_dll_load_status(true);
|
||||
|
||||
|
|
@ -94,6 +209,8 @@ HRESULT WINAPI InitializeImpl(LPVOID lpParam, HANDLE hMainThreadContinue) {
|
|||
if ((g_startInfo.BootWaitMessageBox & DalamudStartInfo::WaitMessageboxFlags::BeforeInitialize) != DalamudStartInfo::WaitMessageboxFlags::None)
|
||||
MessageBoxW(nullptr, L"Press OK to continue (BeforeInitialize)", L"Dalamud Boot", MB_OK);
|
||||
|
||||
CheckMsvcrtVersion();
|
||||
|
||||
if (g_startInfo.BootDebugDirectX) {
|
||||
logging::I("Enabling DirectX Debugging.");
|
||||
|
||||
|
|
@ -159,7 +276,7 @@ HRESULT WINAPI InitializeImpl(LPVOID lpParam, HANDLE hMainThreadContinue) {
|
|||
|
||||
if (minHookLoaded) {
|
||||
logging::I("Applying fixes...");
|
||||
xivfixes::apply_all(true);
|
||||
std::thread([] { xivfixes::apply_all(true); }).join();
|
||||
logging::I("Fixes OK");
|
||||
} else {
|
||||
logging::W("Skipping fixes, as MinHook has failed to load.");
|
||||
|
|
@ -170,11 +287,14 @@ HRESULT WINAPI InitializeImpl(LPVOID lpParam, HANDLE hMainThreadContinue) {
|
|||
while (!IsDebuggerPresent())
|
||||
Sleep(100);
|
||||
logging::I("Debugger attached.");
|
||||
__debugbreak();
|
||||
}
|
||||
|
||||
const auto fs_module_path = utils::get_module_path(g_hModule);
|
||||
const auto runtimeconfig_path = std::filesystem::path(fs_module_path).replace_filename(L"Dalamud.runtimeconfig.json").wstring();
|
||||
const auto module_path = std::filesystem::path(fs_module_path).replace_filename(L"Dalamud.dll").wstring();
|
||||
const auto fs_module_path = utils::loaded_module(g_hModule).path();
|
||||
if (!fs_module_path)
|
||||
return fs_module_path.error();
|
||||
const auto runtimeconfig_path = std::filesystem::path(*fs_module_path).replace_filename(L"Dalamud.runtimeconfig.json").wstring();
|
||||
const auto module_path = std::filesystem::path(*fs_module_path).replace_filename(L"Dalamud.dll").wstring();
|
||||
|
||||
// ============================== CLR ========================================= //
|
||||
|
||||
|
|
|
|||
26
Dalamud.Boot/error_info.cpp
Normal file
26
Dalamud.Boot/error_info.cpp
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
#include "error_info.h"
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <Windows.h>
|
||||
|
||||
DalamudBootError::DalamudBootError(DalamudBootErrorDescription dalamudErrorDescription, long hresult) noexcept
|
||||
: m_dalamudErrorDescription(dalamudErrorDescription)
|
||||
, m_hresult(hresult) {
|
||||
}
|
||||
|
||||
DalamudBootError::DalamudBootError(DalamudBootErrorDescription dalamudErrorDescription) noexcept
|
||||
: DalamudBootError(dalamudErrorDescription, E_FAIL) {
|
||||
}
|
||||
|
||||
const char* DalamudBootError::describe() const {
|
||||
switch (m_dalamudErrorDescription) {
|
||||
case DalamudBootErrorDescription::ModuleResourceLoadFail:
|
||||
return "Failed to load resource.";
|
||||
case DalamudBootErrorDescription::ModuleResourceVersionReadFail:
|
||||
return "Failed to query version information.";
|
||||
case DalamudBootErrorDescription::ModuleResourceVersionSignatureFail:
|
||||
return "Invalid version info found.";
|
||||
default:
|
||||
return "(unavailable)";
|
||||
}
|
||||
}
|
||||
42
Dalamud.Boot/error_info.h
Normal file
42
Dalamud.Boot/error_info.h
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
#pragma once
|
||||
|
||||
#include <expected>
|
||||
#include <string>
|
||||
|
||||
typedef unsigned long DWORD;
|
||||
typedef _Return_type_success_(return >= 0) long HRESULT;
|
||||
|
||||
enum class DalamudBootErrorDescription {
|
||||
None,
|
||||
ModulePathResolutionFail,
|
||||
ModuleResourceLoadFail,
|
||||
ModuleResourceVersionReadFail,
|
||||
ModuleResourceVersionSignatureFail,
|
||||
};
|
||||
|
||||
class DalamudBootError {
|
||||
DalamudBootErrorDescription m_dalamudErrorDescription;
|
||||
long m_hresult;
|
||||
|
||||
public:
|
||||
DalamudBootError(DalamudBootErrorDescription dalamudErrorDescription, long hresult) noexcept;
|
||||
DalamudBootError(DalamudBootErrorDescription dalamudErrorDescription) noexcept;
|
||||
|
||||
const char* describe() const;
|
||||
|
||||
operator HRESULT() const {
|
||||
return m_hresult;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
using DalamudExpected = std::expected<
|
||||
std::conditional_t<
|
||||
std::is_reference_v<T>,
|
||||
std::reference_wrapper<std::remove_reference_t<T>>,
|
||||
T
|
||||
>,
|
||||
DalamudBootError
|
||||
>;
|
||||
|
||||
using DalamudUnexpected = std::unexpected<DalamudBootError>;
|
||||
|
|
@ -84,19 +84,13 @@ void hooks::getprocaddress_singleton_import_hook::initialize() {
|
|||
const auto dllName = unicode::convert<std::string>(pData->Loaded.FullDllName->Buffer);
|
||||
|
||||
utils::loaded_module mod(pData->Loaded.DllBase);
|
||||
std::wstring version, description;
|
||||
try {
|
||||
version = utils::format_file_version(mod.get_file_version());
|
||||
} catch (...) {
|
||||
version = L"<unknown>";
|
||||
}
|
||||
|
||||
try {
|
||||
description = mod.get_description();
|
||||
} catch (...) {
|
||||
description = L"<unknown>";
|
||||
}
|
||||
|
||||
const auto version = mod.get_file_version()
|
||||
.transform([](const auto& v) { return utils::format_file_version(v.get()); })
|
||||
.value_or(L"<unknown>");
|
||||
|
||||
const auto description = mod.get_description()
|
||||
.value_or(L"<unknown>");
|
||||
|
||||
logging::I(R"({} "{}" ("{}" ver {}) has been loaded at 0x{:X} ~ 0x{:X} (0x{:X}); finding import table items to hook.)",
|
||||
LogTag, dllName, description, version,
|
||||
reinterpret_cast<size_t>(pData->Loaded.DllBase),
|
||||
|
|
@ -125,7 +119,9 @@ void hooks::getprocaddress_singleton_import_hook::hook_module(const utils::loade
|
|||
if (mod.is_current_process())
|
||||
return;
|
||||
|
||||
const auto path = unicode::convert<std::string>(mod.path().wstring());
|
||||
const auto path = mod.path()
|
||||
.transform([](const auto& p) { return unicode::convert<std::string>(p.wstring()); })
|
||||
.value_or("<unknown>");
|
||||
|
||||
for (const auto& [hModule, targetFns] : m_targetFns) {
|
||||
for (const auto& [targetFn, pfnThunk] : targetFns) {
|
||||
|
|
@ -133,7 +129,7 @@ void hooks::getprocaddress_singleton_import_hook::hook_module(const utils::loade
|
|||
if (void* pGetProcAddressImport; mod.find_imported_function_pointer(dllName.c_str(), targetFn.c_str(), 0, pGetProcAddressImport)) {
|
||||
auto& hook = m_hooks[hModule][targetFn][mod];
|
||||
if (!hook) {
|
||||
logging::I("{} Hooking {}!{} imported by {}", LogTag, dllName, targetFn, unicode::convert<std::string>(mod.path().wstring()));
|
||||
logging::I("{} Hooking {}!{} imported by {}", LogTag, dllName, targetFn, path);
|
||||
|
||||
hook.emplace(std::format("getprocaddress_singleton_import_hook::hook_module({}!{})", dllName, targetFn), static_cast<void**>(pGetProcAddressImport), pfnThunk);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,9 @@
|
|||
#define WIN32_LEAN_AND_MEAN
|
||||
#define NOMINMAX
|
||||
|
||||
// https://developercommunity.visualstudio.com/t/Access-violation-with-std::mutex::lock-a/10664660
|
||||
#define _DISABLE_CONSTEXPR_MUTEX_CONSTRUCTOR
|
||||
|
||||
// Windows Header Files (1)
|
||||
#include <Windows.h>
|
||||
|
||||
|
|
@ -21,6 +24,7 @@
|
|||
#include <iphlpapi.h>
|
||||
#include <PathCch.h>
|
||||
#include <Psapi.h>
|
||||
#include <shellapi.h>
|
||||
#include <ShlObj.h>
|
||||
#include <Shlwapi.h>
|
||||
#include <SubAuth.h>
|
||||
|
|
@ -51,6 +55,7 @@
|
|||
#include <set>
|
||||
#include <span>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <type_traits>
|
||||
|
||||
// https://www.akenotsuki.com/misc/srell/en/
|
||||
|
|
|
|||
|
|
@ -3,12 +3,23 @@
|
|||
// Used by Dalamud.Boot.rc
|
||||
//
|
||||
#define IDI_ICON1 101
|
||||
#define IDS_APPNAME 102
|
||||
#define IDS_MSVCRT_ACTION_OPENDOWNLOAD 103
|
||||
#define IDS_MSVCRT_ACTION_IGNORE 104
|
||||
#define IDS_MSVCRT_DIALOG_MAININSTRUCTION 105
|
||||
#define IDS_MSVCRT_DIALOG_CONTENT 106
|
||||
#define IDS_MSVCRT_DOWNLOADURL 107
|
||||
#define IDS_INITIALIZEFAIL_ACTION_ABORT 108
|
||||
#define IDS_INITIALIZEFAIL_ACTION_CONTINUE 109
|
||||
#define IDS_INITIALIZEFAIL_DIALOG_MAININSTRUCTION 110
|
||||
#define IDS_INITIALIZEFAIL_DIALOG_CONTENT 111
|
||||
#define IDS_INITIALIZEFAIL_DIALOG_FOOTER 112
|
||||
|
||||
// Next default values for new objects
|
||||
//
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
#ifndef APSTUDIO_READONLY_SYMBOLS
|
||||
#define _APS_NEXT_RESOURCE_VALUE 102
|
||||
#define _APS_NEXT_RESOURCE_VALUE 103
|
||||
#define _APS_NEXT_COMMAND_VALUE 40001
|
||||
#define _APS_NEXT_CONTROL_VALUE 1001
|
||||
#define _APS_NEXT_SYMED_VALUE 101
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
#include "logging.h"
|
||||
#include "utils.h"
|
||||
#include "resource.h"
|
||||
|
||||
HRESULT WINAPI InitializeImpl(LPVOID lpParam, HANDLE hMainThreadContinue);
|
||||
|
||||
|
|
@ -379,12 +380,50 @@ extern "C" void WINAPI RewrittenEntryPoint_AdjustedStack(RewrittenEntryPointPara
|
|||
auto desc = err.Description();
|
||||
if (desc.length() == 0)
|
||||
desc = err.ErrorMessage();
|
||||
if (MessageBoxW(nullptr, std::format(
|
||||
L"Failed to load Dalamud. Load game without Dalamud(yes) or abort(no)?\n\n{}\n{}",
|
||||
last_operation,
|
||||
desc.GetBSTR()).c_str(),
|
||||
L"Dalamud.Boot", MB_OK | MB_YESNO) == IDNO)
|
||||
ExitProcess(-1);
|
||||
|
||||
enum IdTaskDialogAction {
|
||||
IdTaskDialogActionAbort = 101,
|
||||
IdTaskDialogActionContinue,
|
||||
};
|
||||
|
||||
const TASKDIALOG_BUTTON buttons[]{
|
||||
{IdTaskDialogActionAbort, MAKEINTRESOURCEW(IDS_INITIALIZEFAIL_ACTION_ABORT)},
|
||||
{IdTaskDialogActionContinue, MAKEINTRESOURCEW(IDS_INITIALIZEFAIL_ACTION_CONTINUE)},
|
||||
};
|
||||
|
||||
const auto hru32 = static_cast<uint32_t>(hr);
|
||||
const auto footer = std::vformat(
|
||||
utils::get_string_resource(IDS_INITIALIZEFAIL_DIALOG_FOOTER),
|
||||
std::make_wformat_args(
|
||||
last_operation,
|
||||
hru32,
|
||||
desc.GetBSTR()));
|
||||
|
||||
const TASKDIALOGCONFIG config{
|
||||
.cbSize = sizeof config,
|
||||
.hInstance = g_hModule,
|
||||
.dwFlags = TDF_CAN_BE_MINIMIZED | TDF_ALLOW_DIALOG_CANCELLATION | TDF_USE_COMMAND_LINKS | TDF_EXPAND_FOOTER_AREA,
|
||||
.pszWindowTitle = MAKEINTRESOURCEW(IDS_APPNAME),
|
||||
.pszMainIcon = MAKEINTRESOURCEW(IDI_ICON1),
|
||||
.pszMainInstruction = MAKEINTRESOURCEW(IDS_INITIALIZEFAIL_DIALOG_MAININSTRUCTION),
|
||||
.pszContent = MAKEINTRESOURCEW(IDS_INITIALIZEFAIL_DIALOG_CONTENT),
|
||||
.cButtons = _countof(buttons),
|
||||
.pButtons = buttons,
|
||||
.nDefaultButton = IdTaskDialogActionAbort,
|
||||
.pszFooter = footer.c_str(),
|
||||
};
|
||||
|
||||
int buttonPressed;
|
||||
if (utils::scoped_dpi_awareness_context ctx;
|
||||
FAILED(TaskDialogIndirect(&config, &buttonPressed, nullptr, nullptr)))
|
||||
buttonPressed = IdTaskDialogActionAbort;
|
||||
|
||||
switch (buttonPressed) {
|
||||
case IdTaskDialogActionAbort:
|
||||
ExitProcess(-1);
|
||||
break;
|
||||
}
|
||||
|
||||
if (hMainThreadContinue) {
|
||||
CloseHandle(hMainThreadContinue);
|
||||
hMainThreadContinue = nullptr;
|
||||
|
|
|
|||
|
|
@ -3,22 +3,27 @@
|
|||
|
||||
#include "utils.h"
|
||||
|
||||
std::filesystem::path utils::loaded_module::path() const {
|
||||
std::wstring buf(MAX_PATH, L'\0');
|
||||
for (;;) {
|
||||
if (const auto len = GetModuleFileNameExW(GetCurrentProcess(), m_hModule, &buf[0], static_cast<DWORD>(buf.size())); len != buf.size()) {
|
||||
if (buf.empty())
|
||||
throw std::runtime_error(std::format("Failed to resolve module path: Win32 error {}", GetLastError()));
|
||||
DalamudExpected<std::filesystem::path> utils::loaded_module::path() const {
|
||||
for (std::wstring buf(MAX_PATH, L'\0');; buf.resize(buf.size() * 2)) {
|
||||
if (const auto len = GetModuleFileNameW(m_hModule, &buf[0], static_cast<DWORD>(buf.size()));
|
||||
len != buf.size()) {
|
||||
if (!len) {
|
||||
return DalamudUnexpected(
|
||||
std::in_place,
|
||||
DalamudBootErrorDescription::ModulePathResolutionFail,
|
||||
HRESULT_FROM_WIN32(GetLastError()));
|
||||
}
|
||||
|
||||
buf.resize(len);
|
||||
return buf;
|
||||
}
|
||||
|
||||
if (buf.size() * 2 < PATHCCH_MAX_CCH)
|
||||
buf.resize(buf.size() * 2);
|
||||
else if (auto p = std::filesystem::path(buf); exists(p))
|
||||
return p;
|
||||
else
|
||||
throw std::runtime_error("Failed to resolve module path: no amount of buffer size would fit the data");
|
||||
if (buf.size() > PATHCCH_MAX_CCH) {
|
||||
return DalamudUnexpected(
|
||||
std::in_place,
|
||||
DalamudBootErrorDescription::ModulePathResolutionFail,
|
||||
E_OUTOFMEMORY);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -144,66 +149,90 @@ void* utils::loaded_module::get_imported_function_pointer(const char* pcszDllNam
|
|||
throw std::runtime_error(std::format("Failed to find import for {}!{} ({}).", pcszDllName, pcszFunctionName ? pcszFunctionName : "<unnamed>", hintOrOrdinal));
|
||||
}
|
||||
|
||||
std::unique_ptr<std::remove_pointer_t<HGLOBAL>, decltype(&FreeResource)> utils::loaded_module::get_resource(LPCWSTR lpName, LPCWSTR lpType) const {
|
||||
DalamudExpected<std::unique_ptr<std::remove_pointer_t<HGLOBAL>, decltype(&FreeResource)>> utils::loaded_module::get_resource(LPCWSTR lpName, LPCWSTR lpType) const {
|
||||
const auto hres = FindResourceW(m_hModule, lpName, lpType);
|
||||
if (!hres)
|
||||
throw std::runtime_error("No such resource");
|
||||
|
||||
return DalamudUnexpected(std::in_place, DalamudBootErrorDescription::ModuleResourceLoadFail, GetLastError());
|
||||
|
||||
const auto hRes = LoadResource(m_hModule, hres);
|
||||
if (!hRes)
|
||||
throw std::runtime_error("LoadResource failure");
|
||||
return DalamudUnexpected(std::in_place, DalamudBootErrorDescription::ModuleResourceLoadFail, GetLastError());
|
||||
|
||||
return {hRes, &FreeResource};
|
||||
return std::unique_ptr<std::remove_pointer_t<HGLOBAL>, decltype(&FreeResource)>(hRes, &FreeResource);
|
||||
}
|
||||
|
||||
std::wstring utils::loaded_module::get_description() const {
|
||||
const auto rsrc = get_resource(MAKEINTRESOURCE(VS_VERSION_INFO), RT_VERSION);
|
||||
const auto pBlock = LockResource(rsrc.get());
|
||||
|
||||
DalamudExpected<std::wstring> utils::loaded_module::get_description() const {
|
||||
auto rsrc = get_resource(MAKEINTRESOURCE(VS_VERSION_INFO), RT_VERSION);
|
||||
if (!rsrc)
|
||||
return DalamudUnexpected(std::move(rsrc.error()));
|
||||
|
||||
const auto pBlock = LockResource(rsrc->get());
|
||||
|
||||
struct LANGANDCODEPAGE {
|
||||
WORD wLanguage;
|
||||
WORD wCodePage;
|
||||
} * lpTranslate;
|
||||
UINT cbTranslate;
|
||||
if (!VerQueryValueW(pBlock,
|
||||
TEXT("\\VarFileInfo\\Translation"),
|
||||
L"\\VarFileInfo\\Translation",
|
||||
reinterpret_cast<LPVOID*>(&lpTranslate),
|
||||
&cbTranslate)) {
|
||||
throw std::runtime_error("Invalid version information (1)");
|
||||
return DalamudUnexpected(
|
||||
std::in_place,
|
||||
DalamudBootErrorDescription::ModuleResourceVersionReadFail,
|
||||
HRESULT_FROM_WIN32(GetLastError()));
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < (cbTranslate / sizeof(LANGANDCODEPAGE)); i++) {
|
||||
wchar_t subblockNameBuf[64];
|
||||
*std::format_to_n(
|
||||
subblockNameBuf,
|
||||
_countof(subblockNameBuf),
|
||||
L"\\StringFileInfo\\{:04x}{:04x}\\FileDescription",
|
||||
lpTranslate[i].wLanguage,
|
||||
lpTranslate[i].wCodePage).out = 0;;
|
||||
|
||||
wchar_t* buf = nullptr;
|
||||
UINT size = 0;
|
||||
if (!VerQueryValueW(pBlock,
|
||||
std::format(L"\\StringFileInfo\\{:04x}{:04x}\\FileDescription",
|
||||
lpTranslate[i].wLanguage,
|
||||
lpTranslate[i].wCodePage).c_str(),
|
||||
reinterpret_cast<LPVOID*>(&buf),
|
||||
&size)) {
|
||||
if (!VerQueryValueW(pBlock, subblockNameBuf, reinterpret_cast<LPVOID*>(&buf), &size))
|
||||
continue;
|
||||
}
|
||||
|
||||
auto currName = std::wstring_view(buf, size);
|
||||
while (!currName.empty() && currName.back() == L'\0')
|
||||
currName = currName.substr(0, currName.size() - 1);
|
||||
if (const auto p = currName.find(L'\0'); p != std::string::npos)
|
||||
currName = currName.substr(0, p);
|
||||
if (currName.empty())
|
||||
continue;
|
||||
return std::wstring(currName);
|
||||
}
|
||||
|
||||
throw std::runtime_error("Invalid version information (2)");
|
||||
|
||||
return DalamudUnexpected(
|
||||
std::in_place,
|
||||
DalamudBootErrorDescription::ModuleResourceVersionReadFail,
|
||||
HRESULT_FROM_WIN32(ERROR_NOT_FOUND));
|
||||
}
|
||||
|
||||
VS_FIXEDFILEINFO utils::loaded_module::get_file_version() const {
|
||||
const auto rsrc = get_resource(MAKEINTRESOURCE(VS_VERSION_INFO), RT_VERSION);
|
||||
const auto pBlock = LockResource(rsrc.get());
|
||||
std::expected<std::reference_wrapper<const VS_FIXEDFILEINFO>, DalamudBootError> utils::loaded_module::get_file_version() const {
|
||||
auto rsrc = get_resource(MAKEINTRESOURCE(VS_VERSION_INFO), RT_VERSION);
|
||||
if (!rsrc)
|
||||
return DalamudUnexpected(std::move(rsrc.error()));
|
||||
|
||||
const auto pBlock = LockResource(rsrc->get());
|
||||
UINT size = 0;
|
||||
LPVOID lpBuffer = nullptr;
|
||||
if (!VerQueryValueW(pBlock, L"\\", &lpBuffer, &size))
|
||||
throw std::runtime_error("Failed to query version information.");
|
||||
if (!VerQueryValueW(pBlock, L"\\", &lpBuffer, &size)) {
|
||||
return std::unexpected<DalamudBootError>(
|
||||
std::in_place,
|
||||
DalamudBootErrorDescription::ModuleResourceVersionReadFail,
|
||||
HRESULT_FROM_WIN32(GetLastError()));
|
||||
}
|
||||
|
||||
const VS_FIXEDFILEINFO& versionInfo = *static_cast<const VS_FIXEDFILEINFO*>(lpBuffer);
|
||||
if (versionInfo.dwSignature != 0xfeef04bd)
|
||||
throw std::runtime_error("Invalid version info found.");
|
||||
if (versionInfo.dwSignature != 0xfeef04bd) {
|
||||
return std::unexpected<DalamudBootError>(
|
||||
std::in_place,
|
||||
DalamudBootErrorDescription::ModuleResourceVersionSignatureFail);
|
||||
}
|
||||
|
||||
return versionInfo;
|
||||
}
|
||||
|
||||
|
|
@ -353,7 +382,7 @@ const char* utils::signature_finder::result::resolve_jump_target(size_t instruct
|
|||
nmd_x86_instruction instruction{};
|
||||
if (!nmd_x86_decode(&Match[instructionOffset], NMD_X86_MAXIMUM_INSTRUCTION_LENGTH, &instruction, NMD_X86_MODE_64, NMD_X86_DECODER_FLAGS_ALL))
|
||||
throw std::runtime_error("Matched address does not have a valid assembly instruction");
|
||||
|
||||
|
||||
size_t numExplicitOperands = 0;
|
||||
for (size_t i = 0; i < instruction.num_operands; i++)
|
||||
numExplicitOperands += instruction.operands[i].is_implicit ? 0 : 1;
|
||||
|
|
@ -589,17 +618,10 @@ bool utils::is_running_on_wine() {
|
|||
return g_startInfo.Platform != "WINDOWS";
|
||||
}
|
||||
|
||||
std::filesystem::path utils::get_module_path(HMODULE hModule) {
|
||||
std::wstring buf(MAX_PATH, L'\0');
|
||||
while (true) {
|
||||
if (const auto res = GetModuleFileNameW(hModule, &buf[0], static_cast<int>(buf.size())); !res)
|
||||
throw std::runtime_error(std::format("GetModuleFileName failure: 0x{:X}", GetLastError()));
|
||||
else if (res < buf.size()) {
|
||||
buf.resize(res);
|
||||
return buf;
|
||||
} else
|
||||
buf.resize(buf.size() * 2);
|
||||
}
|
||||
std::wstring utils::get_string_resource(uint32_t resId) {
|
||||
LPCWSTR pstr;
|
||||
const auto len = LoadStringW(g_hModule, resId, reinterpret_cast<LPWSTR>(&pstr), 0);
|
||||
return std::wstring(pstr, len);
|
||||
}
|
||||
|
||||
HWND utils::try_find_game_window() {
|
||||
|
|
@ -625,7 +647,7 @@ void utils::wait_for_game_window() {
|
|||
|
||||
std::wstring utils::escape_shell_arg(const std::wstring& arg) {
|
||||
// https://docs.microsoft.com/en-us/archive/blogs/twistylittlepassagesallalike/everyone-quotes-command-line-arguments-the-wrong-way
|
||||
|
||||
|
||||
std::wstring res;
|
||||
if (!arg.empty() && arg.find_first_of(L" \t\n\v\"") == std::wstring::npos) {
|
||||
res.append(arg);
|
||||
|
|
@ -677,3 +699,22 @@ std::wstring utils::format_win32_error(DWORD err) {
|
|||
|
||||
return std::format(L"Win32 error ({}=0x{:X})", err, err);
|
||||
}
|
||||
|
||||
utils::scoped_dpi_awareness_context::scoped_dpi_awareness_context()
|
||||
: scoped_dpi_awareness_context(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2) {
|
||||
}
|
||||
|
||||
utils::scoped_dpi_awareness_context::scoped_dpi_awareness_context(DPI_AWARENESS_CONTEXT context) {
|
||||
const auto user32 = GetModuleHandleW(L"user32.dll");
|
||||
m_setThreadDpiAwarenessContext =
|
||||
user32
|
||||
? reinterpret_cast<decltype(&SetThreadDpiAwarenessContext)>(
|
||||
GetProcAddress(user32, "SetThreadDpiAwarenessContext"))
|
||||
: nullptr;
|
||||
m_old = m_setThreadDpiAwarenessContext ? m_setThreadDpiAwarenessContext(context) : DPI_AWARENESS_CONTEXT_UNAWARE;
|
||||
}
|
||||
|
||||
utils::scoped_dpi_awareness_context::~scoped_dpi_awareness_context() {
|
||||
if (m_setThreadDpiAwarenessContext)
|
||||
m_setThreadDpiAwarenessContext(m_old);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
#include <expected>
|
||||
#include <filesystem>
|
||||
#include <functional>
|
||||
#include <span>
|
||||
|
|
@ -7,6 +8,7 @@
|
|||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "error_info.h"
|
||||
#include "unicode.h"
|
||||
|
||||
namespace utils {
|
||||
|
|
@ -18,14 +20,13 @@ namespace utils {
|
|||
loaded_module(void* hModule) : m_hModule(reinterpret_cast<HMODULE>(hModule)) {}
|
||||
loaded_module(size_t hModule) : m_hModule(reinterpret_cast<HMODULE>(hModule)) {}
|
||||
|
||||
std::filesystem::path path() const;
|
||||
DalamudExpected<std::filesystem::path> path() const;
|
||||
|
||||
bool is_current_process() const { return m_hModule == GetModuleHandleW(nullptr); }
|
||||
bool owns_address(const void* pAddress) const;
|
||||
|
||||
operator HMODULE() const {
|
||||
return m_hModule;
|
||||
}
|
||||
operator HMODULE() const { return m_hModule; }
|
||||
operator bool() const { return m_hModule; }
|
||||
|
||||
size_t address_int() const { return reinterpret_cast<size_t>(m_hModule); }
|
||||
size_t image_size() const { return is_pe64() ? nt_header64().OptionalHeader.SizeOfImage : nt_header32().OptionalHeader.SizeOfImage; }
|
||||
|
|
@ -58,9 +59,9 @@ namespace utils {
|
|||
void* get_imported_function_pointer(const char* pcszDllName, const char* pcszFunctionName, uint32_t hintOrOrdinal) const;
|
||||
template<typename TFn> TFn** get_imported_function_pointer(const char* pcszDllName, const char* pcszFunctionName, uint32_t hintOrOrdinal) { return reinterpret_cast<TFn**>(get_imported_function_pointer(pcszDllName, pcszFunctionName, hintOrOrdinal)); }
|
||||
|
||||
[[nodiscard]] std::unique_ptr<std::remove_pointer_t<HGLOBAL>, decltype(&FreeResource)> get_resource(LPCWSTR lpName, LPCWSTR lpType) const;
|
||||
[[nodiscard]] std::wstring get_description() const;
|
||||
[[nodiscard]] VS_FIXEDFILEINFO get_file_version() const;
|
||||
[[nodiscard]] DalamudExpected<std::unique_ptr<std::remove_pointer_t<HGLOBAL>, decltype(&FreeResource)>> get_resource(LPCWSTR lpName, LPCWSTR lpType) const;
|
||||
[[nodiscard]] DalamudExpected<std::wstring> get_description() const;
|
||||
[[nodiscard]] DalamudExpected<const VS_FIXEDFILEINFO&> get_file_version() const;
|
||||
|
||||
static loaded_module current_process();
|
||||
static std::vector<loaded_module> all_modules();
|
||||
|
|
@ -269,7 +270,7 @@ namespace utils {
|
|||
|
||||
bool is_running_on_wine();
|
||||
|
||||
std::filesystem::path get_module_path(HMODULE hModule);
|
||||
std::wstring get_string_resource(uint32_t resId);
|
||||
|
||||
/// @brief Find the game main window.
|
||||
/// @return Handle to the game main window, or nullptr if it doesn't exist (yet).
|
||||
|
|
@ -280,4 +281,18 @@ namespace utils {
|
|||
std::wstring escape_shell_arg(const std::wstring& arg);
|
||||
|
||||
std::wstring format_win32_error(DWORD err);
|
||||
|
||||
class scoped_dpi_awareness_context {
|
||||
DPI_AWARENESS_CONTEXT m_old;
|
||||
decltype(&SetThreadDpiAwarenessContext) m_setThreadDpiAwarenessContext;
|
||||
|
||||
public:
|
||||
scoped_dpi_awareness_context();
|
||||
scoped_dpi_awareness_context(DPI_AWARENESS_CONTEXT);
|
||||
~scoped_dpi_awareness_context();
|
||||
scoped_dpi_awareness_context(const scoped_dpi_awareness_context&) = delete;
|
||||
scoped_dpi_awareness_context(scoped_dpi_awareness_context&&) = delete;
|
||||
scoped_dpi_awareness_context& operator=(const scoped_dpi_awareness_context&) = delete;
|
||||
scoped_dpi_awareness_context& operator=(scoped_dpi_awareness_context&&) = delete;
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -102,9 +102,13 @@ bool is_ffxiv_address(const wchar_t* module_name, const DWORD64 address)
|
|||
return false;
|
||||
}
|
||||
|
||||
static void append_injector_launch_args(std::vector<std::wstring>& args)
|
||||
static DalamudExpected<void> append_injector_launch_args(std::vector<std::wstring>& args)
|
||||
{
|
||||
args.emplace_back(L"--game=\"" + utils::loaded_module::current_process().path().wstring() + L"\"");
|
||||
if (auto path = utils::loaded_module::current_process().path())
|
||||
args.emplace_back(L"--game=\"" + path->wstring() + L"\"");
|
||||
else
|
||||
return DalamudUnexpected(std::in_place, std::move(path.error()));
|
||||
|
||||
switch (g_startInfo.DalamudLoadMethod) {
|
||||
case DalamudStartInfo::LoadMethod::Entrypoint:
|
||||
args.emplace_back(L"--mode=entrypoint");
|
||||
|
|
@ -155,6 +159,8 @@ static void append_injector_launch_args(std::vector<std::wstring>& args)
|
|||
args.emplace_back(szArgList[i]);
|
||||
LocalFree(szArgList);
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
LONG exception_handler(EXCEPTION_POINTERS* ex)
|
||||
|
|
@ -358,11 +364,20 @@ bool veh::add_handler(bool doFullDump, const std::string& workingDirectory)
|
|||
args.emplace_back(std::format(L"--process-handle={}", reinterpret_cast<size_t>(hInheritableCurrentProcess)));
|
||||
args.emplace_back(std::format(L"--exception-info-pipe-read-handle={}", reinterpret_cast<size_t>(hReadPipeInheritable->get())));
|
||||
args.emplace_back(std::format(L"--asset-directory={}", unicode::convert<std::wstring>(g_startInfo.AssetDirectory)));
|
||||
args.emplace_back(std::format(L"--log-directory={}", g_startInfo.BootLogPath.empty()
|
||||
? utils::loaded_module(g_hModule).path().parent_path().wstring()
|
||||
: std::filesystem::path(unicode::convert<std::wstring>(g_startInfo.BootLogPath)).parent_path().wstring()));
|
||||
if (const auto path = utils::loaded_module(g_hModule).path()) {
|
||||
args.emplace_back(std::format(L"--log-directory={}", g_startInfo.BootLogPath.empty()
|
||||
? path->parent_path().wstring()
|
||||
: std::filesystem::path(unicode::convert<std::wstring>(g_startInfo.BootLogPath)).parent_path().wstring()));
|
||||
} else {
|
||||
logging::W("Failed to read path of the Dalamud Boot module: {}", path.error().describe());
|
||||
return false;
|
||||
}
|
||||
|
||||
args.emplace_back(L"--");
|
||||
append_injector_launch_args(args);
|
||||
if (auto r = append_injector_launch_args(args); !r) {
|
||||
logging::W("Failed to generate injector launch args: {}", r.error().describe());
|
||||
return false;
|
||||
}
|
||||
|
||||
for (const auto& arg : args)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -8,12 +8,6 @@
|
|||
#include "ntdll.h"
|
||||
#include "utils.h"
|
||||
|
||||
template<typename T>
|
||||
static std::span<T> assume_nonempty_span(std::span<T> t, const char* descr) {
|
||||
if (t.empty())
|
||||
throw std::runtime_error(std::format("Unexpected empty span found: {}", descr));
|
||||
return t;
|
||||
}
|
||||
void xivfixes::unhook_dll(bool bApply) {
|
||||
static const auto LogTag = "[xivfixes:unhook_dll]";
|
||||
static const auto LogTagW = L"[xivfixes:unhook_dll]";
|
||||
|
|
@ -23,77 +17,90 @@ void xivfixes::unhook_dll(bool bApply) {
|
|||
|
||||
const auto mods = utils::loaded_module::all_modules();
|
||||
|
||||
const auto test_module = [&](size_t i, const utils::loaded_module & mod) {
|
||||
std::filesystem::path path;
|
||||
try {
|
||||
path = mod.path();
|
||||
std::wstring version, description;
|
||||
try {
|
||||
version = utils::format_file_version(mod.get_file_version());
|
||||
} catch (...) {
|
||||
version = L"<unknown>";
|
||||
}
|
||||
|
||||
try {
|
||||
description = mod.get_description();
|
||||
} catch (...) {
|
||||
description = L"<unknown>";
|
||||
}
|
||||
|
||||
logging::I(R"({} [{}/{}] Module 0x{:X} ~ 0x{:X} (0x{:X}): "{}" ("{}" ver {}))", LogTagW, i + 1, mods.size(), mod.address_int(), mod.address_int() + mod.image_size(), mod.image_size(), path.wstring(), description, version);
|
||||
} catch (const std::exception& e) {
|
||||
logging::W("{} [{}/{}] Module 0x{:X}: Failed to resolve path: {}", LogTag, i + 1, mods.size(), mod.address_int(), e.what());
|
||||
for (size_t i = 0; i < mods.size(); i++) {
|
||||
const auto& mod = mods[i];
|
||||
const auto path = mod.path();
|
||||
if (!path) {
|
||||
logging::W(
|
||||
"{} [{}/{}] Module 0x{:X}: Failed to resolve path: {}",
|
||||
LogTag,
|
||||
i + 1,
|
||||
mods.size(),
|
||||
mod.address_int(),
|
||||
path.error().describe());
|
||||
return;
|
||||
}
|
||||
|
||||
const auto moduleName = unicode::convert<std::string>(path.filename().wstring());
|
||||
const auto version = mod.get_file_version()
|
||||
.transform([](const auto& v) { return utils::format_file_version(v.get()); })
|
||||
.value_or(L"<unknown>");
|
||||
|
||||
std::vector<char> buf;
|
||||
std::string formatBuf;
|
||||
const auto description = mod.get_description()
|
||||
.value_or(L"<unknown>");
|
||||
|
||||
logging::I(
|
||||
R"({} [{}/{}] Module 0x{:X} ~ 0x{:X} (0x{:X}): "{}" ("{}" ver {}))",
|
||||
LogTagW,
|
||||
i + 1,
|
||||
mods.size(),
|
||||
mod.address_int(),
|
||||
mod.address_int() + mod.image_size(),
|
||||
mod.image_size(),
|
||||
path->wstring(),
|
||||
description,
|
||||
version);
|
||||
|
||||
const auto moduleName = unicode::convert<std::string>(path->filename().wstring());
|
||||
|
||||
const auto& sectionHeader = mod.section_header(".text");
|
||||
const auto section = mod.span_as<char>(sectionHeader.VirtualAddress, sectionHeader.Misc.VirtualSize);
|
||||
if (section.empty()) {
|
||||
logging::W("{} Error: .text[VA:VA + VS] is empty", LogTag);
|
||||
return;
|
||||
}
|
||||
|
||||
auto hFsDllRaw = CreateFileW(path->c_str(), GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, 0, nullptr);
|
||||
if (hFsDllRaw == INVALID_HANDLE_VALUE) {
|
||||
logging::W("{} Module loaded in current process but could not open file: Win32 error {}", LogTag, GetLastError());
|
||||
return;
|
||||
}
|
||||
|
||||
auto hFsDll = std::unique_ptr<void, decltype(&CloseHandle)>(hFsDllRaw, &CloseHandle);
|
||||
std::vector<char> buf(section.size());
|
||||
SetFilePointer(hFsDll.get(), sectionHeader.PointerToRawData, nullptr, FILE_CURRENT);
|
||||
if (DWORD read{}; ReadFile(hFsDll.get(), &buf[0], static_cast<DWORD>(buf.size()), &read, nullptr)) {
|
||||
if (read < section.size_bytes()) {
|
||||
logging::W("{} ReadFile: read {} bytes < requested {} bytes", LogTagW, read, section.size_bytes());
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
logging::I("{} ReadFile: Win32 error {}", LogTagW, GetLastError());
|
||||
return;
|
||||
}
|
||||
|
||||
const auto doRestore = g_startInfo.BootUnhookDlls.contains(unicode::convert<std::string>(path->filename().u8string()));
|
||||
try {
|
||||
const auto& sectionHeader = mod.section_header(".text");
|
||||
const auto section = assume_nonempty_span(mod.span_as<char>(sectionHeader.VirtualAddress, sectionHeader.Misc.VirtualSize), ".text[VA:VA+VS]");
|
||||
auto hFsDllRaw = CreateFileW(path.c_str(), GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, 0, nullptr);
|
||||
if (hFsDllRaw == INVALID_HANDLE_VALUE) {
|
||||
logging::W("{} Module loaded in current process but could not open file: Win32 error {}", LogTag, GetLastError());
|
||||
return;
|
||||
}
|
||||
auto hFsDll = std::unique_ptr<void, decltype(CloseHandle)*>(hFsDllRaw, &CloseHandle);
|
||||
|
||||
buf.resize(section.size());
|
||||
SetFilePointer(hFsDll.get(), sectionHeader.PointerToRawData, nullptr, FILE_CURRENT);
|
||||
if (DWORD read{}; ReadFile(hFsDll.get(), &buf[0], static_cast<DWORD>(buf.size()), &read, nullptr)) {
|
||||
if (read < section.size_bytes()) {
|
||||
logging::W("{} ReadFile: read {} bytes < requested {} bytes", LogTagW, read, section.size_bytes());
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
logging::I("{} ReadFile: Win32 error {}", LogTagW, GetLastError());
|
||||
return;
|
||||
}
|
||||
|
||||
const auto doRestore = g_startInfo.BootUnhookDlls.contains(unicode::convert<std::string>(path.filename().u8string()));
|
||||
|
||||
std::optional<utils::memory_tenderizer> tenderizer;
|
||||
for (size_t i = 0, instructionLength = 1, printed = 0; i < buf.size(); i += instructionLength) {
|
||||
if (section[i] == buf[i]) {
|
||||
std::string formatBuf;
|
||||
for (size_t inst = 0, instructionLength = 1, printed = 0; inst < buf.size(); inst += instructionLength) {
|
||||
if (section[inst] == buf[inst]) {
|
||||
instructionLength = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto rva = sectionHeader.VirtualAddress + i;
|
||||
const auto rva = sectionHeader.VirtualAddress + inst;
|
||||
nmd_x86_instruction instruction{};
|
||||
if (!nmd_x86_decode(§ion[i], section.size() - i, &instruction, NMD_X86_MODE_64, NMD_X86_DECODER_FLAGS_ALL)) {
|
||||
if (!nmd_x86_decode(§ion[inst], section.size() - inst, &instruction, NMD_X86_MODE_64, NMD_X86_DECODER_FLAGS_ALL)) {
|
||||
instructionLength = 1;
|
||||
if (printed < 64) {
|
||||
logging::W("{} {}+0x{:0X}: dd {:02X}", LogTag, moduleName, rva, static_cast<uint8_t>(section[i]));
|
||||
logging::W("{} {}+0x{:0X}: dd {:02X}", LogTag, moduleName, rva, static_cast<uint8_t>(section[inst]));
|
||||
printed++;
|
||||
}
|
||||
} else {
|
||||
instructionLength = instruction.length;
|
||||
if (printed < 64) {
|
||||
formatBuf.resize(128);
|
||||
nmd_x86_format(&instruction, &formatBuf[0], reinterpret_cast<size_t>(§ion[i]), NMD_X86_FORMAT_FLAGS_DEFAULT | NMD_X86_FORMAT_FLAGS_BYTES);
|
||||
nmd_x86_format(&instruction, &formatBuf[0], reinterpret_cast<size_t>(§ion[inst]), NMD_X86_FORMAT_FLAGS_DEFAULT | NMD_X86_FORMAT_FLAGS_BYTES);
|
||||
formatBuf.resize(strnlen(&formatBuf[0], formatBuf.size()));
|
||||
|
||||
const auto& directory = mod.data_directory(IMAGE_DIRECTORY_ENTRY_EXPORT);
|
||||
|
|
@ -103,25 +110,25 @@ void xivfixes::unhook_dll(bool bApply) {
|
|||
const auto functions = mod.span_as<DWORD>(exportDirectory.AddressOfFunctions, exportDirectory.NumberOfFunctions);
|
||||
|
||||
std::string resolvedExportName;
|
||||
for (size_t j = 0; j < names.size(); ++j) {
|
||||
for (size_t nameIndex = 0; nameIndex < names.size(); ++nameIndex) {
|
||||
std::string_view name;
|
||||
if (const char* pcszName = mod.address_as<char>(names[j]); pcszName < mod.address() || pcszName >= mod.address() + mod.image_size()) {
|
||||
if (const char* pcszName = mod.address_as<char>(names[nameIndex]); pcszName < mod.address() || pcszName >= mod.address() + mod.image_size()) {
|
||||
if (IsBadReadPtr(pcszName, 256)) {
|
||||
logging::W("{} Name #{} points to an invalid address outside the executable. Skipping.", LogTag, j);
|
||||
logging::W("{} Name #{} points to an invalid address outside the executable. Skipping.", LogTag, nameIndex);
|
||||
continue;
|
||||
}
|
||||
|
||||
name = std::string_view(pcszName, strnlen(pcszName, 256));
|
||||
logging::W("{} Name #{} points to a seemingly valid address outside the executable: {}", LogTag, j, name);
|
||||
logging::W("{} Name #{} points to a seemingly valid address outside the executable: {}", LogTag, nameIndex, name);
|
||||
}
|
||||
|
||||
if (ordinals[j] >= functions.size()) {
|
||||
logging::W("{} Ordinal #{} points to function index #{} >= #{}. Skipping.", LogTag, j, ordinals[j], functions.size());
|
||||
if (ordinals[nameIndex] >= functions.size()) {
|
||||
logging::W("{} Ordinal #{} points to function index #{} >= #{}. Skipping.", LogTag, nameIndex, ordinals[nameIndex], functions.size());
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto rva = functions[ordinals[j]];
|
||||
if (rva == §ion[i] - mod.address()) {
|
||||
const auto rva = functions[ordinals[nameIndex]];
|
||||
if (rva == §ion[inst] - mod.address()) {
|
||||
resolvedExportName = std::format("[export:{}]", name);
|
||||
break;
|
||||
}
|
||||
|
|
@ -135,7 +142,7 @@ void xivfixes::unhook_dll(bool bApply) {
|
|||
if (doRestore) {
|
||||
if (!tenderizer)
|
||||
tenderizer.emplace(section, PAGE_EXECUTE_READWRITE);
|
||||
memcpy(§ion[i], &buf[i], instructionLength);
|
||||
memcpy(§ion[inst], &buf[inst], instructionLength);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -147,21 +154,7 @@ void xivfixes::unhook_dll(bool bApply) {
|
|||
} catch (const std::exception& e) {
|
||||
logging::W("{} Error: {}", LogTag, e.what());
|
||||
}
|
||||
};
|
||||
|
||||
// This is needed since try and __try cannot be used in the same function. Lambdas circumvent the limitation.
|
||||
const auto windows_exception_handler = [&]() {
|
||||
for (size_t i = 0; i < mods.size(); i++) {
|
||||
const auto& mod = mods[i];
|
||||
__try {
|
||||
test_module(i, mod);
|
||||
} __except (EXCEPTION_EXECUTE_HANDLER) {
|
||||
logging::W("{} Error: Access Violation", LogTag);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
windows_exception_handler();
|
||||
}
|
||||
}
|
||||
|
||||
using TFnGetInputDeviceManager = void* ();
|
||||
|
|
@ -294,13 +287,11 @@ static bool is_xivalex(const std::filesystem::path& dllPath) {
|
|||
static bool is_openprocess_already_dealt_with() {
|
||||
static const auto s_value = [] {
|
||||
for (const auto& mod : utils::loaded_module::all_modules()) {
|
||||
try {
|
||||
if (is_xivalex(mod.path()))
|
||||
return true;
|
||||
|
||||
} catch (...) {
|
||||
// pass
|
||||
}
|
||||
const auto path = mod.path().value_or({});
|
||||
if (path.empty())
|
||||
continue;
|
||||
if (is_xivalex(path))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}();
|
||||
|
|
@ -650,43 +641,22 @@ void xivfixes::symbol_load_patches(bool bApply) {
|
|||
|
||||
void xivfixes::disable_game_debugging_protection(bool bApply) {
|
||||
static const char* LogTag = "[xivfixes:disable_game_debugging_protection]";
|
||||
static const std::vector<uint8_t> patchBytes = {
|
||||
0x31, 0xC0, // XOR EAX, EAX
|
||||
0x90, // NOP
|
||||
0x90, // NOP
|
||||
0x90, // NOP
|
||||
0x90 // NOP
|
||||
};
|
||||
static std::optional<hooks::import_hook<decltype(IsDebuggerPresent)>> s_hookIsDebuggerPresent;
|
||||
|
||||
if (!bApply)
|
||||
return;
|
||||
if (bApply) {
|
||||
if (!g_startInfo.BootEnabledGameFixes.contains("disable_game_debugging_protection")) {
|
||||
logging::I("{} Turned off via environment variable.", LogTag);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!g_startInfo.BootEnabledGameFixes.contains("disable_game_debugging_protection")) {
|
||||
logging::I("{} Turned off via environment variable.", LogTag);
|
||||
return;
|
||||
}
|
||||
|
||||
// Find IsDebuggerPresent in Framework.Tick()
|
||||
const char* matchPtr = utils::signature_finder()
|
||||
.look_in(utils::loaded_module(g_hGameInstance), ".text")
|
||||
.look_for_hex("FF 15 ?? ?? ?? ?? 85 C0 74 13 41")
|
||||
.find_one()
|
||||
.Match.data();
|
||||
|
||||
if (!matchPtr) {
|
||||
logging::E("{} Failed to find signature.", LogTag);
|
||||
return;
|
||||
}
|
||||
|
||||
void* address = const_cast<void*>(static_cast<const void*>(matchPtr));
|
||||
|
||||
DWORD oldProtect;
|
||||
if (VirtualProtect(address, patchBytes.size(), PAGE_EXECUTE_READWRITE, &oldProtect)) {
|
||||
memcpy(address, patchBytes.data(), patchBytes.size());
|
||||
VirtualProtect(address, patchBytes.size(), oldProtect, &oldProtect);
|
||||
logging::I("{} Patch applied at address 0x{:X}.", LogTag, reinterpret_cast<uintptr_t>(address));
|
||||
s_hookIsDebuggerPresent.emplace("kernel32.dll!IsDebuggerPresent", "kernel32.dll", "IsDebuggerPresent", 0);
|
||||
s_hookIsDebuggerPresent->set_detour([]() { return false; });
|
||||
logging::I("{} Enable", LogTag);
|
||||
} else {
|
||||
logging::E("{} Failed to change memory protection.", LogTag);
|
||||
if (s_hookIsDebuggerPresent) {
|
||||
logging::I("{} Disable", LogTag);
|
||||
s_hookIsDebuggerPresent.reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@
|
|||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<LanguageStandard>stdcpplatest</LanguageStandard>
|
||||
<LanguageStandard>stdcpp23</LanguageStandard>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
<PreprocessorDefinitions>CPPDLLTEMPLATE_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
|
|
@ -55,7 +55,7 @@
|
|||
<ClCompile>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>false</IntrinsicFunctions>
|
||||
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
|
||||
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
|
||||
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
|
|
@ -67,7 +67,7 @@
|
|||
<ClCompile>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
|
||||
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
|
||||
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
|
|
@ -108,4 +108,4 @@
|
|||
<Delete Files="$(OutDir)$(TargetName).lib" />
|
||||
<Delete Files="$(OutDir)$(TargetName).exp" />
|
||||
</Target>
|
||||
</Project>
|
||||
</Project>
|
||||
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
<PropertyGroup Label="Feature">
|
||||
<Description>XIV Launcher addon framework</Description>
|
||||
<DalamudVersion>13.0.0.0</DalamudVersion>
|
||||
<DalamudVersion>13.0.0.3</DalamudVersion>
|
||||
<AssemblyVersion>$(DalamudVersion)</AssemblyVersion>
|
||||
<Version>$(DalamudVersion)</Version>
|
||||
<FileVersion>$(DalamudVersion)</FileVersion>
|
||||
|
|
@ -68,7 +68,7 @@
|
|||
<PackageReference Include="goatcorp.Reloaded.Assembler" Version="1.0.14-goatcorp3" />
|
||||
<PackageReference Include="JetBrains.Annotations" Version="2024.2.0" />
|
||||
<PackageReference Include="Lumina" Version="$(LuminaVersion)" />
|
||||
<PackageReference Include="Microsoft.Extensions.ObjectPool" Version="9.0.0-preview.1.24081.5" />
|
||||
<PackageReference Include="Microsoft.Extensions.ObjectPool" Version="8.0.7" />
|
||||
<PackageReference Include="Microsoft.Windows.CsWin32" Version="0.3.183">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ public abstract unsafe class AddonArgs
|
|||
/// </summary>
|
||||
/// <param name="name">The name to check.</param>
|
||||
/// <returns>Whether it is the case.</returns>
|
||||
internal bool IsAddon(ReadOnlySpan<char> name)
|
||||
internal bool IsAddon(string name)
|
||||
{
|
||||
if (this.Addon.IsNull)
|
||||
return false;
|
||||
|
|
@ -46,12 +46,10 @@ public abstract unsafe class AddonArgs
|
|||
if (name.Length is 0 or > 32)
|
||||
return false;
|
||||
|
||||
var addonName = this.Addon.Name;
|
||||
|
||||
if (string.IsNullOrEmpty(addonName))
|
||||
if (string.IsNullOrEmpty(this.Addon.Name))
|
||||
return false;
|
||||
|
||||
return name == addonName;
|
||||
return name == this.Addon.Name;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ internal sealed class ClientState : IInternalDisposableService, IClientState
|
|||
private readonly ClientStateAddressResolver address;
|
||||
private readonly Hook<EventFramework.Delegates.SetTerritoryTypeId> setupTerritoryTypeHook;
|
||||
private readonly Hook<UIModule.Delegates.HandlePacket> uiModuleHandlePacketHook;
|
||||
private readonly Hook<LogoutCallbackInterface.Delegates.OnLogout> onLogoutHook;
|
||||
private Hook<LogoutCallbackInterface.Delegates.OnLogout> onLogoutHook;
|
||||
|
||||
[ServiceManager.ServiceDependency]
|
||||
private readonly Framework framework = Service<Framework>.Get();
|
||||
|
|
@ -64,14 +64,14 @@ internal sealed class ClientState : IInternalDisposableService, IClientState
|
|||
|
||||
this.setupTerritoryTypeHook = Hook<EventFramework.Delegates.SetTerritoryTypeId>.FromAddress(setTerritoryTypeAddr, this.SetupTerritoryTypeDetour);
|
||||
this.uiModuleHandlePacketHook = Hook<UIModule.Delegates.HandlePacket>.FromAddress((nint)UIModule.StaticVirtualTablePointer->HandlePacket, this.UIModuleHandlePacketDetour);
|
||||
this.onLogoutHook = Hook<LogoutCallbackInterface.Delegates.OnLogout>.FromAddress((nint)LogoutCallbackInterface.StaticVirtualTablePointer->OnLogout, this.OnLogoutDetour);
|
||||
|
||||
this.framework.Update += this.FrameworkOnOnUpdateEvent;
|
||||
this.networkHandlers.CfPop += this.NetworkHandlersOnCfPop;
|
||||
|
||||
this.setupTerritoryTypeHook.Enable();
|
||||
this.uiModuleHandlePacketHook.Enable();
|
||||
this.onLogoutHook.Enable();
|
||||
|
||||
this.framework.RunOnTick(this.Setup);
|
||||
}
|
||||
|
||||
private unsafe delegate void ProcessPacketPlayerSetupDelegate(nint a1, nint packet);
|
||||
|
|
@ -180,8 +180,25 @@ internal sealed class ClientState : IInternalDisposableService, IClientState
|
|||
this.networkHandlers.CfPop -= this.NetworkHandlersOnCfPop;
|
||||
}
|
||||
|
||||
private unsafe void Setup()
|
||||
{
|
||||
this.onLogoutHook = Hook<LogoutCallbackInterface.Delegates.OnLogout>.FromAddress((nint)AgentLobby.Instance()->LogoutCallbackInterface.VirtualTable->OnLogout, this.OnLogoutDetour);
|
||||
this.onLogoutHook.Enable();
|
||||
|
||||
this.TerritoryType = (ushort)GameMain.Instance()->CurrentTerritoryTypeId;
|
||||
}
|
||||
|
||||
private unsafe void SetupTerritoryTypeDetour(EventFramework* eventFramework, ushort territoryType)
|
||||
{
|
||||
this.SetTerritoryType(territoryType);
|
||||
this.setupTerritoryTypeHook.Original(eventFramework, territoryType);
|
||||
}
|
||||
|
||||
private unsafe void SetTerritoryType(ushort territoryType)
|
||||
{
|
||||
if (this.TerritoryType == territoryType)
|
||||
return;
|
||||
|
||||
Log.Debug("TerritoryType changed: {0}", territoryType);
|
||||
|
||||
this.TerritoryType = territoryType;
|
||||
|
|
@ -207,8 +224,6 @@ internal sealed class ClientState : IInternalDisposableService, IClientState
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.setupTerritoryTypeHook.Original(eventFramework, territoryType);
|
||||
}
|
||||
|
||||
private unsafe void UIModuleHandlePacketDetour(
|
||||
|
|
|
|||
|
|
@ -1031,6 +1031,13 @@ public enum SystemConfigOption
|
|||
[GameConfigOption("TitleScreenType", ConfigType.UInt)]
|
||||
TitleScreenType,
|
||||
|
||||
/// <summary>
|
||||
/// System option with the internal name DisplayObjectLimitType2.
|
||||
/// This option is a UInt.
|
||||
/// </summary>
|
||||
[GameConfigOption("DisplayObjectLimitType2", ConfigType.UInt)]
|
||||
DisplayObjectLimitType2,
|
||||
|
||||
/// <summary>
|
||||
/// System option with the internal name AccessibilitySoundVisualEnable.
|
||||
/// This option is a UInt.
|
||||
|
|
@ -1115,6 +1122,13 @@ public enum SystemConfigOption
|
|||
[GameConfigOption("CameraZoom", ConfigType.UInt)]
|
||||
CameraZoom,
|
||||
|
||||
/// <summary>
|
||||
/// System option with the internal name DynamicAroundRangeMode.
|
||||
/// This option is a UInt.
|
||||
/// </summary>
|
||||
[GameConfigOption("DynamicAroundRangeMode", ConfigType.UInt)]
|
||||
DynamicAroundRangeMode,
|
||||
|
||||
/// <summary>
|
||||
/// System option with the internal name DynamicRezoType.
|
||||
/// This option is a UInt.
|
||||
|
|
|
|||
|
|
@ -2032,6 +2032,13 @@ public enum UiConfigOption
|
|||
[GameConfigOption("NamePlateDispJobIconInInstanceOther", ConfigType.UInt)]
|
||||
NamePlateDispJobIconInInstanceOther,
|
||||
|
||||
/// <summary>
|
||||
/// UiConfig option with the internal name LogNamePlateDispEnemyCast.
|
||||
/// This option is a UInt.
|
||||
/// </summary>
|
||||
[GameConfigOption("LogNamePlateDispEnemyCast", ConfigType.UInt)]
|
||||
LogNamePlateDispEnemyCast,
|
||||
|
||||
/// <summary>
|
||||
/// UiConfig option with the internal name ActiveInfo.
|
||||
/// This option is a UInt.
|
||||
|
|
@ -2690,6 +2697,594 @@ public enum UiConfigOption
|
|||
[GameConfigOption("LogColorOtherClass", ConfigType.UInt)]
|
||||
LogColorOtherClass,
|
||||
|
||||
/// <summary>
|
||||
/// UiConfig option with the internal name LogChatBubbleEnableChatBubble.
|
||||
/// This option is a UInt.
|
||||
/// </summary>
|
||||
[GameConfigOption("LogChatBubbleEnableChatBubble", ConfigType.UInt)]
|
||||
LogChatBubbleEnableChatBubble,
|
||||
|
||||
/// <summary>
|
||||
/// UiConfig option with the internal name LogChatBubbleShowMax.
|
||||
/// This option is a UInt.
|
||||
/// </summary>
|
||||
[GameConfigOption("LogChatBubbleShowMax", ConfigType.UInt)]
|
||||
LogChatBubbleShowMax,
|
||||
|
||||
/// <summary>
|
||||
/// UiConfig option with the internal name LogChatBubbleShowOwnMessage.
|
||||
/// This option is a UInt.
|
||||
/// </summary>
|
||||
[GameConfigOption("LogChatBubbleShowOwnMessage", ConfigType.UInt)]
|
||||
LogChatBubbleShowOwnMessage,
|
||||
|
||||
/// <summary>
|
||||
/// UiConfig option with the internal name LogChatBubbleShowDuringBattle.
|
||||
/// This option is a UInt.
|
||||
/// </summary>
|
||||
[GameConfigOption("LogChatBubbleShowDuringBattle", ConfigType.UInt)]
|
||||
LogChatBubbleShowDuringBattle,
|
||||
|
||||
/// <summary>
|
||||
/// UiConfig option with the internal name LogChatBubbleSizeType.
|
||||
/// This option is a UInt.
|
||||
/// </summary>
|
||||
[GameConfigOption("LogChatBubbleSizeType", ConfigType.UInt)]
|
||||
LogChatBubbleSizeType,
|
||||
|
||||
/// <summary>
|
||||
/// UiConfig option with the internal name LogChatBubbleShowLargePvP.
|
||||
/// This option is a UInt.
|
||||
/// </summary>
|
||||
[GameConfigOption("LogChatBubbleShowLargePvP", ConfigType.UInt)]
|
||||
LogChatBubbleShowLargePvP,
|
||||
|
||||
/// <summary>
|
||||
/// UiConfig option with the internal name LogChatBubbleShowQuickChat.
|
||||
/// This option is a UInt.
|
||||
/// </summary>
|
||||
[GameConfigOption("LogChatBubbleShowQuickChat", ConfigType.UInt)]
|
||||
LogChatBubbleShowQuickChat,
|
||||
|
||||
/// <summary>
|
||||
/// UiConfig option with the internal name LogChatBubbleDispRowType.
|
||||
/// This option is a UInt.
|
||||
/// </summary>
|
||||
[GameConfigOption("LogChatBubbleDispRowType", ConfigType.UInt)]
|
||||
LogChatBubbleDispRowType,
|
||||
|
||||
/// <summary>
|
||||
/// UiConfig option with the internal name LogChatBubbleSayShowType.
|
||||
/// This option is a UInt.
|
||||
/// </summary>
|
||||
[GameConfigOption("LogChatBubbleSayShowType", ConfigType.UInt)]
|
||||
LogChatBubbleSayShowType,
|
||||
|
||||
/// <summary>
|
||||
/// UiConfig option with the internal name LogChatBubbleSayFontColor.
|
||||
/// This option is a UInt.
|
||||
/// </summary>
|
||||
[GameConfigOption("LogChatBubbleSayFontColor", ConfigType.UInt)]
|
||||
LogChatBubbleSayFontColor,
|
||||
|
||||
/// <summary>
|
||||
/// UiConfig option with the internal name LogChatBubbleSayWindowColor.
|
||||
/// This option is a UInt.
|
||||
/// </summary>
|
||||
[GameConfigOption("LogChatBubbleSayWindowColor", ConfigType.UInt)]
|
||||
LogChatBubbleSayWindowColor,
|
||||
|
||||
/// <summary>
|
||||
/// UiConfig option with the internal name LogChatBubbleYellShowType.
|
||||
/// This option is a UInt.
|
||||
/// </summary>
|
||||
[GameConfigOption("LogChatBubbleYellShowType", ConfigType.UInt)]
|
||||
LogChatBubbleYellShowType,
|
||||
|
||||
/// <summary>
|
||||
/// UiConfig option with the internal name LogChatBubbleYellFontColor.
|
||||
/// This option is a UInt.
|
||||
/// </summary>
|
||||
[GameConfigOption("LogChatBubbleYellFontColor", ConfigType.UInt)]
|
||||
LogChatBubbleYellFontColor,
|
||||
|
||||
/// <summary>
|
||||
/// UiConfig option with the internal name LogChatBubbleYellWindowColor.
|
||||
/// This option is a UInt.
|
||||
/// </summary>
|
||||
[GameConfigOption("LogChatBubbleYellWindowColor", ConfigType.UInt)]
|
||||
LogChatBubbleYellWindowColor,
|
||||
|
||||
/// <summary>
|
||||
/// UiConfig option with the internal name LogChatBubbleShoutShowType.
|
||||
/// This option is a UInt.
|
||||
/// </summary>
|
||||
[GameConfigOption("LogChatBubbleShoutShowType", ConfigType.UInt)]
|
||||
LogChatBubbleShoutShowType,
|
||||
|
||||
/// <summary>
|
||||
/// UiConfig option with the internal name LogChatBubbleShoutFontColor.
|
||||
/// This option is a UInt.
|
||||
/// </summary>
|
||||
[GameConfigOption("LogChatBubbleShoutFontColor", ConfigType.UInt)]
|
||||
LogChatBubbleShoutFontColor,
|
||||
|
||||
/// <summary>
|
||||
/// UiConfig option with the internal name LogChatBubbleShoutWindowColor.
|
||||
/// This option is a UInt.
|
||||
/// </summary>
|
||||
[GameConfigOption("LogChatBubbleShoutWindowColor", ConfigType.UInt)]
|
||||
LogChatBubbleShoutWindowColor,
|
||||
|
||||
/// <summary>
|
||||
/// UiConfig option with the internal name LogChatBubbleTellShowType.
|
||||
/// This option is a UInt.
|
||||
/// </summary>
|
||||
[GameConfigOption("LogChatBubbleTellShowType", ConfigType.UInt)]
|
||||
LogChatBubbleTellShowType,
|
||||
|
||||
/// <summary>
|
||||
/// UiConfig option with the internal name LogChatBubbleTellFontColor.
|
||||
/// This option is a UInt.
|
||||
/// </summary>
|
||||
[GameConfigOption("LogChatBubbleTellFontColor", ConfigType.UInt)]
|
||||
LogChatBubbleTellFontColor,
|
||||
|
||||
/// <summary>
|
||||
/// UiConfig option with the internal name LogChatBubbleTellWindowColor.
|
||||
/// This option is a UInt.
|
||||
/// </summary>
|
||||
[GameConfigOption("LogChatBubbleTellWindowColor", ConfigType.UInt)]
|
||||
LogChatBubbleTellWindowColor,
|
||||
|
||||
/// <summary>
|
||||
/// UiConfig option with the internal name LogChatBubblePartyShowType.
|
||||
/// This option is a UInt.
|
||||
/// </summary>
|
||||
[GameConfigOption("LogChatBubblePartyShowType", ConfigType.UInt)]
|
||||
LogChatBubblePartyShowType,
|
||||
|
||||
/// <summary>
|
||||
/// UiConfig option with the internal name LogChatBubblePartyFontColor.
|
||||
/// This option is a UInt.
|
||||
/// </summary>
|
||||
[GameConfigOption("LogChatBubblePartyFontColor", ConfigType.UInt)]
|
||||
LogChatBubblePartyFontColor,
|
||||
|
||||
/// <summary>
|
||||
/// UiConfig option with the internal name LogChatBubblePartyWindowColor.
|
||||
/// This option is a UInt.
|
||||
/// </summary>
|
||||
[GameConfigOption("LogChatBubblePartyWindowColor", ConfigType.UInt)]
|
||||
LogChatBubblePartyWindowColor,
|
||||
|
||||
/// <summary>
|
||||
/// UiConfig option with the internal name LogChatBubbleAllianceShowType.
|
||||
/// This option is a UInt.
|
||||
/// </summary>
|
||||
[GameConfigOption("LogChatBubbleAllianceShowType", ConfigType.UInt)]
|
||||
LogChatBubbleAllianceShowType,
|
||||
|
||||
/// <summary>
|
||||
/// UiConfig option with the internal name LogChatBubbleAllianceFontColor.
|
||||
/// This option is a UInt.
|
||||
/// </summary>
|
||||
[GameConfigOption("LogChatBubbleAllianceFontColor", ConfigType.UInt)]
|
||||
LogChatBubbleAllianceFontColor,
|
||||
|
||||
/// <summary>
|
||||
/// UiConfig option with the internal name LogChatBubbleAllianceWindowColor.
|
||||
/// This option is a UInt.
|
||||
/// </summary>
|
||||
[GameConfigOption("LogChatBubbleAllianceWindowColor", ConfigType.UInt)]
|
||||
LogChatBubbleAllianceWindowColor,
|
||||
|
||||
/// <summary>
|
||||
/// UiConfig option with the internal name LogChatBubbleFcShowType.
|
||||
/// This option is a UInt.
|
||||
/// </summary>
|
||||
[GameConfigOption("LogChatBubbleFcShowType", ConfigType.UInt)]
|
||||
LogChatBubbleFcShowType,
|
||||
|
||||
/// <summary>
|
||||
/// UiConfig option with the internal name LogChatBubbleFcFontColor.
|
||||
/// This option is a UInt.
|
||||
/// </summary>
|
||||
[GameConfigOption("LogChatBubbleFcFontColor", ConfigType.UInt)]
|
||||
LogChatBubbleFcFontColor,
|
||||
|
||||
/// <summary>
|
||||
/// UiConfig option with the internal name LogChatBubbleFcWindowColor.
|
||||
/// This option is a UInt.
|
||||
/// </summary>
|
||||
[GameConfigOption("LogChatBubbleFcWindowColor", ConfigType.UInt)]
|
||||
LogChatBubbleFcWindowColor,
|
||||
|
||||
/// <summary>
|
||||
/// UiConfig option with the internal name LogChatBubbleBeginnerShowType.
|
||||
/// This option is a UInt.
|
||||
/// </summary>
|
||||
[GameConfigOption("LogChatBubbleBeginnerShowType", ConfigType.UInt)]
|
||||
LogChatBubbleBeginnerShowType,
|
||||
|
||||
/// <summary>
|
||||
/// UiConfig option with the internal name LogChatBubbleBeginnerFontColor.
|
||||
/// This option is a UInt.
|
||||
/// </summary>
|
||||
[GameConfigOption("LogChatBubbleBeginnerFontColor", ConfigType.UInt)]
|
||||
LogChatBubbleBeginnerFontColor,
|
||||
|
||||
/// <summary>
|
||||
/// UiConfig option with the internal name LogChatBubbleBeginnerWindowColor.
|
||||
/// This option is a UInt.
|
||||
/// </summary>
|
||||
[GameConfigOption("LogChatBubbleBeginnerWindowColor", ConfigType.UInt)]
|
||||
LogChatBubbleBeginnerWindowColor,
|
||||
|
||||
/// <summary>
|
||||
/// UiConfig option with the internal name LogChatBubblePvpteamShowType.
|
||||
/// This option is a UInt.
|
||||
/// </summary>
|
||||
[GameConfigOption("LogChatBubblePvpteamShowType", ConfigType.UInt)]
|
||||
LogChatBubblePvpteamShowType,
|
||||
|
||||
/// <summary>
|
||||
/// UiConfig option with the internal name LogChatBubblePvpteamFontColor.
|
||||
/// This option is a UInt.
|
||||
/// </summary>
|
||||
[GameConfigOption("LogChatBubblePvpteamFontColor", ConfigType.UInt)]
|
||||
LogChatBubblePvpteamFontColor,
|
||||
|
||||
/// <summary>
|
||||
/// UiConfig option with the internal name LogChatBubblePvpteamWindowColor.
|
||||
/// This option is a UInt.
|
||||
/// </summary>
|
||||
[GameConfigOption("LogChatBubblePvpteamWindowColor", ConfigType.UInt)]
|
||||
LogChatBubblePvpteamWindowColor,
|
||||
|
||||
/// <summary>
|
||||
/// UiConfig option with the internal name LogChatBubbleLs1ShowType.
|
||||
/// This option is a UInt.
|
||||
/// </summary>
|
||||
[GameConfigOption("LogChatBubbleLs1ShowType", ConfigType.UInt)]
|
||||
LogChatBubbleLs1ShowType,
|
||||
|
||||
/// <summary>
|
||||
/// UiConfig option with the internal name LogChatBubbleLs1FontColor.
|
||||
/// This option is a UInt.
|
||||
/// </summary>
|
||||
[GameConfigOption("LogChatBubbleLs1FontColor", ConfigType.UInt)]
|
||||
LogChatBubbleLs1FontColor,
|
||||
|
||||
/// <summary>
|
||||
/// UiConfig option with the internal name LogChatBubbleLs1WindowColor.
|
||||
/// This option is a UInt.
|
||||
/// </summary>
|
||||
[GameConfigOption("LogChatBubbleLs1WindowColor", ConfigType.UInt)]
|
||||
LogChatBubbleLs1WindowColor,
|
||||
|
||||
/// <summary>
|
||||
/// UiConfig option with the internal name LogChatBubbleLs2ShowType.
|
||||
/// This option is a UInt.
|
||||
/// </summary>
|
||||
[GameConfigOption("LogChatBubbleLs2ShowType", ConfigType.UInt)]
|
||||
LogChatBubbleLs2ShowType,
|
||||
|
||||
/// <summary>
|
||||
/// UiConfig option with the internal name LogChatBubbleLs2FontColor.
|
||||
/// This option is a UInt.
|
||||
/// </summary>
|
||||
[GameConfigOption("LogChatBubbleLs2FontColor", ConfigType.UInt)]
|
||||
LogChatBubbleLs2FontColor,
|
||||
|
||||
/// <summary>
|
||||
/// UiConfig option with the internal name LogChatBubbleLs2WindowColor.
|
||||
/// This option is a UInt.
|
||||
/// </summary>
|
||||
[GameConfigOption("LogChatBubbleLs2WindowColor", ConfigType.UInt)]
|
||||
LogChatBubbleLs2WindowColor,
|
||||
|
||||
/// <summary>
|
||||
/// UiConfig option with the internal name LogChatBubbleLs3ShowType.
|
||||
/// This option is a UInt.
|
||||
/// </summary>
|
||||
[GameConfigOption("LogChatBubbleLs3ShowType", ConfigType.UInt)]
|
||||
LogChatBubbleLs3ShowType,
|
||||
|
||||
/// <summary>
|
||||
/// UiConfig option with the internal name LogChatBubbleLs3FontColor.
|
||||
/// This option is a UInt.
|
||||
/// </summary>
|
||||
[GameConfigOption("LogChatBubbleLs3FontColor", ConfigType.UInt)]
|
||||
LogChatBubbleLs3FontColor,
|
||||
|
||||
/// <summary>
|
||||
/// UiConfig option with the internal name LogChatBubbleLs3WindowColor.
|
||||
/// This option is a UInt.
|
||||
/// </summary>
|
||||
[GameConfigOption("LogChatBubbleLs3WindowColor", ConfigType.UInt)]
|
||||
LogChatBubbleLs3WindowColor,
|
||||
|
||||
/// <summary>
|
||||
/// UiConfig option with the internal name LogChatBubbleLs4ShowType.
|
||||
/// This option is a UInt.
|
||||
/// </summary>
|
||||
[GameConfigOption("LogChatBubbleLs4ShowType", ConfigType.UInt)]
|
||||
LogChatBubbleLs4ShowType,
|
||||
|
||||
/// <summary>
|
||||
/// UiConfig option with the internal name LogChatBubbleLs4FontColor.
|
||||
/// This option is a UInt.
|
||||
/// </summary>
|
||||
[GameConfigOption("LogChatBubbleLs4FontColor", ConfigType.UInt)]
|
||||
LogChatBubbleLs4FontColor,
|
||||
|
||||
/// <summary>
|
||||
/// UiConfig option with the internal name LogChatBubbleLs4WindowColor.
|
||||
/// This option is a UInt.
|
||||
/// </summary>
|
||||
[GameConfigOption("LogChatBubbleLs4WindowColor", ConfigType.UInt)]
|
||||
LogChatBubbleLs4WindowColor,
|
||||
|
||||
/// <summary>
|
||||
/// UiConfig option with the internal name LogChatBubbleLs5ShowType.
|
||||
/// This option is a UInt.
|
||||
/// </summary>
|
||||
[GameConfigOption("LogChatBubbleLs5ShowType", ConfigType.UInt)]
|
||||
LogChatBubbleLs5ShowType,
|
||||
|
||||
/// <summary>
|
||||
/// UiConfig option with the internal name LogChatBubbleLs5FontColor.
|
||||
/// This option is a UInt.
|
||||
/// </summary>
|
||||
[GameConfigOption("LogChatBubbleLs5FontColor", ConfigType.UInt)]
|
||||
LogChatBubbleLs5FontColor,
|
||||
|
||||
/// <summary>
|
||||
/// UiConfig option with the internal name LogChatBubbleLs5WindowColor.
|
||||
/// This option is a UInt.
|
||||
/// </summary>
|
||||
[GameConfigOption("LogChatBubbleLs5WindowColor", ConfigType.UInt)]
|
||||
LogChatBubbleLs5WindowColor,
|
||||
|
||||
/// <summary>
|
||||
/// UiConfig option with the internal name LogChatBubbleLs6ShowType.
|
||||
/// This option is a UInt.
|
||||
/// </summary>
|
||||
[GameConfigOption("LogChatBubbleLs6ShowType", ConfigType.UInt)]
|
||||
LogChatBubbleLs6ShowType,
|
||||
|
||||
/// <summary>
|
||||
/// UiConfig option with the internal name LogChatBubbleLs6FontColor.
|
||||
/// This option is a UInt.
|
||||
/// </summary>
|
||||
[GameConfigOption("LogChatBubbleLs6FontColor", ConfigType.UInt)]
|
||||
LogChatBubbleLs6FontColor,
|
||||
|
||||
/// <summary>
|
||||
/// UiConfig option with the internal name LogChatBubbleLs6WindowColor.
|
||||
/// This option is a UInt.
|
||||
/// </summary>
|
||||
[GameConfigOption("LogChatBubbleLs6WindowColor", ConfigType.UInt)]
|
||||
LogChatBubbleLs6WindowColor,
|
||||
|
||||
/// <summary>
|
||||
/// UiConfig option with the internal name LogChatBubbleLs7ShowType.
|
||||
/// This option is a UInt.
|
||||
/// </summary>
|
||||
[GameConfigOption("LogChatBubbleLs7ShowType", ConfigType.UInt)]
|
||||
LogChatBubbleLs7ShowType,
|
||||
|
||||
/// <summary>
|
||||
/// UiConfig option with the internal name LogChatBubbleLs7FontColor.
|
||||
/// This option is a UInt.
|
||||
/// </summary>
|
||||
[GameConfigOption("LogChatBubbleLs7FontColor", ConfigType.UInt)]
|
||||
LogChatBubbleLs7FontColor,
|
||||
|
||||
/// <summary>
|
||||
/// UiConfig option with the internal name LogChatBubbleLs7WindowColor.
|
||||
/// This option is a UInt.
|
||||
/// </summary>
|
||||
[GameConfigOption("LogChatBubbleLs7WindowColor", ConfigType.UInt)]
|
||||
LogChatBubbleLs7WindowColor,
|
||||
|
||||
/// <summary>
|
||||
/// UiConfig option with the internal name LogChatBubbleLs8ShowType.
|
||||
/// This option is a UInt.
|
||||
/// </summary>
|
||||
[GameConfigOption("LogChatBubbleLs8ShowType", ConfigType.UInt)]
|
||||
LogChatBubbleLs8ShowType,
|
||||
|
||||
/// <summary>
|
||||
/// UiConfig option with the internal name LogChatBubbleLs8FontColor.
|
||||
/// This option is a UInt.
|
||||
/// </summary>
|
||||
[GameConfigOption("LogChatBubbleLs8FontColor", ConfigType.UInt)]
|
||||
LogChatBubbleLs8FontColor,
|
||||
|
||||
/// <summary>
|
||||
/// UiConfig option with the internal name LogChatBubbleLs8WindowColor.
|
||||
/// This option is a UInt.
|
||||
/// </summary>
|
||||
[GameConfigOption("LogChatBubbleLs8WindowColor", ConfigType.UInt)]
|
||||
LogChatBubbleLs8WindowColor,
|
||||
|
||||
/// <summary>
|
||||
/// UiConfig option with the internal name LogChatBubbleCwls1ShowType.
|
||||
/// This option is a UInt.
|
||||
/// </summary>
|
||||
[GameConfigOption("LogChatBubbleCwls1ShowType", ConfigType.UInt)]
|
||||
LogChatBubbleCwls1ShowType,
|
||||
|
||||
/// <summary>
|
||||
/// UiConfig option with the internal name LogChatBubbleCwls1FontColor.
|
||||
/// This option is a UInt.
|
||||
/// </summary>
|
||||
[GameConfigOption("LogChatBubbleCwls1FontColor", ConfigType.UInt)]
|
||||
LogChatBubbleCwls1FontColor,
|
||||
|
||||
/// <summary>
|
||||
/// UiConfig option with the internal name LogChatBubbleCwls1WindowColor.
|
||||
/// This option is a UInt.
|
||||
/// </summary>
|
||||
[GameConfigOption("LogChatBubbleCwls1WindowColor", ConfigType.UInt)]
|
||||
LogChatBubbleCwls1WindowColor,
|
||||
|
||||
/// <summary>
|
||||
/// UiConfig option with the internal name LogChatBubbleCwls2ShowType.
|
||||
/// This option is a UInt.
|
||||
/// </summary>
|
||||
[GameConfigOption("LogChatBubbleCwls2ShowType", ConfigType.UInt)]
|
||||
LogChatBubbleCwls2ShowType,
|
||||
|
||||
/// <summary>
|
||||
/// UiConfig option with the internal name LogChatBubbleCwls2FontColor.
|
||||
/// This option is a UInt.
|
||||
/// </summary>
|
||||
[GameConfigOption("LogChatBubbleCwls2FontColor", ConfigType.UInt)]
|
||||
LogChatBubbleCwls2FontColor,
|
||||
|
||||
/// <summary>
|
||||
/// UiConfig option with the internal name LogChatBubbleCwls2WindowColor.
|
||||
/// This option is a UInt.
|
||||
/// </summary>
|
||||
[GameConfigOption("LogChatBubbleCwls2WindowColor", ConfigType.UInt)]
|
||||
LogChatBubbleCwls2WindowColor,
|
||||
|
||||
/// <summary>
|
||||
/// UiConfig option with the internal name LogChatBubbleCwls3ShowType.
|
||||
/// This option is a UInt.
|
||||
/// </summary>
|
||||
[GameConfigOption("LogChatBubbleCwls3ShowType", ConfigType.UInt)]
|
||||
LogChatBubbleCwls3ShowType,
|
||||
|
||||
/// <summary>
|
||||
/// UiConfig option with the internal name LogChatBubbleCwls3FontColor.
|
||||
/// This option is a UInt.
|
||||
/// </summary>
|
||||
[GameConfigOption("LogChatBubbleCwls3FontColor", ConfigType.UInt)]
|
||||
LogChatBubbleCwls3FontColor,
|
||||
|
||||
/// <summary>
|
||||
/// UiConfig option with the internal name LogChatBubbleCwls3WindowColor.
|
||||
/// This option is a UInt.
|
||||
/// </summary>
|
||||
[GameConfigOption("LogChatBubbleCwls3WindowColor", ConfigType.UInt)]
|
||||
LogChatBubbleCwls3WindowColor,
|
||||
|
||||
/// <summary>
|
||||
/// UiConfig option with the internal name LogChatBubbleCwls4ShowType.
|
||||
/// This option is a UInt.
|
||||
/// </summary>
|
||||
[GameConfigOption("LogChatBubbleCwls4ShowType", ConfigType.UInt)]
|
||||
LogChatBubbleCwls4ShowType,
|
||||
|
||||
/// <summary>
|
||||
/// UiConfig option with the internal name LogChatBubbleCwls4FontColor.
|
||||
/// This option is a UInt.
|
||||
/// </summary>
|
||||
[GameConfigOption("LogChatBubbleCwls4FontColor", ConfigType.UInt)]
|
||||
LogChatBubbleCwls4FontColor,
|
||||
|
||||
/// <summary>
|
||||
/// UiConfig option with the internal name LogChatBubbleCwls4WindowColor.
|
||||
/// This option is a UInt.
|
||||
/// </summary>
|
||||
[GameConfigOption("LogChatBubbleCwls4WindowColor", ConfigType.UInt)]
|
||||
LogChatBubbleCwls4WindowColor,
|
||||
|
||||
/// <summary>
|
||||
/// UiConfig option with the internal name LogChatBubbleCwls5ShowType.
|
||||
/// This option is a UInt.
|
||||
/// </summary>
|
||||
[GameConfigOption("LogChatBubbleCwls5ShowType", ConfigType.UInt)]
|
||||
LogChatBubbleCwls5ShowType,
|
||||
|
||||
/// <summary>
|
||||
/// UiConfig option with the internal name LogChatBubbleCwls5FontColor.
|
||||
/// This option is a UInt.
|
||||
/// </summary>
|
||||
[GameConfigOption("LogChatBubbleCwls5FontColor", ConfigType.UInt)]
|
||||
LogChatBubbleCwls5FontColor,
|
||||
|
||||
/// <summary>
|
||||
/// UiConfig option with the internal name LogChatBubbleCwls5WindowColor.
|
||||
/// This option is a UInt.
|
||||
/// </summary>
|
||||
[GameConfigOption("LogChatBubbleCwls5WindowColor", ConfigType.UInt)]
|
||||
LogChatBubbleCwls5WindowColor,
|
||||
|
||||
/// <summary>
|
||||
/// UiConfig option with the internal name LogChatBubbleCwls6ShowType.
|
||||
/// This option is a UInt.
|
||||
/// </summary>
|
||||
[GameConfigOption("LogChatBubbleCwls6ShowType", ConfigType.UInt)]
|
||||
LogChatBubbleCwls6ShowType,
|
||||
|
||||
/// <summary>
|
||||
/// UiConfig option with the internal name LogChatBubbleCwls6FontColor.
|
||||
/// This option is a UInt.
|
||||
/// </summary>
|
||||
[GameConfigOption("LogChatBubbleCwls6FontColor", ConfigType.UInt)]
|
||||
LogChatBubbleCwls6FontColor,
|
||||
|
||||
/// <summary>
|
||||
/// UiConfig option with the internal name LogChatBubbleCwls6WindowColor.
|
||||
/// This option is a UInt.
|
||||
/// </summary>
|
||||
[GameConfigOption("LogChatBubbleCwls6WindowColor", ConfigType.UInt)]
|
||||
LogChatBubbleCwls6WindowColor,
|
||||
|
||||
/// <summary>
|
||||
/// UiConfig option with the internal name LogChatBubbleCwls7ShowType.
|
||||
/// This option is a UInt.
|
||||
/// </summary>
|
||||
[GameConfigOption("LogChatBubbleCwls7ShowType", ConfigType.UInt)]
|
||||
LogChatBubbleCwls7ShowType,
|
||||
|
||||
/// <summary>
|
||||
/// UiConfig option with the internal name LogChatBubbleCwls7FontColor.
|
||||
/// This option is a UInt.
|
||||
/// </summary>
|
||||
[GameConfigOption("LogChatBubbleCwls7FontColor", ConfigType.UInt)]
|
||||
LogChatBubbleCwls7FontColor,
|
||||
|
||||
/// <summary>
|
||||
/// UiConfig option with the internal name LogChatBubbleCwls7WindowColor.
|
||||
/// This option is a UInt.
|
||||
/// </summary>
|
||||
[GameConfigOption("LogChatBubbleCwls7WindowColor", ConfigType.UInt)]
|
||||
LogChatBubbleCwls7WindowColor,
|
||||
|
||||
/// <summary>
|
||||
/// UiConfig option with the internal name LogChatBubbleCwls8ShowType.
|
||||
/// This option is a UInt.
|
||||
/// </summary>
|
||||
[GameConfigOption("LogChatBubbleCwls8ShowType", ConfigType.UInt)]
|
||||
LogChatBubbleCwls8ShowType,
|
||||
|
||||
/// <summary>
|
||||
/// UiConfig option with the internal name LogChatBubbleCwls8FontColor.
|
||||
/// This option is a UInt.
|
||||
/// </summary>
|
||||
[GameConfigOption("LogChatBubbleCwls8FontColor", ConfigType.UInt)]
|
||||
LogChatBubbleCwls8FontColor,
|
||||
|
||||
/// <summary>
|
||||
/// UiConfig option with the internal name LogChatBubbleCwls8WindowColor.
|
||||
/// This option is a UInt.
|
||||
/// </summary>
|
||||
[GameConfigOption("LogChatBubbleCwls8WindowColor", ConfigType.UInt)]
|
||||
LogChatBubbleCwls8WindowColor,
|
||||
|
||||
/// <summary>
|
||||
/// UiConfig option with the internal name LogPermeationRateInput.
|
||||
/// This option is a UInt.
|
||||
/// </summary>
|
||||
[GameConfigOption("LogPermeationRateInput", ConfigType.UInt)]
|
||||
LogPermeationRateInput,
|
||||
|
||||
/// <summary>
|
||||
/// UiConfig option with the internal name ChatType.
|
||||
/// This option is a UInt.
|
||||
|
|
@ -3453,6 +4048,27 @@ public enum UiConfigOption
|
|||
[GameConfigOption("GPoseMotionFilterAction", ConfigType.UInt)]
|
||||
GPoseMotionFilterAction,
|
||||
|
||||
/// <summary>
|
||||
/// UiConfig option with the internal name GPoseRollRotationCameraCorrection.
|
||||
/// This option is a UInt.
|
||||
/// </summary>
|
||||
[GameConfigOption("GPoseRollRotationCameraCorrection", ConfigType.UInt)]
|
||||
GPoseRollRotationCameraCorrection,
|
||||
|
||||
/// <summary>
|
||||
/// UiConfig option with the internal name GPoseInitCameraFocus.
|
||||
/// This option is a UInt.
|
||||
/// </summary>
|
||||
[GameConfigOption("GPoseInitCameraFocus", ConfigType.UInt)]
|
||||
GPoseInitCameraFocus,
|
||||
|
||||
/// <summary>
|
||||
/// UiConfig option with the internal name GposePortraitRotateType.
|
||||
/// This option is a UInt.
|
||||
/// </summary>
|
||||
[GameConfigOption("GposePortraitRotateType", ConfigType.UInt)]
|
||||
GposePortraitRotateType,
|
||||
|
||||
/// <summary>
|
||||
/// UiConfig option with the internal name LsListSortPriority.
|
||||
/// This option is a UInt.
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ internal sealed unsafe class ChatGui : IInternalDisposableService, IChatGui
|
|||
private static readonly ModuleLog Log = new("ChatGui");
|
||||
|
||||
private readonly Queue<XivChatEntry> chatQueue = new();
|
||||
private readonly Dictionary<(string PluginName, Guid CommandId), Action<Guid, SeString>> dalamudLinkHandlers = new();
|
||||
private readonly Dictionary<(string PluginName, uint CommandId), Action<uint, SeString>> dalamudLinkHandlers = new();
|
||||
|
||||
private readonly Hook<PrintMessageDelegate> printMessageHook;
|
||||
private readonly Hook<InventoryItem.Delegates.Copy> inventoryItemCopyHook;
|
||||
|
|
@ -50,7 +50,8 @@ internal sealed unsafe class ChatGui : IInternalDisposableService, IChatGui
|
|||
[ServiceManager.ServiceDependency]
|
||||
private readonly DalamudConfiguration configuration = Service<DalamudConfiguration>.Get();
|
||||
|
||||
private ImmutableDictionary<(string PluginName, Guid CommandId), Action<Guid, SeString>>? dalamudLinkHandlersCopy;
|
||||
private ImmutableDictionary<(string PluginName, uint CommandId), Action<uint, SeString>>? dalamudLinkHandlersCopy;
|
||||
private uint dalamudChatHandlerId = 1000;
|
||||
|
||||
[ServiceManager.ServiceConstructor]
|
||||
private ChatGui()
|
||||
|
|
@ -86,7 +87,7 @@ internal sealed unsafe class ChatGui : IInternalDisposableService, IChatGui
|
|||
public byte LastLinkedItemFlags { get; private set; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IReadOnlyDictionary<(string PluginName, Guid CommandId), Action<Guid, SeString>> RegisteredLinkHandlers
|
||||
public IReadOnlyDictionary<(string PluginName, uint CommandId), Action<uint, SeString>> RegisteredLinkHandlers
|
||||
{
|
||||
get
|
||||
{
|
||||
|
|
@ -164,19 +165,33 @@ internal sealed unsafe class ChatGui : IInternalDisposableService, IChatGui
|
|||
|
||||
#region Chat Links
|
||||
|
||||
/// <inheritdoc/>
|
||||
public DalamudLinkPayload AddChatLinkHandler(Action<Guid, SeString> commandAction)
|
||||
/// <summary>
|
||||
/// Register a chat link handler.
|
||||
/// </summary>
|
||||
/// <remarks>Internal use only.</remarks>
|
||||
/// <param name="commandAction">The action to be executed.</param>
|
||||
/// <returns>Returns an SeString payload for the link.</returns>
|
||||
public DalamudLinkPayload AddChatLinkHandler(Action<uint, SeString> commandAction)
|
||||
{
|
||||
return this.AddChatLinkHandler("Dalamud", commandAction);
|
||||
return this.AddChatLinkHandler("Dalamud", this.dalamudChatHandlerId++, commandAction);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void RemoveChatLinkHandler(Guid commandId)
|
||||
/// <remarks>Internal use only.</remarks>
|
||||
public DalamudLinkPayload AddChatLinkHandler(uint commandId, Action<uint, SeString> commandAction)
|
||||
{
|
||||
return this.AddChatLinkHandler("Dalamud", commandId, commandAction);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
/// <remarks>Internal use only.</remarks>
|
||||
public void RemoveChatLinkHandler(uint commandId)
|
||||
{
|
||||
this.RemoveChatLinkHandler("Dalamud", commandId);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
/// <remarks>Internal use only.</remarks>
|
||||
public void RemoveChatLinkHandler()
|
||||
{
|
||||
this.RemoveChatLinkHandler("Dalamud");
|
||||
|
|
@ -240,11 +255,11 @@ internal sealed unsafe class ChatGui : IInternalDisposableService, IChatGui
|
|||
/// Create a link handler.
|
||||
/// </summary>
|
||||
/// <param name="pluginName">The name of the plugin handling the link.</param>
|
||||
/// <param name="commandId">The ID of the command to run.</param>
|
||||
/// <param name="commandAction">The command action itself.</param>
|
||||
/// <returns>A payload for handling.</returns>
|
||||
internal DalamudLinkPayload AddChatLinkHandler(string pluginName, Action<Guid, SeString> commandAction)
|
||||
internal DalamudLinkPayload AddChatLinkHandler(string pluginName, uint commandId, Action<uint, SeString> commandAction)
|
||||
{
|
||||
var commandId = Guid.CreateVersion7();
|
||||
var payload = new DalamudLinkPayload { Plugin = pluginName, CommandId = commandId };
|
||||
lock (this.dalamudLinkHandlers)
|
||||
{
|
||||
|
|
@ -277,7 +292,7 @@ internal sealed unsafe class ChatGui : IInternalDisposableService, IChatGui
|
|||
/// </summary>
|
||||
/// <param name="pluginName">The name of the plugin handling the link.</param>
|
||||
/// <param name="commandId">The ID of the command to be removed.</param>
|
||||
internal void RemoveChatLinkHandler(string pluginName, Guid commandId)
|
||||
internal void RemoveChatLinkHandler(string pluginName, uint commandId)
|
||||
{
|
||||
lock (this.dalamudLinkHandlers)
|
||||
{
|
||||
|
|
@ -400,13 +415,13 @@ internal sealed unsafe class ChatGui : IInternalDisposableService, IChatGui
|
|||
|
||||
if (!terminatedSender.SequenceEqual(possiblyModifiedSenderData))
|
||||
{
|
||||
Log.Verbose($"HandlePrintMessageDetour Sender modified: {SeString.Parse(terminatedSender)} -> {parsedSender}");
|
||||
Log.Verbose($"HandlePrintMessageDetour Sender modified: {new ReadOnlySeStringSpan(terminatedSender).ToMacroString()} -> {new ReadOnlySeStringSpan(possiblyModifiedSenderData).ToMacroString()}");
|
||||
sender->SetString(possiblyModifiedSenderData);
|
||||
}
|
||||
|
||||
if (!terminatedMessage.SequenceEqual(possiblyModifiedMessageData))
|
||||
{
|
||||
Log.Verbose($"HandlePrintMessageDetour Message modified: {SeString.Parse(terminatedMessage)} -> {parsedMessage}");
|
||||
Log.Verbose($"HandlePrintMessageDetour Message modified: {new ReadOnlySeStringSpan(terminatedMessage).ToMacroString()} -> {new ReadOnlySeStringSpan(possiblyModifiedMessageData).ToMacroString()}");
|
||||
message->SetString(possiblyModifiedMessageData);
|
||||
}
|
||||
|
||||
|
|
@ -534,7 +549,7 @@ internal class ChatGuiPluginScoped : IInternalDisposableService, IChatGui
|
|||
public byte LastLinkedItemFlags => this.chatGuiService.LastLinkedItemFlags;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IReadOnlyDictionary<(string PluginName, Guid CommandId), Action<Guid, SeString>> RegisteredLinkHandlers => this.chatGuiService.RegisteredLinkHandlers;
|
||||
public IReadOnlyDictionary<(string PluginName, uint CommandId), Action<uint, SeString>> RegisteredLinkHandlers => this.chatGuiService.RegisteredLinkHandlers;
|
||||
|
||||
/// <inheritdoc/>
|
||||
void IInternalDisposableService.DisposeService()
|
||||
|
|
@ -551,11 +566,11 @@ internal class ChatGuiPluginScoped : IInternalDisposableService, IChatGui
|
|||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public DalamudLinkPayload AddChatLinkHandler(Action<Guid, SeString> commandAction)
|
||||
=> this.chatGuiService.AddChatLinkHandler(this.plugin.InternalName, commandAction);
|
||||
public DalamudLinkPayload AddChatLinkHandler(uint commandId, Action<uint, SeString> commandAction)
|
||||
=> this.chatGuiService.AddChatLinkHandler(this.plugin.InternalName, commandId, commandAction);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void RemoveChatLinkHandler(Guid commandId)
|
||||
public void RemoveChatLinkHandler(uint commandId)
|
||||
=> this.chatGuiService.RemoveChatLinkHandler(this.plugin.InternalName, commandId);
|
||||
|
||||
/// <inheritdoc/>
|
||||
|
|
|
|||
|
|
@ -586,8 +586,7 @@ internal sealed unsafe class DtrBar : IInternalDisposableService, IDtrBar
|
|||
newTextNode->LineSpacing = 12;
|
||||
newTextNode->AlignmentFontType = 5;
|
||||
newTextNode->FontSize = 14;
|
||||
newTextNode->TextFlags = (byte)TextFlags.Edge;
|
||||
newTextNode->TextFlags2 = 0;
|
||||
newTextNode->TextFlags = TextFlags.Edge;
|
||||
|
||||
if (this.emptyString == null)
|
||||
this.emptyString = Utf8String.FromString(" ");
|
||||
|
|
@ -642,7 +641,7 @@ internal sealed unsafe class DtrBar : IInternalDisposableService, IDtrBar
|
|||
break;
|
||||
|
||||
case AddonEventType.MouseClick:
|
||||
dtrBarEntry.OnClick?.Invoke(new AddonMouseEventData(eventData));
|
||||
dtrBarEntry.OnClick?.Invoke(DtrInteractionEvent.FromMouseEvent(new AddonMouseEventData(eventData)));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,6 +43,11 @@ public interface IReadOnlyDtrBarEntry
|
|||
/// Gets a value indicating whether the user has hidden this entry from view through the Dalamud settings.
|
||||
/// </summary>
|
||||
public bool UserHidden { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets an action to be invoked when the user clicks on the dtr entry.
|
||||
/// </summary>
|
||||
public Action<DtrInteractionEvent>? OnClick { get; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -68,7 +73,7 @@ public interface IDtrBarEntry : IReadOnlyDtrBarEntry
|
|||
/// <summary>
|
||||
/// Gets or sets an action to be invoked when the user clicks on the dtr entry.
|
||||
/// </summary>
|
||||
public Action<AddonMouseEventData>? OnClick { get; set; }
|
||||
public new Action<DtrInteractionEvent>? OnClick { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Remove this entry from the bar.
|
||||
|
|
@ -118,7 +123,7 @@ internal sealed unsafe class DtrBarEntry : IDisposable, IDtrBarEntry
|
|||
public SeString? Tooltip { get; set; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Action<AddonMouseEventData>? OnClick { get; set; }
|
||||
public Action<DtrInteractionEvent>? OnClick { get; set; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool HasClickAction => this.OnClick != null;
|
||||
|
|
|
|||
59
Dalamud/Game/Gui/Dtr/DtrInteractionEvent.cs
Normal file
59
Dalamud/Game/Gui/Dtr/DtrInteractionEvent.cs
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
using System.Numerics;
|
||||
|
||||
using Dalamud.Game.Addon.Events.EventDataTypes;
|
||||
|
||||
namespace Dalamud.Game.Gui.Dtr;
|
||||
|
||||
/// <summary>
|
||||
/// Represents an interaction event from the DTR system.
|
||||
/// </summary>
|
||||
public class DtrInteractionEvent
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the type of mouse click (left or right).
|
||||
/// </summary>
|
||||
public MouseClickType ClickType { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the modifier keys that were held during the click.
|
||||
/// </summary>
|
||||
public ClickModifierKeys ModifierKeys { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the scroll direction of the mouse wheel, if applicable.
|
||||
/// </summary>
|
||||
public MouseScrollDirection ScrollDirection { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets lower-level mouse data, if this event came from native UI.
|
||||
///
|
||||
/// Can only be set by Dalamud. If null, this event was manually created.
|
||||
/// </summary>
|
||||
public AddonMouseEventData? AtkEventSource { get; private init; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the position of the mouse cursor when the event occurred.
|
||||
/// </summary>
|
||||
public Vector2 Position { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Helper to create a <see cref="DtrInteractionEvent"/> from an <see cref="AddonMouseEventData"/>.
|
||||
/// </summary>
|
||||
/// <param name="ev">The event.</param>
|
||||
/// <returns>A better event.</returns>
|
||||
public static DtrInteractionEvent FromMouseEvent(AddonMouseEventData ev)
|
||||
{
|
||||
return new DtrInteractionEvent
|
||||
{
|
||||
AtkEventSource = ev,
|
||||
ClickType = ev.IsLeftClick ? MouseClickType.Left : MouseClickType.Right,
|
||||
ModifierKeys = (ev.IsAltHeld ? ClickModifierKeys.Alt : 0) |
|
||||
(ev.IsControlHeld ? ClickModifierKeys.Ctrl : 0) |
|
||||
(ev.IsShiftHeld ? ClickModifierKeys.Shift : 0),
|
||||
ScrollDirection = ev.IsScrollUp ? MouseScrollDirection.Up :
|
||||
ev.IsScrollDown ? MouseScrollDirection.Down :
|
||||
MouseScrollDirection.None,
|
||||
Position = ev.Position,
|
||||
};
|
||||
}
|
||||
}
|
||||
65
Dalamud/Game/Gui/Dtr/DtrInteractionTypes.cs
Normal file
65
Dalamud/Game/Gui/Dtr/DtrInteractionTypes.cs
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
namespace Dalamud.Game.Gui.Dtr;
|
||||
|
||||
/// <summary>
|
||||
/// An enum representing the mouse click types.
|
||||
/// </summary>
|
||||
public enum MouseClickType
|
||||
{
|
||||
/// <summary>
|
||||
/// A left click.
|
||||
/// </summary>
|
||||
Left,
|
||||
|
||||
/// <summary>
|
||||
/// A right click.
|
||||
/// </summary>
|
||||
Right,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Modifier keys that can be held during a mouse click event.
|
||||
/// </summary>
|
||||
[Flags]
|
||||
public enum ClickModifierKeys
|
||||
{
|
||||
/// <summary>
|
||||
/// No modifiers were present.
|
||||
/// </summary>
|
||||
None = 0,
|
||||
|
||||
/// <summary>
|
||||
/// The CTRL key was held.
|
||||
/// </summary>
|
||||
Ctrl = 1 << 0,
|
||||
|
||||
/// <summary>
|
||||
/// The ALT key was held.
|
||||
/// </summary>
|
||||
Alt = 1 << 1,
|
||||
|
||||
/// <summary>
|
||||
/// The SHIFT key was held.
|
||||
/// </summary>
|
||||
Shift = 1 << 2,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Possible directions for scroll wheel events.
|
||||
/// </summary>
|
||||
public enum MouseScrollDirection
|
||||
{
|
||||
/// <summary>
|
||||
/// No scrolling.
|
||||
/// </summary>
|
||||
None = 0,
|
||||
|
||||
/// <summary>
|
||||
/// A scroll up event.
|
||||
/// </summary>
|
||||
Up = 1,
|
||||
|
||||
/// <summary>
|
||||
/// A scroll down event.
|
||||
/// </summary>
|
||||
Down = -1,
|
||||
}
|
||||
|
|
@ -343,11 +343,11 @@ public class SigScanner : IDisposable, ISigScanner
|
|||
break;
|
||||
|
||||
var scanRet = mBase + index;
|
||||
mBase = scanRet + 1;
|
||||
if (this.IsCopy)
|
||||
scanRet -= this.moduleCopyOffset;
|
||||
|
||||
yield return scanRet;
|
||||
mBase = scanRet + 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -121,6 +121,15 @@ internal class SeStringEvaluator : IServiceType, ISeStringEvaluator
|
|||
return this.Evaluate(ReadOnlySeString.FromMacroString(macroString).AsSpan(), localParameters, language);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ReadOnlySeString EvaluateMacroString(
|
||||
ReadOnlySpan<byte> macroString,
|
||||
Span<SeStringParameter> localParameters = default,
|
||||
ClientLanguage? language = null)
|
||||
{
|
||||
return this.Evaluate(ReadOnlySeString.FromMacroString(macroString).AsSpan(), localParameters, language);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ReadOnlySeString EvaluateFromAddon(
|
||||
uint addonId,
|
||||
|
|
@ -247,6 +256,9 @@ internal class SeStringEvaluator : IServiceType, ISeStringEvaluator
|
|||
case MacroCode.Switch:
|
||||
return this.TryResolveSwitch(in context, payload);
|
||||
|
||||
case MacroCode.SwitchPlatform:
|
||||
return this.TryResolveSwitchPlatform(in context, payload);
|
||||
|
||||
case MacroCode.PcName:
|
||||
return this.TryResolvePcName(in context, payload);
|
||||
|
||||
|
|
@ -450,6 +462,29 @@ internal class SeStringEvaluator : IServiceType, ISeStringEvaluator
|
|||
return false;
|
||||
}
|
||||
|
||||
private bool TryResolveSwitchPlatform(in SeStringContext context, in ReadOnlySePayloadSpan payload)
|
||||
{
|
||||
if (!payload.TryGetExpression(out var expr1))
|
||||
return false;
|
||||
|
||||
if (!expr1.TryGetInt(out var intVal))
|
||||
return false;
|
||||
|
||||
// Our version of the game uses IsMacClient() here and the
|
||||
// Xbox version seems to always return 7 for the platform.
|
||||
var platform = Util.IsWine() ? 5 : 3;
|
||||
|
||||
// The sheet is seeminly split into first 20 rows for wired controllers
|
||||
// and the last 20 rows for wireless controllers.
|
||||
var rowId = (uint)((20 * ((intVal - 1) / 20)) + (platform - 4 < 2 ? 2 : 1));
|
||||
|
||||
if (!this.dataManager.GetExcelSheet<Platform>().TryGetRow(rowId, out var platformRow))
|
||||
return false;
|
||||
|
||||
context.Builder.Append(platformRow.Name);
|
||||
return true;
|
||||
}
|
||||
|
||||
private unsafe bool TryResolvePcName(in SeStringContext context, in ReadOnlySePayloadSpan payload)
|
||||
{
|
||||
if (!payload.TryGetExpression(out var eEntityId))
|
||||
|
|
|
|||
|
|
@ -77,4 +77,6 @@ public readonly struct SeStringParameter
|
|||
public static implicit operator SeStringParameter(DSeString value) => new(new ReadOnlySeString(value.Encode()));
|
||||
|
||||
public static implicit operator SeStringParameter(string value) => new(value);
|
||||
|
||||
public static implicit operator SeStringParameter(ReadOnlySpan<byte> value) => new(value);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ public class DalamudLinkPayload : Payload
|
|||
public override PayloadType Type => PayloadType.DalamudLink;
|
||||
|
||||
/// <summary>Gets the plugin command ID to be linked.</summary>
|
||||
public Guid CommandId { get; internal set; }
|
||||
public uint CommandId { get; internal set; }
|
||||
|
||||
/// <summary>Gets an optional extra integer value 1.</summary>
|
||||
public int Extra1 { get; internal set; }
|
||||
|
|
@ -40,7 +40,7 @@ public class DalamudLinkPayload : Payload
|
|||
var ssb = Lumina.Text.SeStringBuilder.SharedPool.Get();
|
||||
var res = ssb.BeginMacro(MacroCode.Link)
|
||||
.AppendIntExpression((int)EmbeddedInfoType.DalamudLink - 1)
|
||||
.AppendStringExpression(this.CommandId.ToString())
|
||||
.AppendUIntExpression(this.CommandId)
|
||||
.AppendIntExpression(this.Extra1)
|
||||
.AppendIntExpression(this.Extra2)
|
||||
.BeginStringExpression()
|
||||
|
|
@ -72,15 +72,15 @@ public class DalamudLinkPayload : Payload
|
|||
if (!pluginExpression.TryGetString(out var pluginString))
|
||||
return;
|
||||
|
||||
if (!commandIdExpression.TryGetString(out var commandId))
|
||||
if (!commandIdExpression.TryGetUInt(out var commandId))
|
||||
return;
|
||||
|
||||
this.Plugin = pluginString.ExtractText();
|
||||
this.CommandId = Guid.Parse(commandId.ExtractText());
|
||||
this.CommandId = commandId;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!commandIdExpression.TryGetString(out var commandId))
|
||||
if (!commandIdExpression.TryGetUInt(out var commandId))
|
||||
return;
|
||||
|
||||
if (!extra1Expression.TryGetInt(out var extra1))
|
||||
|
|
@ -102,7 +102,7 @@ public class DalamudLinkPayload : Payload
|
|||
return;
|
||||
}
|
||||
|
||||
this.CommandId = Guid.Parse(commandId.ExtractText());
|
||||
this.CommandId = commandId;
|
||||
this.Extra1 = extra1;
|
||||
this.Extra2 = extra2;
|
||||
this.Plugin = extraData[0];
|
||||
|
|
|
|||
|
|
@ -0,0 +1,4 @@
|
|||
namespace Dalamud.Interface.ImGuiBackend.Delegates;
|
||||
|
||||
/// <summary>Delegate to be called when ImGui should be used to layout now.</summary>
|
||||
public delegate void ImGuiBuildUiDelegate();
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
namespace Dalamud.Interface.ImGuiBackend.Delegates;
|
||||
|
||||
/// <summary>Delegate to be called on new input frame.</summary>
|
||||
public delegate void ImGuiNewInputFrameDelegate();
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
namespace Dalamud.Interface.ImGuiBackend.Delegates;
|
||||
|
||||
/// <summary>Delegate to be called on new render frame.</summary>
|
||||
public delegate void ImGuiNewRenderFrameDelegate();
|
||||
|
|
@ -8,6 +8,7 @@ using System.Runtime.InteropServices;
|
|||
using Dalamud.Bindings.ImGui;
|
||||
using Dalamud.Bindings.ImGuizmo;
|
||||
using Dalamud.Bindings.ImPlot;
|
||||
using Dalamud.Interface.ImGuiBackend.Delegates;
|
||||
using Dalamud.Interface.ImGuiBackend.Helpers;
|
||||
using Dalamud.Interface.ImGuiBackend.InputHandler;
|
||||
using Dalamud.Interface.ImGuiBackend.Renderers;
|
||||
|
|
@ -93,13 +94,13 @@ internal sealed unsafe class Dx11Win32Backend : IWin32Backend
|
|||
~Dx11Win32Backend() => this.ReleaseUnmanagedResources();
|
||||
|
||||
/// <inheritdoc/>
|
||||
public event IImGuiBackend.BuildUiDelegate? BuildUi;
|
||||
public event ImGuiBuildUiDelegate? BuildUi;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public event IImGuiBackend.NewInputFrameDelegate? NewInputFrame;
|
||||
public event ImGuiNewInputFrameDelegate? NewInputFrame;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public event IImGuiBackend.NewRenderFrameDelegate? NewRenderFrame;
|
||||
public event ImGuiNewRenderFrameDelegate? NewRenderFrame;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool UpdateCursor
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
using Dalamud.Interface.ImGuiBackend.InputHandler;
|
||||
using Dalamud.Interface.ImGuiBackend.Delegates;
|
||||
using Dalamud.Interface.ImGuiBackend.InputHandler;
|
||||
using Dalamud.Interface.ImGuiBackend.Renderers;
|
||||
|
||||
namespace Dalamud.Interface.ImGuiBackend;
|
||||
|
|
@ -6,23 +7,14 @@ namespace Dalamud.Interface.ImGuiBackend;
|
|||
/// <summary>Backend for ImGui.</summary>
|
||||
internal interface IImGuiBackend : IDisposable
|
||||
{
|
||||
/// <summary>Delegate to be called when ImGui should be used to layout now.</summary>
|
||||
public delegate void BuildUiDelegate();
|
||||
|
||||
/// <summary>Delegate to be called on new input frame.</summary>
|
||||
public delegate void NewInputFrameDelegate();
|
||||
|
||||
/// <summary>Delegaet to be called on new render frame.</summary>
|
||||
public delegate void NewRenderFrameDelegate();
|
||||
|
||||
/// <summary>User methods invoked every ImGui frame to construct custom UIs.</summary>
|
||||
event BuildUiDelegate? BuildUi;
|
||||
event ImGuiBuildUiDelegate? BuildUi;
|
||||
|
||||
/// <summary>User methods invoked every ImGui frame on handling inputs.</summary>
|
||||
event NewInputFrameDelegate? NewInputFrame;
|
||||
event ImGuiNewInputFrameDelegate? NewInputFrame;
|
||||
|
||||
/// <summary>User methods invoked every ImGui frame on handling renders.</summary>
|
||||
event NewRenderFrameDelegate? NewRenderFrame;
|
||||
event ImGuiNewRenderFrameDelegate? NewRenderFrame;
|
||||
|
||||
/// <summary>Gets or sets a value indicating whether the cursor should be overridden with the ImGui cursor.
|
||||
/// </summary>
|
||||
|
|
@ -36,7 +28,7 @@ internal interface IImGuiBackend : IDisposable
|
|||
|
||||
/// <summary>Gets the input handler.</summary>
|
||||
IImGuiInputHandler InputHandler { get; }
|
||||
|
||||
|
||||
/// <summary>Gets the renderer.</summary>
|
||||
IImGuiRenderer Renderer { get; }
|
||||
|
||||
|
|
@ -45,7 +37,7 @@ internal interface IImGuiBackend : IDisposable
|
|||
|
||||
/// <summary>Handles stuff before resizing happens.</summary>
|
||||
void OnPreResize();
|
||||
|
||||
|
||||
/// <summary>Handles stuff after resizing happens.</summary>
|
||||
/// <param name="newWidth">The new width.</param>
|
||||
/// <param name="newHeight">The new height.</param>
|
||||
|
|
|
|||
|
|
@ -1,19 +1,18 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
using Dalamud.Bindings.ImGui;
|
||||
using Dalamud.Memory;
|
||||
|
||||
using Serilog;
|
||||
|
||||
using TerraFX.Interop.Windows;
|
||||
|
||||
using static Dalamud.Interface.ImGuiBackend.Helpers.ImGuiViewportHelpers;
|
||||
|
||||
using static TerraFX.Interop.Windows.Windows;
|
||||
|
||||
using ERROR = TerraFX.Interop.Windows.ERROR;
|
||||
|
|
@ -245,6 +244,9 @@ internal sealed unsafe partial class Win32InputHandler : IImGuiInputHandler
|
|||
return default(LRESULT);
|
||||
}
|
||||
|
||||
if (!ImGui.IsWindowHovered(ImGuiHoveredFlags.AnyWindow))
|
||||
ImGui.ClearWindowFocus();
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -371,6 +373,14 @@ internal sealed unsafe partial class Win32InputHandler : IImGuiInputHandler
|
|||
case WM.WM_DISPLAYCHANGE:
|
||||
this.viewportHandler.UpdateMonitors();
|
||||
break;
|
||||
|
||||
case WM.WM_KILLFOCUS when hWndCurrent == this.hWnd:
|
||||
if (!ImGui.IsAnyMouseDown() && GetCapture() == hWndCurrent)
|
||||
ReleaseCapture();
|
||||
|
||||
ImGui.GetIO().WantCaptureMouse = false;
|
||||
ImGui.ClearWindowFocus();
|
||||
break;
|
||||
}
|
||||
|
||||
return null;
|
||||
|
|
@ -531,7 +541,7 @@ internal sealed unsafe partial class Win32InputHandler : IImGuiInputHandler
|
|||
|
||||
// We still want to return MA_NOACTIVATE
|
||||
// https://docs.microsoft.com/en-us/windows/win32/inputdev/wm-mouseactivate
|
||||
return 0x3;
|
||||
return MA.MA_NOACTIVATE;
|
||||
case WM.WM_NCHITTEST:
|
||||
// Let mouse pass-through the window. This will allow the backend to set io.MouseHoveredViewport properly (which is OPTIONAL).
|
||||
// The ImGuiViewportFlags_NoInputs flag is set while dragging a viewport, as want to detect the window behind the one we are dragging.
|
||||
|
|
@ -539,8 +549,7 @@ internal sealed unsafe partial class Win32InputHandler : IImGuiInputHandler
|
|||
// your main loop after calling UpdatePlatformWindows(). Iterate all viewports/platform windows and pass the flag to your windowing system.
|
||||
if (viewport.Flags.HasFlag(ImGuiViewportFlags.NoInputs))
|
||||
{
|
||||
// https://docs.microsoft.com/en-us/windows/win32/inputdev/wm-nchittest
|
||||
return -1;
|
||||
return HTTRANSPARENT;
|
||||
}
|
||||
|
||||
break;
|
||||
|
|
@ -575,51 +584,50 @@ internal sealed unsafe partial class Win32InputHandler : IImGuiInputHandler
|
|||
|
||||
private struct ViewportHandler : IDisposable
|
||||
{
|
||||
[SuppressMessage("ReSharper", "CollectionNeverQueried.Local", Justification = "Keeping references alive")]
|
||||
private readonly List<object> delegateReferences = new();
|
||||
private static readonly string WindowClassName = typeof(ViewportHandler).FullName!;
|
||||
|
||||
private Win32InputHandler input;
|
||||
private nint classNamePtr;
|
||||
|
||||
private bool wantUpdateMonitors = true;
|
||||
|
||||
public ViewportHandler(Win32InputHandler input)
|
||||
{
|
||||
this.input = input;
|
||||
this.classNamePtr = Marshal.StringToHGlobalUni("ImGui Platform");
|
||||
|
||||
var pio = ImGui.GetPlatformIO();
|
||||
pio.PlatformCreateWindow = this.RegisterFunctionPointer<CreateWindowDelegate>(this.OnCreateWindow);
|
||||
pio.PlatformDestroyWindow = this.RegisterFunctionPointer<DestroyWindowDelegate>(this.OnDestroyWindow);
|
||||
pio.PlatformShowWindow = this.RegisterFunctionPointer<ShowWindowDelegate>(this.OnShowWindow);
|
||||
pio.PlatformSetWindowPos = this.RegisterFunctionPointer<SetWindowPosDelegate>(this.OnSetWindowPos);
|
||||
pio.PlatformGetWindowPos = this.RegisterFunctionPointer<GetWindowPosDelegate>(this.OnGetWindowPos);
|
||||
pio.PlatformSetWindowSize = this.RegisterFunctionPointer<SetWindowSizeDelegate>(this.OnSetWindowSize);
|
||||
pio.PlatformGetWindowSize = this.RegisterFunctionPointer<GetWindowSizeDelegate>(this.OnGetWindowSize);
|
||||
pio.PlatformSetWindowFocus = this.RegisterFunctionPointer<SetWindowFocusDelegate>(this.OnSetWindowFocus);
|
||||
pio.PlatformGetWindowFocus = this.RegisterFunctionPointer<GetWindowFocusDelegate>(this.OnGetWindowFocus);
|
||||
pio.PlatformGetWindowMinimized =
|
||||
this.RegisterFunctionPointer<GetWindowMinimizedDelegate>(this.OnGetWindowMinimized);
|
||||
pio.PlatformSetWindowTitle = this.RegisterFunctionPointer<SetWindowTitleDelegate>(this.OnSetWindowTitle);
|
||||
pio.PlatformSetWindowAlpha = this.RegisterFunctionPointer<SetWindowAlphaDelegate>(this.OnSetWindowAlpha);
|
||||
pio.PlatformUpdateWindow = this.RegisterFunctionPointer<UpdateWindowDelegate>(this.OnUpdateWindow);
|
||||
pio.PlatformCreateWindow = (delegate* unmanaged[Cdecl]<ImGuiViewportPtr, void>)&OnCreateWindow;
|
||||
pio.PlatformDestroyWindow = (delegate* unmanaged[Cdecl]<ImGuiViewportPtr, void>)&OnDestroyWindow;
|
||||
pio.PlatformShowWindow = (delegate* unmanaged[Cdecl]<ImGuiViewportPtr, void>)&OnShowWindow;
|
||||
pio.PlatformSetWindowPos = (delegate* unmanaged[Cdecl]<ImGuiViewportPtr, Vector2, void>)&OnSetWindowPos;
|
||||
pio.PlatformGetWindowPos = (delegate* unmanaged[Cdecl]<Vector2*, ImGuiViewportPtr, Vector2*>)&OnGetWindowPos;
|
||||
pio.PlatformSetWindowSize = (delegate* unmanaged[Cdecl]<ImGuiViewportPtr, Vector2, void>)&OnSetWindowSize;
|
||||
pio.PlatformGetWindowSize = (delegate* unmanaged[Cdecl]<Vector2*, ImGuiViewportPtr, Vector2*>)&OnGetWindowSize;
|
||||
pio.PlatformSetWindowFocus = (delegate* unmanaged[Cdecl]<ImGuiViewportPtr, void>)&OnSetWindowFocus;
|
||||
pio.PlatformGetWindowFocus = (delegate* unmanaged[Cdecl]<ImGuiViewportPtr, byte>)&OnGetWindowFocus;
|
||||
pio.PlatformGetWindowMinimized = (delegate* unmanaged[Cdecl]<ImGuiViewportPtr, byte>)&OnGetWindowMinimized;
|
||||
pio.PlatformSetWindowTitle = (delegate* unmanaged[Cdecl]<ImGuiViewportPtr, byte*, void>)&OnSetWindowTitle;
|
||||
pio.PlatformSetWindowAlpha = (delegate* unmanaged[Cdecl]<ImGuiViewportPtr, float, void>)&OnSetWindowAlpha;
|
||||
pio.PlatformUpdateWindow = (delegate* unmanaged[Cdecl]<ImGuiViewportPtr, void>)&OnUpdateWindow;
|
||||
// pio.Platform_SetImeInputPos = this.RegisterFunctionPointer<SetImeInputPosDelegate>(this.OnSetImeInputPos);
|
||||
// pio.Platform_GetWindowDpiScale = this.RegisterFunctionPointer<GetWindowDpiScaleDelegate>(this.OnGetWindowDpiScale);
|
||||
// pio.Platform_ChangedViewport = this.RegisterFunctionPointer<ChangedViewportDelegate>(this.OnChangedViewport);
|
||||
|
||||
var wcex = new WNDCLASSEXW
|
||||
fixed (char* windowClassNamePtr = WindowClassName)
|
||||
{
|
||||
cbSize = (uint)sizeof(WNDCLASSEXW),
|
||||
style = CS.CS_HREDRAW | CS.CS_VREDRAW,
|
||||
hInstance = GetModuleHandleW(null),
|
||||
hbrBackground = (HBRUSH)(1 + COLOR.COLOR_BACKGROUND),
|
||||
lpfnWndProc = (delegate* unmanaged<HWND, uint, WPARAM, LPARAM, LRESULT>)Marshal
|
||||
.GetFunctionPointerForDelegate(this.input.wndProcDelegate),
|
||||
lpszClassName = (ushort*)this.classNamePtr,
|
||||
};
|
||||
var wcex = new WNDCLASSEXW
|
||||
{
|
||||
cbSize = (uint)sizeof(WNDCLASSEXW),
|
||||
style = CS.CS_HREDRAW | CS.CS_VREDRAW,
|
||||
hInstance = (HINSTANCE)Marshal.GetHINSTANCE(typeof(ViewportHandler).Module),
|
||||
hbrBackground = (HBRUSH)(1 + COLOR.COLOR_BACKGROUND),
|
||||
lpfnWndProc = (delegate* unmanaged<HWND, uint, WPARAM, LPARAM, LRESULT>)Marshal
|
||||
.GetFunctionPointerForDelegate(this.input.wndProcDelegate),
|
||||
lpszClassName = (ushort*)windowClassNamePtr,
|
||||
};
|
||||
|
||||
if (RegisterClassExW(&wcex) == 0)
|
||||
throw Marshal.GetExceptionForHR(Marshal.GetHRForLastWin32Error()) ?? new("RegisterClassEx Fail");
|
||||
if (RegisterClassExW(&wcex) == 0)
|
||||
throw Marshal.GetExceptionForHR(Marshal.GetHRForLastWin32Error()) ?? new("RegisterClassEx Fail");
|
||||
}
|
||||
|
||||
// Register main window handle (which is owned by the main application, not by us)
|
||||
// This is mostly for simplicity and consistency, so that our code (e.g. mouse handling etc.) can use same logic for main and secondary viewports.
|
||||
|
|
@ -647,11 +655,11 @@ internal sealed unsafe partial class Win32InputHandler : IImGuiInputHandler
|
|||
ImGui.GetPlatformIO().Handle->Monitors = default;
|
||||
}
|
||||
|
||||
if (this.classNamePtr != 0)
|
||||
fixed (char* windowClassNamePtr = WindowClassName)
|
||||
{
|
||||
UnregisterClassW((ushort*)this.classNamePtr, GetModuleHandleW(null));
|
||||
Marshal.FreeHGlobal(this.classNamePtr);
|
||||
this.classNamePtr = 0;
|
||||
UnregisterClassW(
|
||||
(ushort*)windowClassNamePtr,
|
||||
(HINSTANCE)Marshal.GetHINSTANCE(typeof(ViewportHandler).Module));
|
||||
}
|
||||
|
||||
pio.PlatformCreateWindow = null;
|
||||
|
|
@ -740,13 +748,8 @@ internal sealed unsafe partial class Win32InputHandler : IImGuiInputHandler
|
|||
}
|
||||
}
|
||||
|
||||
private void* RegisterFunctionPointer<T>(T obj)
|
||||
{
|
||||
this.delegateReferences.Add(obj);
|
||||
return Marshal.GetFunctionPointerForDelegate(obj).ToPointer();
|
||||
}
|
||||
|
||||
private void OnCreateWindow(ImGuiViewportPtr viewport)
|
||||
[UnmanagedCallersOnly(CallConvs = [typeof(CallConvCdecl)])]
|
||||
private static void OnCreateWindow(ImGuiViewportPtr viewport)
|
||||
{
|
||||
var data = (ImGuiViewportDataWin32*)Marshal.AllocHGlobal(Marshal.SizeOf<ImGuiViewportDataWin32>());
|
||||
viewport.PlatformUserData = data;
|
||||
|
|
@ -774,12 +777,12 @@ internal sealed unsafe partial class Win32InputHandler : IImGuiInputHandler
|
|||
};
|
||||
AdjustWindowRectEx(&rect, (uint)data->DwStyle, false, (uint)data->DwExStyle);
|
||||
|
||||
fixed (char* pwszWindowTitle = "Untitled")
|
||||
fixed (char* windowClassNamePtr = WindowClassName)
|
||||
{
|
||||
data->Hwnd = CreateWindowExW(
|
||||
(uint)data->DwExStyle,
|
||||
(ushort*)this.classNamePtr,
|
||||
(ushort*)pwszWindowTitle,
|
||||
(ushort*)windowClassNamePtr,
|
||||
(ushort*)windowClassNamePtr,
|
||||
(uint)data->DwStyle,
|
||||
rect.left,
|
||||
rect.top,
|
||||
|
|
@ -787,8 +790,8 @@ internal sealed unsafe partial class Win32InputHandler : IImGuiInputHandler
|
|||
rect.bottom - rect.top,
|
||||
parentWindow,
|
||||
default,
|
||||
GetModuleHandleW(null),
|
||||
default);
|
||||
(HINSTANCE)Marshal.GetHINSTANCE(typeof(ViewportHandler).Module),
|
||||
null);
|
||||
}
|
||||
|
||||
data->HwndOwned = true;
|
||||
|
|
@ -796,7 +799,8 @@ internal sealed unsafe partial class Win32InputHandler : IImGuiInputHandler
|
|||
viewport.PlatformHandle = viewport.PlatformHandleRaw = data->Hwnd;
|
||||
}
|
||||
|
||||
private void OnDestroyWindow(ImGuiViewportPtr viewport)
|
||||
[UnmanagedCallersOnly(CallConvs = [typeof(CallConvCdecl)])]
|
||||
private static void OnDestroyWindow(ImGuiViewportPtr viewport)
|
||||
{
|
||||
// This is also called on the main viewport for some reason, and we never set that viewport's PlatformUserData
|
||||
if (viewport.PlatformUserData == null) return;
|
||||
|
|
@ -807,7 +811,11 @@ internal sealed unsafe partial class Win32InputHandler : IImGuiInputHandler
|
|||
{
|
||||
// Transfer capture so if we started dragging from a window that later disappears, we'll still receive the MOUSEUP event.
|
||||
ReleaseCapture();
|
||||
SetCapture(this.input.hWnd);
|
||||
if (viewport.ParentViewportId != 0)
|
||||
{
|
||||
var parentViewport = ImGui.FindViewportByID(viewport.ParentViewportId);
|
||||
SetCapture((HWND)parentViewport.PlatformHandle);
|
||||
}
|
||||
}
|
||||
|
||||
if (data->Hwnd != nint.Zero && data->HwndOwned)
|
||||
|
|
@ -826,7 +834,8 @@ internal sealed unsafe partial class Win32InputHandler : IImGuiInputHandler
|
|||
viewport.PlatformUserData = viewport.PlatformHandle = null;
|
||||
}
|
||||
|
||||
private void OnShowWindow(ImGuiViewportPtr viewport)
|
||||
[UnmanagedCallersOnly(CallConvs = [typeof(CallConvCdecl)])]
|
||||
private static void OnShowWindow(ImGuiViewportPtr viewport)
|
||||
{
|
||||
var data = (ImGuiViewportDataWin32*)viewport.PlatformUserData;
|
||||
|
||||
|
|
@ -836,7 +845,8 @@ internal sealed unsafe partial class Win32InputHandler : IImGuiInputHandler
|
|||
ShowWindow(data->Hwnd, SW.SW_SHOW);
|
||||
}
|
||||
|
||||
private void OnUpdateWindow(ImGuiViewportPtr viewport)
|
||||
[UnmanagedCallersOnly(CallConvs = [typeof(CallConvCdecl)])]
|
||||
private static void OnUpdateWindow(ImGuiViewportPtr viewport)
|
||||
{
|
||||
// (Optional) Update Win32 style if it changed _after_ creation.
|
||||
// Generally they won't change unless configuration flags are changed, but advanced uses (such as manually rewriting viewport flags) make this useful.
|
||||
|
|
@ -897,17 +907,18 @@ internal sealed unsafe partial class Win32InputHandler : IImGuiInputHandler
|
|||
}
|
||||
}
|
||||
|
||||
private Vector2* OnGetWindowPos(Vector2* returnStorage, ImGuiViewportPtr viewport)
|
||||
[UnmanagedCallersOnly(CallConvs = [typeof(CallConvCdecl)])]
|
||||
private static Vector2* OnGetWindowPos(Vector2* returnValueStorage, ImGuiViewportPtr viewport)
|
||||
{
|
||||
var data = (ImGuiViewportDataWin32*)viewport.PlatformUserData;
|
||||
var pt = new POINT { x = 0, y = 0 };
|
||||
ClientToScreen(data->Hwnd, &pt);
|
||||
returnStorage->X = pt.x;
|
||||
returnStorage->Y = pt.y;
|
||||
return returnStorage;
|
||||
*returnValueStorage = new(pt.x, pt.y);
|
||||
return returnValueStorage;
|
||||
}
|
||||
|
||||
private void OnSetWindowPos(ImGuiViewportPtr viewport, Vector2 pos)
|
||||
[UnmanagedCallersOnly(CallConvs = [typeof(CallConvCdecl)])]
|
||||
private static void OnSetWindowPos(ImGuiViewportPtr viewport, Vector2 pos)
|
||||
{
|
||||
var data = (ImGuiViewportDataWin32*)viewport.PlatformUserData;
|
||||
var rect = new RECT((int)pos.X, (int)pos.Y, (int)pos.X, (int)pos.Y);
|
||||
|
|
@ -924,17 +935,18 @@ internal sealed unsafe partial class Win32InputHandler : IImGuiInputHandler
|
|||
SWP.SWP_NOACTIVATE);
|
||||
}
|
||||
|
||||
private Vector2* OnGetWindowSize(Vector2* returnStorage, ImGuiViewportPtr viewport)
|
||||
[UnmanagedCallersOnly(CallConvs = [typeof(CallConvCdecl)])]
|
||||
private static Vector2* OnGetWindowSize(Vector2* returnValueStorage, ImGuiViewportPtr viewport)
|
||||
{
|
||||
var data = (ImGuiViewportDataWin32*)viewport.PlatformUserData;
|
||||
RECT rect;
|
||||
GetClientRect(data->Hwnd, &rect);
|
||||
returnStorage->X = rect.right - rect.left;
|
||||
returnStorage->Y = rect.bottom - rect.top;
|
||||
return returnStorage;
|
||||
*returnValueStorage = new(rect.right - rect.left, rect.bottom - rect.top);
|
||||
return returnValueStorage;
|
||||
}
|
||||
|
||||
private void OnSetWindowSize(ImGuiViewportPtr viewport, Vector2 size)
|
||||
[UnmanagedCallersOnly(CallConvs = [typeof(CallConvCdecl)])]
|
||||
private static void OnSetWindowSize(ImGuiViewportPtr viewport, Vector2 size)
|
||||
{
|
||||
var data = (ImGuiViewportDataWin32*)viewport.PlatformUserData;
|
||||
|
||||
|
|
@ -952,7 +964,8 @@ internal sealed unsafe partial class Win32InputHandler : IImGuiInputHandler
|
|||
SWP.SWP_NOACTIVATE);
|
||||
}
|
||||
|
||||
private void OnSetWindowFocus(ImGuiViewportPtr viewport)
|
||||
[UnmanagedCallersOnly(CallConvs = [typeof(CallConvCdecl)])]
|
||||
private static void OnSetWindowFocus(ImGuiViewportPtr viewport)
|
||||
{
|
||||
var data = (ImGuiViewportDataWin32*)viewport.PlatformUserData;
|
||||
|
||||
|
|
@ -961,26 +974,30 @@ internal sealed unsafe partial class Win32InputHandler : IImGuiInputHandler
|
|||
SetFocus(data->Hwnd);
|
||||
}
|
||||
|
||||
private bool OnGetWindowFocus(ImGuiViewportPtr viewport)
|
||||
[UnmanagedCallersOnly(CallConvs = [typeof(CallConvCdecl)])]
|
||||
private static byte OnGetWindowFocus(ImGuiViewportPtr viewport)
|
||||
{
|
||||
var data = (ImGuiViewportDataWin32*)viewport.PlatformUserData;
|
||||
return GetForegroundWindow() == data->Hwnd;
|
||||
return GetForegroundWindow() == data->Hwnd ? (byte)1 : (byte)0;
|
||||
}
|
||||
|
||||
private bool OnGetWindowMinimized(ImGuiViewportPtr viewport)
|
||||
[UnmanagedCallersOnly(CallConvs = [typeof(CallConvCdecl)])]
|
||||
private static byte OnGetWindowMinimized(ImGuiViewportPtr viewport)
|
||||
{
|
||||
var data = (ImGuiViewportDataWin32*)viewport.PlatformUserData;
|
||||
return IsIconic(data->Hwnd);
|
||||
return IsIconic(data->Hwnd) ? (byte)1 : (byte)0;
|
||||
}
|
||||
|
||||
private void OnSetWindowTitle(ImGuiViewportPtr viewport, string title)
|
||||
[UnmanagedCallersOnly(CallConvs = [typeof(CallConvCdecl)])]
|
||||
private static void OnSetWindowTitle(ImGuiViewportPtr viewport, byte* title)
|
||||
{
|
||||
var data = (ImGuiViewportDataWin32*)viewport.PlatformUserData;
|
||||
fixed (char* pwszTitle = title)
|
||||
fixed (char* pwszTitle = MemoryHelper.ReadStringNullTerminated((nint)title))
|
||||
SetWindowTextW(data->Hwnd, (ushort*)pwszTitle);
|
||||
}
|
||||
|
||||
private void OnSetWindowAlpha(ImGuiViewportPtr viewport, float alpha)
|
||||
[UnmanagedCallersOnly(CallConvs = [typeof(CallConvCdecl)])]
|
||||
private static void OnSetWindowAlpha(ImGuiViewportPtr viewport, float alpha)
|
||||
{
|
||||
var data = (ImGuiViewportDataWin32*)viewport.PlatformUserData;
|
||||
var style = GetWindowLongW(data->Hwnd, GWL.GWL_EXSTYLE);
|
||||
|
|
|
|||
|
|
@ -223,15 +223,15 @@ internal unsafe partial class Dx11Renderer : IImGuiRenderer
|
|||
ImDrawDataPtr drawData,
|
||||
bool clearRenderTarget)
|
||||
{
|
||||
// Do nothing when there's nothing to draw
|
||||
if (drawData.IsNull || !drawData.Valid)
|
||||
return;
|
||||
|
||||
// Avoid rendering when minimized
|
||||
if (drawData.DisplaySize.X <= 0 || drawData.DisplaySize.Y <= 0)
|
||||
return;
|
||||
|
||||
using var oldState = new D3D11DeviceContextStateBackup(this.featureLevel, this.context.Get());
|
||||
|
||||
// Setup desired DX state
|
||||
this.SetupRenderState(drawData);
|
||||
|
||||
// Set up render target
|
||||
this.context.Get()->OMSetRenderTargets(1, &renderTargetView, null);
|
||||
if (clearRenderTarget)
|
||||
{
|
||||
|
|
@ -239,17 +239,17 @@ internal unsafe partial class Dx11Renderer : IImGuiRenderer
|
|||
this.context.Get()->ClearRenderTargetView(renderTargetView, (float*)&color);
|
||||
}
|
||||
|
||||
if (!drawData.Valid || drawData.CmdListsCount == 0)
|
||||
return;
|
||||
|
||||
// Stop if there's nothing to draw
|
||||
var cmdLists = new Span<ImDrawListPtr>(drawData.Handle->CmdLists, drawData.Handle->CmdListsCount);
|
||||
if (cmdLists.IsEmpty)
|
||||
return;
|
||||
|
||||
// Create and grow vertex/index buffers if needed
|
||||
if (this.vertexBufferSize < drawData.TotalVtxCount)
|
||||
this.vertexBuffer.Dispose();
|
||||
if (this.vertexBuffer.Get() is null)
|
||||
{
|
||||
this.vertexBufferSize = drawData.TotalVtxCount + 5000;
|
||||
this.vertexBufferSize = drawData.TotalVtxCount + 8192;
|
||||
var desc = new D3D11_BUFFER_DESC(
|
||||
(uint)(sizeof(ImDrawVert) * this.vertexBufferSize),
|
||||
(uint)D3D11_BIND_FLAG.D3D11_BIND_VERTEX_BUFFER,
|
||||
|
|
@ -264,7 +264,7 @@ internal unsafe partial class Dx11Renderer : IImGuiRenderer
|
|||
this.indexBuffer.Dispose();
|
||||
if (this.indexBuffer.Get() is null)
|
||||
{
|
||||
this.indexBufferSize = drawData.TotalIdxCount + 5000;
|
||||
this.indexBufferSize = drawData.TotalIdxCount + 16384;
|
||||
var desc = new D3D11_BUFFER_DESC(
|
||||
(uint)(sizeof(ushort) * this.indexBufferSize),
|
||||
(uint)D3D11_BIND_FLAG.D3D11_BIND_INDEX_BUFFER,
|
||||
|
|
@ -275,9 +275,14 @@ internal unsafe partial class Dx11Renderer : IImGuiRenderer
|
|||
this.indexBuffer.Attach(buffer);
|
||||
}
|
||||
|
||||
// Upload vertex/index data into a single contiguous GPU buffer
|
||||
using var oldState = new D3D11DeviceContextStateBackup(this.featureLevel, this.context.Get());
|
||||
|
||||
// Setup desired DX state
|
||||
this.SetupRenderState(drawData);
|
||||
|
||||
try
|
||||
{
|
||||
// Upload vertex/index data into a single contiguous GPU buffer.
|
||||
var vertexData = default(D3D11_MAPPED_SUBRESOURCE);
|
||||
var indexData = default(D3D11_MAPPED_SUBRESOURCE);
|
||||
this.context.Get()->Map(
|
||||
|
|
@ -306,26 +311,18 @@ internal unsafe partial class Dx11Renderer : IImGuiRenderer
|
|||
targetVertices = targetVertices[vertices.Length..];
|
||||
targetIndices = targetIndices[indices.Length..];
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.context.Get()->Unmap((ID3D11Resource*)this.vertexBuffer.Get(), 0);
|
||||
this.context.Get()->Unmap((ID3D11Resource*)this.indexBuffer.Get(), 0);
|
||||
}
|
||||
|
||||
// Setup orthographic projection matrix into our constant buffer.
|
||||
// Our visible imgui space lies from DisplayPos (LT) to DisplayPos+DisplaySize (RB).
|
||||
// DisplayPos is (0,0) for single viewport apps.
|
||||
try
|
||||
{
|
||||
var data = default(D3D11_MAPPED_SUBRESOURCE);
|
||||
// Setup orthographic projection matrix into our constant buffer.
|
||||
// Our visible imgui space lies from DisplayPos (LT) to DisplayPos+DisplaySize (RB).
|
||||
// DisplayPos is (0,0) for single viewport apps.
|
||||
var constantBufferData = default(D3D11_MAPPED_SUBRESOURCE);
|
||||
this.context.Get()->Map(
|
||||
(ID3D11Resource*)this.vertexConstantBuffer.Get(),
|
||||
0,
|
||||
D3D11_MAP.D3D11_MAP_WRITE_DISCARD,
|
||||
0,
|
||||
&data).ThrowOnError();
|
||||
*(Matrix4x4*)data.pData = Matrix4x4.CreateOrthographicOffCenter(
|
||||
&constantBufferData).ThrowOnError();
|
||||
*(Matrix4x4*)constantBufferData.pData = Matrix4x4.CreateOrthographicOffCenter(
|
||||
drawData.DisplayPos.X,
|
||||
drawData.DisplayPos.X + drawData.DisplaySize.X,
|
||||
drawData.DisplayPos.Y + drawData.DisplaySize.Y,
|
||||
|
|
@ -335,6 +332,8 @@ internal unsafe partial class Dx11Renderer : IImGuiRenderer
|
|||
}
|
||||
finally
|
||||
{
|
||||
this.context.Get()->Unmap((ID3D11Resource*)this.vertexBuffer.Get(), 0);
|
||||
this.context.Get()->Unmap((ID3D11Resource*)this.indexBuffer.Get(), 0);
|
||||
this.context.Get()->Unmap((ID3D11Resource*)this.vertexConstantBuffer.Get(), 0);
|
||||
}
|
||||
|
||||
|
|
@ -343,8 +342,6 @@ internal unsafe partial class Dx11Renderer : IImGuiRenderer
|
|||
var vertexOffset = 0;
|
||||
var indexOffset = 0;
|
||||
var clipOff = new Vector4(drawData.DisplayPos, drawData.DisplayPos.X, drawData.DisplayPos.Y);
|
||||
this.context.Get()->PSSetShader(this.pixelShader, null, 0);
|
||||
this.context.Get()->PSSetSamplers(0, 1, this.sampler.GetAddressOf());
|
||||
foreach (ref var cmdList in cmdLists)
|
||||
{
|
||||
var cmds = new ImVectorWrapper<ImDrawCmd>(cmdList.Handle->CmdBuffer.ToUntyped());
|
||||
|
|
@ -467,7 +464,8 @@ internal unsafe partial class Dx11Renderer : IImGuiRenderer
|
|||
buffer = this.vertexConstantBuffer.Get();
|
||||
ctx->VSSetConstantBuffers(0, 1, &buffer);
|
||||
|
||||
// PS handled later
|
||||
ctx->PSSetShader(this.pixelShader, null, 0);
|
||||
ctx->PSSetSamplers(0, 1, this.sampler.GetAddressOf());
|
||||
|
||||
ctx->GSSetShader(null, null, 0);
|
||||
ctx->HSSetShader(null, null, 0);
|
||||
|
|
|
|||
|
|
@ -2,11 +2,9 @@
|
|||
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Text.Unicode;
|
||||
|
|
@ -46,24 +44,24 @@ internal sealed unsafe class DalamudIme : IInternalDisposableService
|
|||
.ToDictionary(x => x.Item1, x => x.Name);
|
||||
|
||||
private static readonly UnicodeRange[] HanRange =
|
||||
{
|
||||
[
|
||||
UnicodeRanges.CjkRadicalsSupplement,
|
||||
UnicodeRanges.CjkSymbolsandPunctuation,
|
||||
UnicodeRanges.CjkUnifiedIdeographsExtensionA,
|
||||
UnicodeRanges.CjkUnifiedIdeographs,
|
||||
UnicodeRanges.CjkCompatibilityIdeographs,
|
||||
UnicodeRanges.CjkCompatibilityForms,
|
||||
UnicodeRanges.CjkCompatibilityForms
|
||||
// No more; Extension B~ are outside BMP range
|
||||
};
|
||||
];
|
||||
|
||||
private static readonly UnicodeRange[] HangulRange =
|
||||
{
|
||||
[
|
||||
UnicodeRanges.HangulJamo,
|
||||
UnicodeRanges.HangulSyllables,
|
||||
UnicodeRanges.HangulCompatibilityJamo,
|
||||
UnicodeRanges.HangulJamoExtendedA,
|
||||
UnicodeRanges.HangulJamoExtendedB,
|
||||
};
|
||||
UnicodeRanges.HangulJamoExtendedB
|
||||
];
|
||||
|
||||
[ServiceManager.ServiceDependency]
|
||||
private readonly DalamudConfiguration dalamudConfiguration = Service<DalamudConfiguration>.Get();
|
||||
|
|
@ -109,24 +107,6 @@ internal sealed unsafe class DalamudIme : IInternalDisposableService
|
|||
private bool updateInputLanguage = true;
|
||||
private bool updateImeStatusAgain;
|
||||
|
||||
[SuppressMessage("StyleCop.CSharp.SpacingRules", "SA1003:Symbols should be spaced correctly", Justification = ".")]
|
||||
static DalamudIme()
|
||||
{
|
||||
nint cimgui;
|
||||
try
|
||||
{
|
||||
_ = ImGui.GetCurrentContext();
|
||||
|
||||
cimgui = Process.GetCurrentProcess().Modules.Cast<ProcessModule>()
|
||||
.First(x => x.ModuleName == "cimgui.dll")
|
||||
.BaseAddress;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
[ServiceManager.ServiceConstructor]
|
||||
private DalamudIme(InterfaceManager.InterfaceManagerWithScene imws)
|
||||
{
|
||||
|
|
@ -170,11 +150,11 @@ internal sealed unsafe class DalamudIme : IInternalDisposableService
|
|||
if (!ImGui.GetIO().ConfigInputTextCursorBlink)
|
||||
return true;
|
||||
var textState = GetInputTextState();
|
||||
if (textState->Id == 0 || (textState->Flags & ImGuiInputTextFlags.ReadOnly) != 0)
|
||||
if (textState.ID == 0 || (textState.Flags & ImGuiInputTextFlags.ReadOnly) != 0)
|
||||
return true;
|
||||
if (textState->CursorAnim <= 0)
|
||||
if (textState.CursorAnim <= 0)
|
||||
return true;
|
||||
return textState->CursorAnim % 1.2f <= 0.8f;
|
||||
return textState.CursorAnim % 1.2f <= 0.8f;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -227,11 +207,7 @@ internal sealed unsafe class DalamudIme : IInternalDisposableService
|
|||
}
|
||||
}
|
||||
|
||||
private static ImGuiInputTextStateWrapper* GetInputTextState()
|
||||
{
|
||||
var ctx = ImGui.GetCurrentContext();
|
||||
return (ImGuiInputTextStateWrapper*)&ctx.Handle->InputTextState;
|
||||
}
|
||||
private static ImGuiInputTextStatePtr GetInputTextState() => new(&ImGui.GetCurrentContext().Handle->InputTextState);
|
||||
|
||||
private static (string String, bool Supported) ToUcs2(char* data, int nc = -1)
|
||||
{
|
||||
|
|
@ -332,7 +308,7 @@ internal sealed unsafe class DalamudIme : IInternalDisposableService
|
|||
try
|
||||
{
|
||||
var textState = GetInputTextState();
|
||||
var invalidTarget = textState->Id == 0 || (textState->Flags & ImGuiInputTextFlags.ReadOnly) != 0;
|
||||
var invalidTarget = textState.ID == 0 || (textState.Flags & ImGuiInputTextFlags.ReadOnly) != 0;
|
||||
|
||||
#if IMEDEBUG
|
||||
switch (args.Message)
|
||||
|
|
@ -564,17 +540,17 @@ internal sealed unsafe class DalamudIme : IInternalDisposableService
|
|||
var textState = GetInputTextState();
|
||||
if (this.temporaryUndoSelection is not null)
|
||||
{
|
||||
textState->Undo();
|
||||
textState->SelectionTuple = this.temporaryUndoSelection.Value;
|
||||
textState.Undo();
|
||||
textState.SetSelectionTuple(this.temporaryUndoSelection.Value);
|
||||
this.temporaryUndoSelection = null;
|
||||
}
|
||||
|
||||
textState->SanitizeSelectionRange();
|
||||
if (textState->ReplaceSelectionAndPushUndo(newString))
|
||||
this.temporaryUndoSelection = textState->SelectionTuple;
|
||||
textState.SanitizeSelectionRange();
|
||||
if (textState.ReplaceSelectionAndPushUndo(newString))
|
||||
this.temporaryUndoSelection = textState.GetSelectionTuple();
|
||||
|
||||
// Put the cursor at the beginning, so that the candidate window appears aligned with the text.
|
||||
textState->SetSelectionRange(textState->SelectionTuple.Start, newString.Length, 0);
|
||||
textState.SetSelectionRange(textState.GetSelectionTuple().Start, newString.Length, 0);
|
||||
|
||||
if (finalCommit)
|
||||
{
|
||||
|
|
@ -621,7 +597,7 @@ internal sealed unsafe class DalamudIme : IInternalDisposableService
|
|||
this.temporaryUndoSelection = null;
|
||||
|
||||
var textState = GetInputTextState();
|
||||
textState->Stb.SelectStart = textState->Stb.Cursor = textState->Stb.SelectEnd;
|
||||
textState.Stb.SelectStart = textState.Stb.Cursor = textState.Stb.SelectEnd;
|
||||
|
||||
this.candidateStrings.Clear();
|
||||
this.immCandNative = default;
|
||||
|
|
@ -931,185 +907,6 @@ internal sealed unsafe class DalamudIme : IInternalDisposableService
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ported from imstb_textedit.h.
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential, Size = 0xE2C)]
|
||||
private struct StbTextEditState
|
||||
{
|
||||
/// <summary>
|
||||
/// Position of the text cursor within the string.
|
||||
/// </summary>
|
||||
public int Cursor;
|
||||
|
||||
/// <summary>
|
||||
/// Selection start point.
|
||||
/// </summary>
|
||||
public int SelectStart;
|
||||
|
||||
/// <summary>
|
||||
/// selection start and end point in characters; if equal, no selection.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Note that start may be less than or greater than end (e.g. when dragging the mouse,
|
||||
/// start is where the initial click was, and you can drag in either direction.)
|
||||
/// </remarks>
|
||||
public int SelectEnd;
|
||||
|
||||
/// <summary>
|
||||
/// Each text field keeps its own insert mode state.
|
||||
/// To keep an app-wide insert mode, copy this value in/out of the app state.
|
||||
/// </summary>
|
||||
public byte InsertMode;
|
||||
|
||||
/// <summary>
|
||||
/// Page size in number of row.
|
||||
/// This value MUST be set to >0 for pageup or pagedown in multilines documents.
|
||||
/// </summary>
|
||||
public int RowCountPerPage;
|
||||
|
||||
// Remainder is stb-private data.
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
private struct ImGuiInputTextStateWrapper
|
||||
{
|
||||
public uint Id;
|
||||
public int CurLenW;
|
||||
public int CurLenA;
|
||||
public ImVector<char> TextWRaw;
|
||||
public ImVector<byte> TextARaw;
|
||||
public ImVector<byte> InitialTextARaw;
|
||||
public bool TextAIsValid;
|
||||
public int BufCapacityA;
|
||||
public float ScrollX;
|
||||
public StbTextEditState Stb;
|
||||
public float CursorAnim;
|
||||
public bool CursorFollow;
|
||||
public bool SelectedAllMouseLock;
|
||||
public bool Edited;
|
||||
public ImGuiInputTextFlags Flags;
|
||||
|
||||
public ImVectorWrapper<char> TextW => new((ImVector*)&this.ThisWrapperPtr->TextWRaw);
|
||||
|
||||
public (int Start, int End, int Cursor) SelectionTuple
|
||||
{
|
||||
get => (this.Stb.SelectStart, this.Stb.SelectEnd, this.Stb.Cursor);
|
||||
set => (this.Stb.SelectStart, this.Stb.SelectEnd, this.Stb.Cursor) = value;
|
||||
}
|
||||
|
||||
private ImGuiInputTextStateWrapper* ThisWrapperPtr => (ImGuiInputTextStateWrapper*)Unsafe.AsPointer(ref this);
|
||||
|
||||
private ImGuiInputTextState* ThisPtr => (ImGuiInputTextState*)Unsafe.AsPointer(ref this);
|
||||
|
||||
public void SetSelectionRange(int offset, int length, int relativeCursorOffset)
|
||||
{
|
||||
this.Stb.SelectStart = offset;
|
||||
this.Stb.SelectEnd = offset + length;
|
||||
if (relativeCursorOffset >= 0)
|
||||
this.Stb.Cursor = this.Stb.SelectStart + relativeCursorOffset;
|
||||
else
|
||||
this.Stb.Cursor = this.Stb.SelectEnd + 1 + relativeCursorOffset;
|
||||
this.SanitizeSelectionRange();
|
||||
}
|
||||
|
||||
public void SanitizeSelectionRange()
|
||||
{
|
||||
ref var s = ref this.Stb.SelectStart;
|
||||
ref var e = ref this.Stb.SelectEnd;
|
||||
ref var c = ref this.Stb.Cursor;
|
||||
s = Math.Clamp(s, 0, this.CurLenW);
|
||||
e = Math.Clamp(e, 0, this.CurLenW);
|
||||
c = Math.Clamp(c, 0, this.CurLenW);
|
||||
if (s == e)
|
||||
s = e = c;
|
||||
if (s > e)
|
||||
(s, e) = (e, s);
|
||||
}
|
||||
|
||||
public void Undo() => ImGuiP.Custom_StbTextUndo(this.ThisPtr);
|
||||
|
||||
public bool MakeUndoReplace(int offset, int oldLength, int newLength)
|
||||
{
|
||||
if (oldLength == 0 && newLength == 0)
|
||||
return false;
|
||||
|
||||
ImGuiP.Custom_StbTextMakeUndoReplace(this.ThisPtr, offset, oldLength, newLength);
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool ReplaceSelectionAndPushUndo(ReadOnlySpan<char> newText)
|
||||
{
|
||||
var off = this.Stb.SelectStart;
|
||||
var len = this.Stb.SelectEnd - this.Stb.SelectStart;
|
||||
return this.MakeUndoReplace(off, len, newText.Length) && this.ReplaceChars(off, len, newText);
|
||||
}
|
||||
|
||||
public bool ReplaceChars(int pos, int len, ReadOnlySpan<char> newText)
|
||||
{
|
||||
this.DeleteChars(pos, len);
|
||||
return this.InsertChars(pos, newText);
|
||||
}
|
||||
|
||||
// See imgui_widgets.cpp: STB_TEXTEDIT_DELETECHARS
|
||||
public void DeleteChars(int pos, int n)
|
||||
{
|
||||
if (n == 0)
|
||||
return;
|
||||
|
||||
var dst = this.TextW.Data + pos;
|
||||
|
||||
// We maintain our buffer length in both UTF-8 and wchar formats
|
||||
this.Edited = true;
|
||||
this.CurLenA -= Encoding.UTF8.GetByteCount(dst, n);
|
||||
this.CurLenW -= n;
|
||||
|
||||
// Offset remaining text (FIXME-OPT: Use memmove)
|
||||
var src = this.TextW.Data + pos + n;
|
||||
int i;
|
||||
for (i = 0; src[i] != 0; i++)
|
||||
dst[i] = src[i];
|
||||
dst[i] = '\0';
|
||||
}
|
||||
|
||||
// See imgui_widgets.cpp: STB_TEXTEDIT_INSERTCHARS
|
||||
public bool InsertChars(int pos, ReadOnlySpan<char> newText)
|
||||
{
|
||||
if (newText.Length == 0)
|
||||
return true;
|
||||
|
||||
var isResizable = (this.Flags & ImGuiInputTextFlags.CallbackResize) != 0;
|
||||
var textLen = this.CurLenW;
|
||||
Debug.Assert(pos <= textLen, "pos <= text_len");
|
||||
|
||||
var newTextLenUtf8 = Encoding.UTF8.GetByteCount(newText);
|
||||
if (!isResizable && newTextLenUtf8 + this.CurLenA + 1 > this.BufCapacityA)
|
||||
return false;
|
||||
|
||||
// Grow internal buffer if needed
|
||||
if (newText.Length + textLen + 1 > this.TextW.Length)
|
||||
{
|
||||
if (!isResizable)
|
||||
return false;
|
||||
|
||||
Debug.Assert(textLen < this.TextW.Length, "text_len < this.TextW.Length");
|
||||
this.TextW.Resize(textLen + Math.Clamp(newText.Length * 4, 32, Math.Max(256, newText.Length)) + 1);
|
||||
}
|
||||
|
||||
var text = this.TextW.DataSpan;
|
||||
if (pos != textLen)
|
||||
text.Slice(pos, textLen - pos).CopyTo(text[(pos + newText.Length)..]);
|
||||
newText.CopyTo(text[pos..]);
|
||||
|
||||
this.Edited = true;
|
||||
this.CurLenW += newText.Length;
|
||||
this.CurLenA += newTextLenUtf8;
|
||||
this.TextW[this.CurLenW] = '\0';
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
#if IMEDEBUG
|
||||
private static class ImeDebug
|
||||
{
|
||||
|
|
|
|||
|
|
@ -575,16 +575,6 @@ internal class DalamudInterface : IInternalDisposableService
|
|||
|
||||
if (this.isCreditsDarkening)
|
||||
this.DrawCreditsDarkeningAnimation();
|
||||
|
||||
// Release focus of any ImGui window if we click into the game.
|
||||
var io = ImGui.GetIO();
|
||||
if (!io.WantCaptureMouse && (global::Windows.Win32.PInvoke.GetKeyState((int)VirtualKey.LBUTTON) & 0x8000) != 0)
|
||||
{
|
||||
unsafe
|
||||
{
|
||||
ImGui.SetWindowFocus((byte*)null);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
|
@ -856,9 +846,9 @@ internal class DalamudInterface : IInternalDisposableService
|
|||
this.OpenBranchSwitcher();
|
||||
}
|
||||
|
||||
ImGui.MenuItem(this.dalamud.StartInfo.GameVersion?.ToString() ?? "Unknown version", false);
|
||||
ImGui.MenuItem($"D: {Util.GetScmVersion()} CS: {Util.GetGitHashClientStructs()}[{FFXIVClientStructs.ThisAssembly.Git.Commits}]", false);
|
||||
ImGui.MenuItem($"CLR: {Environment.Version}", false);
|
||||
ImGui.MenuItem(this.dalamud.StartInfo.GameVersion?.ToString() ?? "Unknown version", false, false);
|
||||
ImGui.MenuItem($"D: {Util.GetScmVersion()} CS: {Util.GetGitHashClientStructs()}[{FFXIVClientStructs.ThisAssembly.Git.Commits}]", false, false);
|
||||
ImGui.MenuItem($"CLR: {Environment.Version}", false, false);
|
||||
|
||||
ImGui.EndMenu();
|
||||
}
|
||||
|
|
@ -1021,8 +1011,8 @@ internal class DalamudInterface : IInternalDisposableService
|
|||
}
|
||||
|
||||
ImGui.Separator();
|
||||
ImGui.MenuItem("API Level:" + PluginManager.DalamudApiLevel, false);
|
||||
ImGui.MenuItem("Loaded plugins:" + pluginManager.InstalledPlugins.Count(), false);
|
||||
ImGui.MenuItem("API Level:" + PluginManager.DalamudApiLevel, false, false);
|
||||
ImGui.MenuItem("Loaded plugins:" + pluginManager.InstalledPlugins.Count(), false, false);
|
||||
ImGui.EndMenu();
|
||||
}
|
||||
|
||||
|
|
|
|||
123
Dalamud/Interface/Internal/ImGuiInputTextStatePtrExtensions.cs
Normal file
123
Dalamud/Interface/Internal/ImGuiInputTextStatePtrExtensions.cs
Normal file
|
|
@ -0,0 +1,123 @@
|
|||
using System.Diagnostics;
|
||||
using System.Text;
|
||||
|
||||
using Dalamud.Bindings.ImGui;
|
||||
|
||||
namespace Dalamud.Interface.Internal;
|
||||
|
||||
#pragma warning disable SA1600
|
||||
internal static unsafe class ImGuiInputTextStatePtrExtensions
|
||||
{
|
||||
public static (int Start, int End, int Cursor) GetSelectionTuple(this ImGuiInputTextStatePtr self) =>
|
||||
(self.Stb.SelectStart, self.Stb.SelectEnd, self.Stb.Cursor);
|
||||
|
||||
public static void SetSelectionTuple(this ImGuiInputTextStatePtr self, (int Start, int End, int Cursor) value) =>
|
||||
(self.Stb.SelectStart, self.Stb.SelectEnd, self.Stb.Cursor) = value;
|
||||
|
||||
public static void SetSelectionRange(this ImGuiInputTextStatePtr self, int offset, int length, int relativeCursorOffset)
|
||||
{
|
||||
self.Stb.SelectStart = offset;
|
||||
self.Stb.SelectEnd = offset + length;
|
||||
if (relativeCursorOffset >= 0)
|
||||
self.Stb.Cursor = self.Stb.SelectStart + relativeCursorOffset;
|
||||
else
|
||||
self.Stb.Cursor = self.Stb.SelectEnd + 1 + relativeCursorOffset;
|
||||
self.SanitizeSelectionRange();
|
||||
}
|
||||
|
||||
public static void SanitizeSelectionRange(this ImGuiInputTextStatePtr self)
|
||||
{
|
||||
ref var s = ref self.Stb.SelectStart;
|
||||
ref var e = ref self.Stb.SelectEnd;
|
||||
ref var c = ref self.Stb.Cursor;
|
||||
s = Math.Clamp(s, 0, self.CurLenW);
|
||||
e = Math.Clamp(e, 0, self.CurLenW);
|
||||
c = Math.Clamp(c, 0, self.CurLenW);
|
||||
if (s == e)
|
||||
s = e = c;
|
||||
if (s > e)
|
||||
(s, e) = (e, s);
|
||||
}
|
||||
|
||||
public static void Undo(this ImGuiInputTextStatePtr self) => ImGuiP.Custom_StbTextUndo(self);
|
||||
|
||||
public static bool MakeUndoReplace(this ImGuiInputTextStatePtr self, int offset, int oldLength, int newLength)
|
||||
{
|
||||
if (oldLength == 0 && newLength == 0)
|
||||
return false;
|
||||
|
||||
ImGuiP.Custom_StbTextMakeUndoReplace(self, offset, oldLength, newLength);
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool ReplaceSelectionAndPushUndo(this ImGuiInputTextStatePtr self, ReadOnlySpan<char> newText)
|
||||
{
|
||||
var off = self.Stb.SelectStart;
|
||||
var len = self.Stb.SelectEnd - self.Stb.SelectStart;
|
||||
return self.MakeUndoReplace(off, len, newText.Length) && self.ReplaceChars(off, len, newText);
|
||||
}
|
||||
|
||||
public static bool ReplaceChars(this ImGuiInputTextStatePtr self, int pos, int len, ReadOnlySpan<char> newText)
|
||||
{
|
||||
self.DeleteChars(pos, len);
|
||||
return self.InsertChars(pos, newText);
|
||||
}
|
||||
|
||||
// See imgui_widgets.cpp: STB_TEXTEDIT_DELETECHARS
|
||||
public static void DeleteChars(this ImGuiInputTextStatePtr self, int pos, int n)
|
||||
{
|
||||
if (n == 0)
|
||||
return;
|
||||
|
||||
var dst = (char*)self.TextW.Data + pos;
|
||||
|
||||
// We maintain our buffer length in both UTF-8 and wchar formats
|
||||
self.Edited = true;
|
||||
self.CurLenA -= Encoding.UTF8.GetByteCount(dst, n);
|
||||
self.CurLenW -= n;
|
||||
|
||||
// Offset remaining text (FIXME-OPT: Use memmove)
|
||||
var src = (char*)self.TextW.Data + pos + n;
|
||||
int i;
|
||||
for (i = 0; src[i] != 0; i++)
|
||||
dst[i] = src[i];
|
||||
dst[i] = '\0';
|
||||
}
|
||||
|
||||
// See imgui_widgets.cpp: STB_TEXTEDIT_INSERTCHARS
|
||||
public static bool InsertChars(this ImGuiInputTextStatePtr self, int pos, ReadOnlySpan<char> newText)
|
||||
{
|
||||
if (newText.Length == 0)
|
||||
return true;
|
||||
|
||||
var isResizable = (self.Flags & ImGuiInputTextFlags.CallbackResize) != 0;
|
||||
var textLen = self.CurLenW;
|
||||
Debug.Assert(pos <= textLen, "pos <= text_len");
|
||||
|
||||
var newTextLenUtf8 = Encoding.UTF8.GetByteCount(newText);
|
||||
if (!isResizable && newTextLenUtf8 + self.CurLenA + 1 > self.BufCapacityA)
|
||||
return false;
|
||||
|
||||
// Grow internal buffer if needed
|
||||
if (newText.Length + textLen + 1 > self.TextW.Size)
|
||||
{
|
||||
if (!isResizable)
|
||||
return false;
|
||||
|
||||
Debug.Assert(textLen < self.TextW.Size, "text_len < self.TextW.Length");
|
||||
self.TextW.Resize(textLen + Math.Clamp(newText.Length * 4, 32, Math.Max(256, newText.Length)) + 1);
|
||||
}
|
||||
|
||||
var text = new Span<char>(self.TextW.Data, self.TextW.Size);
|
||||
if (pos != textLen)
|
||||
text.Slice(pos, textLen - pos).CopyTo(text[(pos + newText.Length)..]);
|
||||
newText.CopyTo(text[pos..]);
|
||||
|
||||
self.Edited = true;
|
||||
self.CurLenW += newText.Length;
|
||||
self.CurLenA += newTextLenUtf8;
|
||||
self.TextW[self.CurLenW] = '\0';
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -18,6 +18,7 @@ using Dalamud.Hooking;
|
|||
using Dalamud.Hooking.Internal;
|
||||
using Dalamud.Hooking.WndProcHook;
|
||||
using Dalamud.Interface.ImGuiBackend;
|
||||
using Dalamud.Interface.ImGuiBackend.Delegates;
|
||||
using Dalamud.Interface.ImGuiNotification;
|
||||
using Dalamud.Interface.ImGuiNotification.Internal;
|
||||
using Dalamud.Interface.Internal.Asserts;
|
||||
|
|
@ -128,7 +129,7 @@ internal partial class InterfaceManager : IInternalDisposableService
|
|||
/// <summary>
|
||||
/// This event gets called each frame to facilitate ImGui drawing.
|
||||
/// </summary>
|
||||
public event IImGuiBackend.BuildUiDelegate? Draw;
|
||||
public event ImGuiBuildUiDelegate? Draw;
|
||||
|
||||
/// <summary>
|
||||
/// This event gets called when ResizeBuffers is called.
|
||||
|
|
@ -634,29 +635,6 @@ internal partial class InterfaceManager : IInternalDisposableService
|
|||
Service<InterfaceManagerWithScene>.ProvideException(ex);
|
||||
Log.Error(ex, "Could not load ImGui dependencies.");
|
||||
|
||||
fixed (void* lpText =
|
||||
"Dalamud plugins require the Microsoft Visual C++ Redistributable to be installed.\nPlease install the runtime from the official Microsoft website or disable Dalamud.\n\nDo you want to download the redistributable now?")
|
||||
{
|
||||
fixed (void* lpCaption = "Dalamud Error")
|
||||
{
|
||||
var res = MessageBoxW(
|
||||
default,
|
||||
(ushort*)lpText,
|
||||
(ushort*)lpCaption,
|
||||
MB.MB_YESNO | MB.MB_TOPMOST | MB.MB_ICONERROR);
|
||||
|
||||
if (res == IDYES)
|
||||
{
|
||||
var psi = new ProcessStartInfo
|
||||
{
|
||||
FileName = "https://aka.ms/vs/16/release/vc_redist.x64.exe",
|
||||
UseShellExecute = true,
|
||||
};
|
||||
Process.Start(psi);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Environment.Exit(-1);
|
||||
|
||||
// Doesn't reach here, but to make the compiler not complain
|
||||
|
|
|
|||
|
|
@ -243,8 +243,6 @@ internal unsafe class UiDebug
|
|||
ImGui.Text($"BGColor: #{textNode->BackgroundColor.R:X2}{textNode->BackgroundColor.G:X2}{textNode->BackgroundColor.B:X2}{textNode->BackgroundColor.A:X2}");
|
||||
|
||||
ImGui.Text($"TextFlags: {textNode->TextFlags}");
|
||||
ImGui.SameLine();
|
||||
ImGui.Text($"TextFlags2: {textNode->TextFlags2}");
|
||||
|
||||
break;
|
||||
case NodeType.Counter:
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
using System.Diagnostics;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
|
||||
|
|
@ -117,9 +118,11 @@ public class AddonLifecycleWidget : IDataWindowWidget
|
|||
{
|
||||
ImGui.Columns(2);
|
||||
|
||||
var functionAddress = receiveEventListener.FunctionAddress;
|
||||
|
||||
ImGui.Text("Hook Address"u8);
|
||||
ImGui.NextColumn();
|
||||
ImGui.Text(receiveEventListener.FunctionAddress.ToString("X"));
|
||||
ImGui.Text($"0x{functionAddress:X} (ffxiv_dx11.exe+{functionAddress - Process.GetCurrentProcess().MainModule!.BaseAddress:X})");
|
||||
|
||||
ImGui.NextColumn();
|
||||
ImGui.Text("Hook Status"u8);
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ internal class UldWidget : IDataWindowWidget
|
|||
{
|
||||
// ULD styles can be hardcoded for now as they don't add new ones regularly. Can later try and find where to load these from in the game EXE.
|
||||
private static readonly string[] ThemeDisplayNames = ["Dark", "Light", "Classic FF", "Clear Blue"];
|
||||
private static readonly string[] ThemeBasePaths = ["ui/uld/", "ui/uld/light/", "ui/uld/third/", "ui/uld/fourth/"];
|
||||
private static readonly string[] ThemeBasePaths = ["ui/uld/", "ui/uld/img01/", "ui/uld/img02/", "ui/uld/img03/"];
|
||||
|
||||
// 48 8D 15 ?? ?? ?? ?? is the part of the signatures that contain the string location offset
|
||||
// 48 = 64 bit register prefix
|
||||
|
|
|
|||
|
|
@ -2076,10 +2076,18 @@ internal class PluginInstallerWindow : Window, IDisposable
|
|||
var isOpen = this.openPluginCollapsibles.Contains(index);
|
||||
|
||||
var sectionSize = ImGuiHelpers.GlobalScale * 66;
|
||||
var tapeCursor = ImGui.GetCursorPos();
|
||||
|
||||
ImGui.Separator();
|
||||
|
||||
var childId = $"plugin_child_{label}_{plugin?.EffectiveWorkingPluginId}_{manifest.InternalName}";
|
||||
const ImGuiWindowFlags childFlags = ImGuiWindowFlags.NoScrollbar | ImGuiWindowFlags.NoScrollWithMouse;
|
||||
|
||||
using var pluginChild = ImRaii.Child(childId, new Vector2(ImGui.GetContentRegionAvail().X, sectionSize), false, childFlags);
|
||||
if (!pluginChild)
|
||||
{
|
||||
return isOpen;
|
||||
}
|
||||
|
||||
var startCursor = ImGui.GetCursorPos();
|
||||
|
||||
if (flags.HasFlag(PluginHeaderFlags.IsTesting))
|
||||
|
|
@ -2115,7 +2123,7 @@ internal class PluginInstallerWindow : Window, IDisposable
|
|||
}
|
||||
}
|
||||
|
||||
DrawCautionTape(tapeCursor + new Vector2(0, 1), new Vector2(ImGui.GetWindowWidth(), sectionSize + ImGui.GetStyle().ItemSpacing.Y), ImGuiHelpers.GlobalScale * 40, 20);
|
||||
DrawCautionTape(startCursor + new Vector2(0, 1), new Vector2(ImGui.GetWindowWidth(), sectionSize + ImGui.GetStyle().ItemSpacing.Y), ImGuiHelpers.GlobalScale * 40, 20);
|
||||
}
|
||||
|
||||
ImGui.PushStyleColor(ImGuiCol.Button, isOpen ? new Vector4(0.5f, 0.5f, 0.5f, 0.1f) : Vector4.Zero);
|
||||
|
|
@ -2124,7 +2132,7 @@ internal class PluginInstallerWindow : Window, IDisposable
|
|||
ImGui.PushStyleColor(ImGuiCol.ButtonActive, new Vector4(0.5f, 0.5f, 0.5f, 0.35f));
|
||||
ImGui.PushStyleVar(ImGuiStyleVar.FrameRounding, 0);
|
||||
|
||||
ImGui.SetCursorPos(tapeCursor);
|
||||
ImGui.SetCursorPos(startCursor);
|
||||
|
||||
if (ImGui.Button($"###plugin{index}CollapsibleBtn", new Vector2(ImGui.GetContentRegionAvail().X, sectionSize + ImGui.GetStyle().ItemSpacing.Y)))
|
||||
{
|
||||
|
|
|
|||
|
|
@ -477,7 +477,7 @@ internal class TitleScreenMenuWindow : Window, IDisposable
|
|||
var textNode = addon->GetTextNodeById(3);
|
||||
|
||||
// look and feel init. should be harmless to set.
|
||||
textNode->TextFlags |= (byte)TextFlags.MultiLine;
|
||||
textNode->TextFlags |= TextFlags.MultiLine;
|
||||
textNode->AlignmentType = AlignmentType.TopLeft;
|
||||
|
||||
var containsDalamudVersionString = textNode->OriginalTextPointer.Value == textNode->NodeText.StringPtr.Value;
|
||||
|
|
|
|||
|
|
@ -122,6 +122,34 @@ public interface IUiBuilder
|
|||
/// </summary>
|
||||
IFontSpec DefaultFontSpec { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the default Dalamud font size in points.
|
||||
/// </summary>
|
||||
public float FontDefaultSizePt { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the default Dalamud font size in pixels.
|
||||
/// </summary>
|
||||
public float FontDefaultSizePx { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the default Dalamud font - supporting all game languages and icons.<br />
|
||||
/// <strong>Accessing this static property outside of <see cref="Draw"/> is dangerous and not supported.</strong>
|
||||
/// </summary>
|
||||
public ImFontPtr FontDefault { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the default Dalamud icon font based on FontAwesome 5 Free solid.<br />
|
||||
/// <strong>Accessing this static property outside of <see cref="Draw"/> is dangerous and not supported.</strong>
|
||||
/// </summary>
|
||||
public ImFontPtr FontIcon { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the default Dalamud monospaced font based on Inconsolata Regular.<br />
|
||||
/// <strong>Accessing this static property outside of <see cref="Draw"/> is dangerous and not supported.</strong>
|
||||
/// </summary>
|
||||
public ImFontPtr FontMono { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the game's active Direct3D device.
|
||||
/// </summary>
|
||||
|
|
@ -380,6 +408,21 @@ public sealed class UiBuilder : IDisposable, IUiBuilder
|
|||
/// </summary>
|
||||
public IFontSpec DefaultFontSpec => Service<FontAtlasFactory>.Get().DefaultFontSpec;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public float FontDefaultSizePt => Service<FontAtlasFactory>.Get().DefaultFontSpec.SizePt;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public float FontDefaultSizePx => Service<FontAtlasFactory>.Get().DefaultFontSpec.SizePx;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ImFontPtr FontDefault => InterfaceManager.DefaultFont;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ImFontPtr FontIcon => InterfaceManager.IconFont;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ImFontPtr FontMono => InterfaceManager.MonoFont;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the handle to the default Dalamud font - supporting all game languages and icons.
|
||||
/// </summary>
|
||||
|
|
@ -541,15 +584,6 @@ public sealed class UiBuilder : IDisposable, IUiBuilder
|
|||
internal static bool DoStats { get; set; } = false;
|
||||
#endif
|
||||
|
||||
private void OnDefaultStyleChanged()
|
||||
=> this.DefaultStyleChanged.InvokeSafely();
|
||||
|
||||
private void OnDefaultGlobalScaleChanged()
|
||||
=> this.DefaultGlobalScaleChanged.InvokeSafely();
|
||||
|
||||
private void OnDefaultFontChanged()
|
||||
=> this.DefaultFontChanged.InvokeSafely();
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether this UiBuilder has a configuration UI registered.
|
||||
/// </summary>
|
||||
|
|
@ -796,6 +830,15 @@ public sealed class UiBuilder : IDisposable, IUiBuilder
|
|||
this.ResizeBuffers?.InvokeSafely();
|
||||
}
|
||||
|
||||
private void OnDefaultStyleChanged()
|
||||
=> this.DefaultStyleChanged.InvokeSafely();
|
||||
|
||||
private void OnDefaultGlobalScaleChanged()
|
||||
=> this.DefaultGlobalScaleChanged.InvokeSafely();
|
||||
|
||||
private void OnDefaultFontChanged()
|
||||
=> this.DefaultFontChanged.InvokeSafely();
|
||||
|
||||
private class FontHandleWrapper : IFontHandle
|
||||
{
|
||||
private IFontHandle? wrapped;
|
||||
|
|
|
|||
|
|
@ -203,8 +203,8 @@ public static partial class ImGuiHelpers
|
|||
ImGui.SetClipboardText(textCopy.IsNull ? text.Span : textCopy.Span);
|
||||
}
|
||||
|
||||
text.Dispose();
|
||||
textCopy.Dispose();
|
||||
text.Recycle();
|
||||
textCopy.Recycle();
|
||||
}
|
||||
|
||||
/// <summary>Draws a SeString.</summary>
|
||||
|
|
|
|||
|
|
@ -2,10 +2,8 @@ using System.Collections.Generic;
|
|||
|
||||
namespace Dalamud.Plugin;
|
||||
|
||||
/// <summary>
|
||||
/// Contains data about changes to the list of active plugins.
|
||||
/// </summary>
|
||||
public class ActivePluginsChangedEventArgs : EventArgs
|
||||
/// <inheritdoc cref="IActivePluginsChangedEventArgs" />
|
||||
public class ActivePluginsChangedEventArgs : EventArgs, IActivePluginsChangedEventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ActivePluginsChangedEventArgs"/> class
|
||||
|
|
@ -19,13 +17,9 @@ public class ActivePluginsChangedEventArgs : EventArgs
|
|||
this.AffectedInternalNames = affectedInternalNames;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the invalidation kind that caused this event to be fired.
|
||||
/// </summary>
|
||||
/// <inheritdoc/>
|
||||
public PluginListInvalidationKind Kind { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the InternalNames of affected plugins.
|
||||
/// </summary>
|
||||
/// <inheritdoc/>
|
||||
public IEnumerable<string> AffectedInternalNames { get; }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -489,7 +489,7 @@ internal sealed class DalamudPluginInterface : IDalamudPluginInterface, IDisposa
|
|||
/// Dispatch the active plugins changed event.
|
||||
/// </summary>
|
||||
/// <param name="args">The event arguments containing information about the change.</param>
|
||||
internal void NotifyActivePluginsChanged(ActivePluginsChangedEventArgs args)
|
||||
internal void NotifyActivePluginsChanged(IActivePluginsChangedEventArgs args)
|
||||
{
|
||||
foreach (var action in Delegate.EnumerateInvocationList(this.ActivePluginsChanged))
|
||||
{
|
||||
|
|
|
|||
19
Dalamud/Plugin/IActivePluginsChangedEventArgs.cs
Normal file
19
Dalamud/Plugin/IActivePluginsChangedEventArgs.cs
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
using System.Collections.Generic;
|
||||
|
||||
namespace Dalamud.Plugin;
|
||||
|
||||
/// <summary>
|
||||
/// Contains data about changes to the list of active plugins.
|
||||
/// </summary>
|
||||
public interface IActivePluginsChangedEventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the invalidation kind that caused this event to be fired.
|
||||
/// </summary>
|
||||
PluginListInvalidationKind Kind { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the InternalNames of affected plugins.
|
||||
/// </summary>
|
||||
IEnumerable<string> AffectedInternalNames { get; }
|
||||
}
|
||||
|
|
@ -33,7 +33,7 @@ public interface IDalamudPluginInterface
|
|||
/// Delegate for events that listen to changes to the list of active plugins.
|
||||
/// </summary>
|
||||
/// <param name="args">The event arguments containing information about the change.</param>
|
||||
public delegate void ActivePluginsChangedDelegate(ActivePluginsChangedEventArgs args);
|
||||
public delegate void ActivePluginsChangedDelegate(IActivePluginsChangedEventArgs args);
|
||||
|
||||
/// <summary>
|
||||
/// Event that gets fired when loc is changed
|
||||
|
|
|
|||
|
|
@ -1240,7 +1240,7 @@ internal class PluginManager : IInternalDisposableService
|
|||
}
|
||||
|
||||
return this.bannedPlugins.Any(ban => (ban.Name == manifest.InternalName || ban.Name == Hash.GetStringSha256Hash(manifest.InternalName))
|
||||
&& ban.AssemblyVersion >= versionToCheck);
|
||||
&& (ban.AssemblyVersion == null || ban.AssemblyVersion >= versionToCheck));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ internal struct BannedPlugin
|
|||
/// Gets plugin assembly version.
|
||||
/// </summary>
|
||||
[JsonProperty]
|
||||
public Version AssemblyVersion { get; private set; }
|
||||
public Version? AssemblyVersion { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets reason for the ban.
|
||||
|
|
|
|||
|
|
@ -83,20 +83,21 @@ public interface IChatGui
|
|||
/// <summary>
|
||||
/// Gets the dictionary of Dalamud Link Handlers.
|
||||
/// </summary>
|
||||
public IReadOnlyDictionary<(string PluginName, Guid CommandId), Action<Guid, SeString>> RegisteredLinkHandlers { get; }
|
||||
public IReadOnlyDictionary<(string PluginName, uint CommandId), Action<uint, SeString>> RegisteredLinkHandlers { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Register a chat link handler.
|
||||
/// </summary>
|
||||
/// <param name="commandId">The ID of the command.</param>
|
||||
/// <param name="commandAction">The action to be executed.</param>
|
||||
/// <returns>Returns an SeString payload for the link.</returns>
|
||||
public DalamudLinkPayload AddChatLinkHandler(Action<Guid, SeString> commandAction);
|
||||
public DalamudLinkPayload AddChatLinkHandler(uint commandId, Action<uint, SeString> commandAction);
|
||||
|
||||
/// <summary>
|
||||
/// Remove a chat link handler.
|
||||
/// </summary>
|
||||
/// <param name="commandId">The ID of the command.</param>
|
||||
public void RemoveChatLinkHandler(Guid commandId);
|
||||
public void RemoveChatLinkHandler(uint commandId);
|
||||
|
||||
/// <summary>
|
||||
/// Removes all chat link handlers registered by the plugin.
|
||||
|
|
|
|||
|
|
@ -38,6 +38,15 @@ public interface ISeStringEvaluator
|
|||
/// <returns>An evaluated <see cref="ReadOnlySeString"/>.</returns>
|
||||
ReadOnlySeString EvaluateMacroString(string macroString, Span<SeStringParameter> localParameters = default, ClientLanguage? language = null);
|
||||
|
||||
/// <summary>
|
||||
/// Evaluates macros in a macro string.
|
||||
/// </summary>
|
||||
/// <param name="macroString">The macro string.</param>
|
||||
/// <param name="localParameters">An optional list of local parameters.</param>
|
||||
/// <param name="language">An optional language override.</param>
|
||||
/// <returns>An evaluated <see cref="ReadOnlySeString"/>.</returns>
|
||||
ReadOnlySeString EvaluateMacroString(ReadOnlySpan<byte> macroString, Span<SeStringParameter> localParameters = default, ClientLanguage? language = null);
|
||||
|
||||
/// <summary>
|
||||
/// Evaluates macros in text from the Addon sheet.
|
||||
/// </summary>
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ internal static class BugBait
|
|||
Reporter = reporter,
|
||||
Name = plugin.InternalName,
|
||||
Version = isTesting ? plugin.TestingAssemblyVersion?.ToString() : plugin.AssemblyVersion.ToString(),
|
||||
Platform = Util.GetHostPlatform().ToString(),
|
||||
DalamudHash = Util.GetScmVersion(),
|
||||
};
|
||||
|
||||
|
|
@ -66,6 +67,9 @@ internal static class BugBait
|
|||
[JsonProperty("version")]
|
||||
public string? Version { get; set; }
|
||||
|
||||
[JsonProperty("platform")]
|
||||
public string? Platform { get; set; }
|
||||
|
||||
[JsonProperty("reporter")]
|
||||
public string? Reporter { get; set; }
|
||||
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ using System.Reflection.Emit;
|
|||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using Dalamud.Bindings.ImGui;
|
||||
|
|
@ -27,6 +28,8 @@ using Windows.Win32.System.Memory;
|
|||
using Windows.Win32.System.Ole;
|
||||
using Windows.Win32.UI.WindowsAndMessaging;
|
||||
|
||||
using Dalamud.Interface.Internal;
|
||||
|
||||
using FLASHWINFO = Windows.Win32.UI.WindowsAndMessaging.FLASHWINFO;
|
||||
using HWND = Windows.Win32.Foundation.HWND;
|
||||
using MEMORY_BASIC_INFORMATION = Windows.Win32.System.Memory.MEMORY_BASIC_INFORMATION;
|
||||
|
|
@ -522,17 +525,36 @@ public static partial class Util
|
|||
public static bool IsWindows11() => Environment.OSVersion.Version.Build >= 22000;
|
||||
|
||||
/// <summary>
|
||||
/// Open a link in the default browser.
|
||||
/// Open a link in the default browser, and attempts to focus the newly launched application.
|
||||
/// </summary>
|
||||
/// <param name="url">The link to open.</param>
|
||||
public static void OpenLink(string url)
|
||||
{
|
||||
var process = new ProcessStartInfo(url)
|
||||
public static void OpenLink(string url) => new Thread(
|
||||
static url =>
|
||||
{
|
||||
UseShellExecute = true,
|
||||
};
|
||||
Process.Start(process);
|
||||
}
|
||||
try
|
||||
{
|
||||
var psi = new ProcessStartInfo((string)url!)
|
||||
{
|
||||
UseShellExecute = true,
|
||||
ErrorDialogParentHandle = Service<InterfaceManager>.GetNullable() is { } im
|
||||
? im.GameWindowHandle
|
||||
: 0,
|
||||
Verb = "open",
|
||||
};
|
||||
if (Process.Start(psi) is not { } process)
|
||||
return;
|
||||
|
||||
if (process.Id != 0)
|
||||
TerraFX.Interop.Windows.Windows.AllowSetForegroundWindow((uint)process.Id);
|
||||
process.WaitForInputIdle();
|
||||
TerraFX.Interop.Windows.Windows.SetForegroundWindow(
|
||||
(TerraFX.Interop.Windows.HWND)process.MainWindowHandle);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error(e, "{fn}: failed to open {url}", nameof(OpenLink), url);
|
||||
}
|
||||
}).Start(url);
|
||||
|
||||
/// <summary>
|
||||
/// Perform a "zipper merge" (A, 1, B, 2, C, 3) of multiple enumerables, allowing for lists to end early.
|
||||
|
|
|
|||
|
|
@ -463,12 +463,14 @@ void open_folder_and_select_items(HWND hwndOpener, const std::wstring& path) {
|
|||
|
||||
void export_tspack(HWND hWndParent, const std::filesystem::path& logDir, const std::string& crashLog, const std::string& troubleshootingPackData) {
|
||||
static const char* SourceLogFiles[] = {
|
||||
"output.log",
|
||||
"output.log", // XIVLauncher for Windows
|
||||
"launcher.log", // XIVLauncher.Core for [mostly] Linux
|
||||
"patcher.log",
|
||||
"dalamud.log",
|
||||
"dalamud.injector.log",
|
||||
"dalamud.boot.log",
|
||||
"aria.log",
|
||||
"wine.log"
|
||||
};
|
||||
static constexpr auto MaxSizePerLog = 1 * 1024 * 1024;
|
||||
static constexpr std::array<COMDLG_FILTERSPEC, 2> OutputFileTypeFilterSpec{{
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
<!-- Dependency versions -->
|
||||
<PropertyGroup Label="Dependency Versions">
|
||||
<LuminaVersion>6.3.0</LuminaVersion>
|
||||
<LuminaVersion>6.5.1</LuminaVersion>
|
||||
<NewtonsoftJsonVersion>13.0.3</NewtonsoftJsonVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ $sourcePaths = (
|
|||
# replace "ImGuiKey.GamepadStart"
|
||||
$tmp = Get-Content -Path "$PSScriptRoot\imgui\Dalamud.Bindings.ImGui\Generated\Enums\ImGuiKeyPrivate.cs" -Raw
|
||||
$tmp = $tmp.Replace("unchecked((int)GamepadStart)", "unchecked((int)ImGuiKey.GamepadStart)").Trim()
|
||||
$tmp | Set-Content -Path "$PSScriptRoot\imgui\Dalamud.Bindings.ImGui\Generated\Enums\ImGuiKeyPrivate.cs" -Encoding ascii
|
||||
$tmp.Trim() | Set-Content -Path "$PSScriptRoot\imgui\Dalamud.Bindings.ImGui\Generated\Enums\ImGuiKeyPrivate.cs" -Encoding ascii
|
||||
|
||||
try
|
||||
{
|
||||
|
|
@ -141,7 +141,9 @@ foreach ($sourcePath in $sourcePaths)
|
|||
$husks = $husks.Replace("public unsafe struct", "public unsafe partial struct")
|
||||
$husks = $referNativeFunctionQualified.Replace($husks, '$1Native.$2')
|
||||
$husks = "// <auto-generated/>`r`n`r`nusing $([string]::Join(";`r`nusing ", $imports) );`r`n`r`n$husks"
|
||||
$husks | Set-Content -Path "$targetPath.gen.cs" -Encoding ascii
|
||||
$husks = $husks -ireplace 'nuint (ActiveIdUsingKeyInputMask)', 'ImBitArrayImGuiKeyNamedKeyCOUNTLessImGuiKeyNamedKeyBEGIN $1'
|
||||
$husks = $husks.Replace('ref Unsafe.AsRef<nuint>(&Handle->ActiveIdUsingKeyInputMask)', 'ref Unsafe.AsRef<ImBitArrayImGuiKeyNamedKeyCOUNTLessImGuiKeyNamedKeyBEGIN>(&Handle->ActiveIdUsingKeyInputMask)')
|
||||
$husks.Trim() | Set-Content -Path "$targetPath.gen.cs" -Encoding ascii
|
||||
}
|
||||
|
||||
$husks = "// <auto-generated/>`r`n`r`nusing $([string]::Join(";`r`nusing ", $imports) );`r`n`r`nnamespace $namespace;`r`n`r`n"
|
||||
|
|
@ -286,6 +288,6 @@ foreach ($sourcePath in $sourcePaths)
|
|||
$null = $sb.Append("// DISCARDED: $methodName`r`n")
|
||||
}
|
||||
|
||||
$sb.ToString() | Set-Content -Path "$targetPath/$className.gen.cs" -Encoding ascii
|
||||
$sb.ToString().Trim() | Set-Content -Path "$targetPath/$className.gen.cs" -Encoding ascii
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8896,4 +8896,3 @@ public unsafe partial class ImGui
|
|||
// DISCARDED: internal static byte VSliderFloatNative(byte* label, Vector2 size, float* v, float vMin, float vMax, byte* format, ImGuiSliderFlags flags)
|
||||
// DISCARDED: internal static byte VSliderIntNative(byte* label, Vector2 size, int* v, int vMin, int vMax, byte* format, ImGuiSliderFlags flags)
|
||||
// DISCARDED: internal static byte VSliderScalarNative(byte* label, Vector2 size, ImGuiDataType dataType, void* pData, void* pMin, void* pMax, byte* format, ImGuiSliderFlags flags)
|
||||
|
||||
|
|
|
|||
|
|
@ -4828,4 +4828,3 @@ public unsafe partial class ImGuiNative
|
|||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -12,4 +12,3 @@ namespace Dalamud.Bindings.ImGui;
|
|||
public unsafe partial struct ImBitArrayImGuiKeyNamedKeyCOUNTLessImGuiKeyNamedKeyBEGIN
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -12,4 +12,3 @@ namespace Dalamud.Bindings.ImGui;
|
|||
public unsafe partial struct ImBitVector
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -12,4 +12,3 @@ namespace Dalamud.Bindings.ImGui;
|
|||
public unsafe partial struct ImBitVectorPtr
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -12,4 +12,3 @@ namespace Dalamud.Bindings.ImGui;
|
|||
public unsafe partial struct ImChunkStreamImGuiTableSettings
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -12,4 +12,3 @@ namespace Dalamud.Bindings.ImGui;
|
|||
public unsafe partial struct ImChunkStreamImGuiWindowSettings
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -47,4 +47,3 @@ public unsafe partial struct ImColor
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -32,4 +32,3 @@ public unsafe partial struct ImColorPtr
|
|||
ImGuiNative.SetHSV(Handle, h, s, v, (float)(1.0f));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -12,4 +12,3 @@ namespace Dalamud.Bindings.ImGui;
|
|||
public unsafe partial struct ImDrawChannel
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -12,4 +12,3 @@ namespace Dalamud.Bindings.ImGui;
|
|||
public unsafe partial struct ImDrawChannelPtr
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -27,4 +27,3 @@ public unsafe partial struct ImDrawCmd
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -12,4 +12,3 @@ namespace Dalamud.Bindings.ImGui;
|
|||
public unsafe partial struct ImDrawCmdHeader
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -21,4 +21,3 @@ public unsafe partial struct ImDrawCmdPtr
|
|||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -40,4 +40,3 @@ public unsafe partial struct ImDrawData
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -12,4 +12,3 @@ namespace Dalamud.Bindings.ImGui;
|
|||
public unsafe partial struct ImDrawDataBuilder
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -12,4 +12,3 @@ namespace Dalamud.Bindings.ImGui;
|
|||
public unsafe partial struct ImDrawDataBuilderPtr
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -28,4 +28,3 @@ public unsafe partial struct ImDrawDataPtr
|
|||
ImGuiNative.ScaleClipRects(Handle, fbScale);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -756,4 +756,3 @@ public unsafe partial struct ImDrawList
|
|||
}
|
||||
}
|
||||
// DISCARDED: AddText
|
||||
|
||||
|
|
|
|||
|
|
@ -441,4 +441,3 @@ public unsafe partial struct ImDrawListPtr
|
|||
}
|
||||
}
|
||||
// DISCARDED: AddText
|
||||
|
||||
|
|
|
|||
|
|
@ -12,4 +12,3 @@ namespace Dalamud.Bindings.ImGui;
|
|||
public unsafe partial struct ImDrawListPtrPtr
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -19,4 +19,3 @@ public unsafe partial struct ImDrawListSharedData
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -16,4 +16,3 @@ public unsafe partial struct ImDrawListSharedDataPtr
|
|||
ImGuiNative.Destroy(Handle);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -84,4 +84,3 @@ public unsafe partial struct ImDrawListSplitter
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -57,4 +57,3 @@ public unsafe partial struct ImDrawListSplitterPtr
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -12,4 +12,3 @@ namespace Dalamud.Bindings.ImGui;
|
|||
public unsafe partial struct ImDrawVert
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -12,4 +12,3 @@ namespace Dalamud.Bindings.ImGui;
|
|||
public unsafe partial struct ImDrawVertPtr
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -174,4 +174,3 @@ public unsafe partial struct ImFont
|
|||
// DISCARDED: GetDebugName
|
||||
// DISCARDED: GetDebugNameS
|
||||
// DISCARDED: RenderText
|
||||
|
||||
|
|
|
|||
|
|
@ -1829,4 +1829,3 @@ public unsafe partial struct ImFontAtlas
|
|||
// DISCARDED: AddFontFromMemoryCompressedBase85TTF
|
||||
// DISCARDED: AddFontFromMemoryCompressedTTF
|
||||
// DISCARDED: AddFontFromMemoryTTF
|
||||
|
||||
|
|
|
|||
|
|
@ -27,4 +27,3 @@ public unsafe partial struct ImFontAtlasCustomRect
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -21,4 +21,3 @@ public unsafe partial struct ImFontAtlasCustomRectPtr
|
|||
return ret != 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1409,4 +1409,3 @@ public unsafe partial struct ImFontAtlasPtr
|
|||
// DISCARDED: AddFontFromMemoryCompressedBase85TTF
|
||||
// DISCARDED: AddFontFromMemoryCompressedTTF
|
||||
// DISCARDED: AddFontFromMemoryTTF
|
||||
|
||||
|
|
|
|||
|
|
@ -12,4 +12,3 @@ namespace Dalamud.Bindings.ImGui;
|
|||
public unsafe partial struct ImFontAtlasTexture
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -12,4 +12,3 @@ namespace Dalamud.Bindings.ImGui;
|
|||
public unsafe partial struct ImFontAtlasTexturePtr
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -12,4 +12,3 @@ namespace Dalamud.Bindings.ImGui;
|
|||
public unsafe partial struct ImFontBuilderIO
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -12,4 +12,3 @@ namespace Dalamud.Bindings.ImGui;
|
|||
public unsafe partial struct ImFontBuilderIOPtr
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -19,4 +19,3 @@ public unsafe partial struct ImFontConfig
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -16,4 +16,3 @@ public unsafe partial struct ImFontConfigPtr
|
|||
ImGuiNative.Destroy(Handle);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue