mirror of
https://github.com/goatcorp/Dalamud.git
synced 2025-12-11 01:37:24 +01:00
Magic the magic happen
This commit is contained in:
parent
84769ae5b7
commit
658eedca37
188 changed files with 10329 additions and 3549 deletions
|
|
@ -24,6 +24,7 @@ csharp_preferred_modifier_order = public, private, protected, internal, new, abs
|
|||
csharp_style_var_elsewhere = true:suggestion
|
||||
csharp_style_var_for_built_in_types = true:suggestion
|
||||
csharp_style_var_when_type_is_apparent = true:suggestion
|
||||
dotnet_code_quality_unused_parameters = non_public
|
||||
dotnet_naming_rule.event_rule.severity = warning
|
||||
dotnet_naming_rule.event_rule.style = on_upper_camel_case_style
|
||||
dotnet_naming_rule.event_rule.symbols = event_symbols
|
||||
|
|
@ -56,11 +57,13 @@ dotnet_naming_symbols.private_static_fields_symbols.required_modifiers = static
|
|||
dotnet_naming_symbols.private_static_readonly_symbols.applicable_accessibilities = private
|
||||
dotnet_naming_symbols.private_static_readonly_symbols.applicable_kinds = field
|
||||
dotnet_naming_symbols.private_static_readonly_symbols.required_modifiers = static,readonly
|
||||
dotnet_style_parentheses_in_arithmetic_binary_operators = never_if_unnecessary:suggestion
|
||||
dotnet_style_parentheses_in_other_binary_operators = never_if_unnecessary:suggestion
|
||||
dotnet_style_parentheses_in_relational_binary_operators = never_if_unnecessary:suggestion
|
||||
dotnet_style_parentheses_in_arithmetic_binary_operators =always_for_clarity:suggestion
|
||||
dotnet_style_parentheses_in_other_binary_operators =always_for_clarity:suggestion
|
||||
dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:suggestion
|
||||
dotnet_style_predefined_type_for_member_access = true:suggestion
|
||||
dotnet_style_require_accessibility_modifiers = for_non_interface_members:suggestion
|
||||
dotnet_style_parentheses_in_other_operators=always_for_clarity:silent
|
||||
dotnet_style_object_initializer = false
|
||||
|
||||
# ReSharper properties
|
||||
resharper_align_linq_query = true
|
||||
|
|
@ -105,8 +108,10 @@ resharper_redundant_base_qualifier_highlighting = none
|
|||
resharper_suggest_var_or_type_built_in_types_highlighting = hint
|
||||
resharper_suggest_var_or_type_elsewhere_highlighting = hint
|
||||
resharper_suggest_var_or_type_simple_types_highlighting = hint
|
||||
csharp_style_deconstructed_variable_declaration=true:silent
|
||||
|
||||
[*.{appxmanifest,asax,ascx,aspx,axaml,axml,build,c,c++,cc,cginc,compute,config,cp,cpp,cs,cshtml,csproj,css,cu,cuh,cxx,dbml,discomap,dtd,h,hh,hlsl,hlsli,hlslinc,hpp,htm,html,hxx,inc,inl,ino,ipp,js,json,jsproj,jsx,lsproj,master,mpp,mq4,mq5,mqh,njsproj,nuspec,paml,proj,props,proto,razor,resjson,resw,resx,skin,StyleCop,targets,tasks,tpp,ts,tsx,usf,ush,vb,vbproj,xaml,xamlx,xml,xoml,xsd}]
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
tab_width = 4
|
||||
dotnet_style_parentheses_in_other_operators=always_for_clarity:silent
|
||||
|
|
|
|||
2
.github/workflows/delete-artifacts.yml
vendored
2
.github/workflows/delete-artifacts.yml
vendored
|
|
@ -12,7 +12,7 @@ jobs:
|
|||
|
||||
steps:
|
||||
- name: Remove old artifacts
|
||||
uses: c-hive/gha-remove-artifacts@24dc23384a1fa6a058b79c73727ae0cb2200ca4c
|
||||
uses: c-hive/gha-remove-artifacts@v1.2.0
|
||||
with:
|
||||
age: '1 month'
|
||||
skip-tags: true
|
||||
|
|
|
|||
26
.github/workflows/main.yml
vendored
26
.github/workflows/main.yml
vendored
|
|
@ -7,15 +7,12 @@ jobs:
|
|||
name: Build on Windows
|
||||
runs-on: windows-2019
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Checkout Dalamud
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
submodules: recursive
|
||||
- name: Setup Nuget
|
||||
uses: nuget/setup-nuget@v1
|
||||
with:
|
||||
nuget-version: latest
|
||||
- name: Restore Nuget Packages
|
||||
run: nuget restore Dalamud.sln
|
||||
- name: Setup MSBuild
|
||||
uses: microsoft/setup-msbuild@v1.0.2
|
||||
- name: Define VERSION
|
||||
run: |
|
||||
$env:COMMIT = $env:GITHUB_SHA.Substring(0, 7)
|
||||
|
|
@ -25,18 +22,17 @@ jobs:
|
|||
($env:REPO_NAME) >> VERSION
|
||||
($env:BRANCH) >> VERSION
|
||||
($env:COMMIT) >> VERSION
|
||||
- name: Build DotNet4
|
||||
run: |
|
||||
cd "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Current\Bin\"
|
||||
.\MSBuild.exe $Env:GITHUB_WORKSPACE\Dalamud.sln /t:Build /p:Configuration=Release /p:DefineConstants=XL_NOAUTOUPDATE
|
||||
- name: Run xUnit Tests
|
||||
run: |
|
||||
${{github.workspace}}\packages\xunit.runner.console.2.4.1\tools\net472\xunit.console.exe ${{github.workspace}}\Dalamud.Test\bin\Release\Dalamud.Test.dll
|
||||
- name: Build Dalamud
|
||||
run: .\build.ps1 compile
|
||||
- name: Test Dalamud
|
||||
run: .\build.ps1 test
|
||||
- name: Create hashlist
|
||||
run: .\CreateHashList.ps1 .\bin\Release
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: dalamud-artifact
|
||||
path: bin\
|
||||
path: bin\Release
|
||||
|
||||
deploy_stg:
|
||||
name: Deploy dalamud-distrib staging
|
||||
|
|
|
|||
3
.gitmodules
vendored
3
.gitmodules
vendored
|
|
@ -4,3 +4,6 @@
|
|||
[submodule "lib/FFXIVClientStructs"]
|
||||
path = lib/FFXIVClientStructs
|
||||
url = https://github.com/goatcorp/FFXIVClientStructs.git
|
||||
[submodule "lib/SharpDX.Desktop"]
|
||||
path = lib/SharpDX.Desktop
|
||||
url = https://github.com/goatcorp/SharpDX.Desktop.git
|
||||
|
|
|
|||
112
.nuke/build.schema.json
Normal file
112
.nuke/build.schema.json
Normal file
|
|
@ -0,0 +1,112 @@
|
|||
{
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
"title": "Build Schema",
|
||||
"$ref": "#/definitions/build",
|
||||
"definitions": {
|
||||
"build": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"Configuration": {
|
||||
"type": "string",
|
||||
"description": "Configuration to build - Default is 'Debug' (local) or 'Release' (server)",
|
||||
"enum": [
|
||||
"Debug",
|
||||
"Release"
|
||||
]
|
||||
},
|
||||
"Continue": {
|
||||
"type": "boolean",
|
||||
"description": "Indicates to continue a previously failed build attempt"
|
||||
},
|
||||
"Help": {
|
||||
"type": "boolean",
|
||||
"description": "Shows the help text for this build assembly"
|
||||
},
|
||||
"Host": {
|
||||
"type": "string",
|
||||
"description": "Host for execution. Default is 'automatic'",
|
||||
"enum": [
|
||||
"AppVeyor",
|
||||
"AzurePipelines",
|
||||
"Bamboo",
|
||||
"Bitrise",
|
||||
"GitHubActions",
|
||||
"GitLab",
|
||||
"Jenkins",
|
||||
"SpaceAutomation",
|
||||
"TeamCity",
|
||||
"Terminal",
|
||||
"TravisCI"
|
||||
]
|
||||
},
|
||||
"NoLogo": {
|
||||
"type": "boolean",
|
||||
"description": "Disables displaying the NUKE logo"
|
||||
},
|
||||
"Plan": {
|
||||
"type": "boolean",
|
||||
"description": "Shows the execution plan (HTML)"
|
||||
},
|
||||
"Profile": {
|
||||
"type": "array",
|
||||
"description": "Defines the profiles to load",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"Root": {
|
||||
"type": "string",
|
||||
"description": "Root directory during build execution"
|
||||
},
|
||||
"Skip": {
|
||||
"type": "array",
|
||||
"description": "List of targets to be skipped. Empty list skips all dependencies",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Clean",
|
||||
"Compile",
|
||||
"CompileDalamud",
|
||||
"CompileDalamudBoot",
|
||||
"CompileInjector",
|
||||
"CompileInjectorBoot",
|
||||
"Restore",
|
||||
"Test"
|
||||
]
|
||||
}
|
||||
},
|
||||
"Solution": {
|
||||
"type": "string",
|
||||
"description": "Path to a solution file that is automatically loaded"
|
||||
},
|
||||
"Target": {
|
||||
"type": "array",
|
||||
"description": "List of targets to be invoked. Default is '{default_target}'",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Clean",
|
||||
"Compile",
|
||||
"CompileDalamud",
|
||||
"CompileDalamudBoot",
|
||||
"CompileInjector",
|
||||
"CompileInjectorBoot",
|
||||
"Restore",
|
||||
"Test"
|
||||
]
|
||||
}
|
||||
},
|
||||
"Verbosity": {
|
||||
"type": "string",
|
||||
"description": "Logging verbosity during build execution. Default is 'Normal'",
|
||||
"enum": [
|
||||
"Minimal",
|
||||
"Normal",
|
||||
"Quiet",
|
||||
"Verbose"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
4
.nuke/parameters.json
Normal file
4
.nuke/parameters.json
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"$schema": "./build.schema.json",
|
||||
"Solution": "Dalamud.sln"
|
||||
}
|
||||
|
|
@ -1,7 +1,11 @@
|
|||
$hashes = @{}
|
||||
$hashes = [ordered]@{}
|
||||
|
||||
Get-ChildItem $args[0] -Exclude dalamud.txt,*.zip,*.pdb,*.ipdb | Foreach-Object {
|
||||
$hashes.Add($_.Name, (Get-FileHash $_.FullName -Algorithm MD5).Hash)
|
||||
Set-Location $args[0]
|
||||
|
||||
Get-ChildItem -File -Recurse -Exclude dalamud.txt,*.zip,*.pdb,*.ipdb | Foreach-Object {
|
||||
$key = ($_.FullName | Resolve-Path -Relative).TrimStart(".\\")
|
||||
$val = (Get-FileHash $_.FullName -Algorithm MD5).Hash
|
||||
$hashes.Add($key, $val)
|
||||
}
|
||||
|
||||
ConvertTo-Json $hashes | Out-File -FilePath (Join-Path $args[0] "hashes.json")
|
||||
$hashes | ConvertTo-Json | Out-File -FilePath "hashes.json"
|
||||
105
Dalamud.Boot/Dalamud.Boot.vcxproj
Normal file
105
Dalamud.Boot/Dalamud.Boot.vcxproj
Normal file
|
|
@ -0,0 +1,105 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{55198DC3-A03D-408E-A8EB-2077780C8576}</ProjectGuid>
|
||||
<RootNamespace>Dalamud_Boot</RootNamespace>
|
||||
<Configuration Condition=" '$(Configuration)'=='' ">Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</PropertyGroup>
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<VCProjectVersion>16.0</VCProjectVersion>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
<OutDir>..\bin\$(Configuration)\</OutDir>
|
||||
<IntDir>obj\$(Configuration)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ItemDefinitionGroup>
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<LanguageStandard>stdcpplatest</LanguageStandard>
|
||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
<PreprocessorDefinitions>CPPDLLTEMPLATE_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableUAC>false</EnableUAC>
|
||||
<AdditionalLibraryDirectories>..\lib\CoreCLR;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)'=='Debug'">
|
||||
<ClCompile>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>false</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<EnableCOMDATFolding>false</EnableCOMDATFolding>
|
||||
<OptimizeReferences>false</OptimizeReferences>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)'=='Release'">
|
||||
<ClCompile>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ItemGroup>
|
||||
<Content Include="..\lib\CoreCLR\nethost\nethost.dll">
|
||||
<Link>nethost.dll</Link>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\lib\CoreCLR\boot.cpp" />
|
||||
<ClCompile Include="..\lib\CoreCLR\CoreCLR.cpp" />
|
||||
<ClCompile Include="..\lib\CoreCLR\pch.cpp" />
|
||||
<ClCompile Include="dllmain.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\lib\CoreCLR\boot.h" />
|
||||
<ClInclude Include="..\lib\CoreCLR\CoreCLR.h" />
|
||||
<ClInclude Include="..\lib\CoreCLR\core\coreclr_delegates.h" />
|
||||
<ClInclude Include="..\lib\CoreCLR\core\hostfxr.h" />
|
||||
<ClInclude Include="..\lib\CoreCLR\framework.h" />
|
||||
<ClInclude Include="..\lib\CoreCLR\nethost\nethost.h" />
|
||||
<ClInclude Include="..\lib\CoreCLR\pch.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Library Include="..\lib\CoreCLR\nethost\libnethost.lib" />
|
||||
<Library Include="..\lib\CoreCLR\nethost\nethost.lib" />
|
||||
</ItemGroup>
|
||||
<Target Name="RemoveExtraFiles" AfterTargets="PostBuildEvent">
|
||||
<Delete Files="$(OutDir)$(TargetName).lib" />
|
||||
<Delete Files="$(OutDir)$(TargetName).exp" />
|
||||
</Target>
|
||||
</Project>
|
||||
62
Dalamud.Boot/Dalamud.Boot.vcxproj.filters
Normal file
62
Dalamud.Boot/Dalamud.Boot.vcxproj.filters
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Library Files">
|
||||
<UniqueIdentifier>{18be40ac-9367-46ff-b848-4c528aa97a8d}</UniqueIdentifier>
|
||||
<Extensions>lib</Extensions>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="dllmain.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\lib\CoreCLR\pch.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\lib\CoreCLR\boot.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\lib\CoreCLR\CoreCLR.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\lib\CoreCLR\core\coreclr_delegates.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\lib\CoreCLR\core\hostfxr.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\lib\CoreCLR\nethost\nethost.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\lib\CoreCLR\CoreCLR.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\lib\CoreCLR\framework.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\lib\CoreCLR\pch.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\lib\CoreCLR\boot.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Library Include="..\lib\CoreCLR\nethost\nethost.lib">
|
||||
<Filter>Library Files</Filter>
|
||||
</Library>
|
||||
<Library Include="..\lib\CoreCLR\nethost\libnethost.lib">
|
||||
<Filter>Library Files</Filter>
|
||||
</Library>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
66
Dalamud.Boot/dllmain.cpp
Normal file
66
Dalamud.Boot/dllmain.cpp
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
#define WIN32_LEAN_AND_MEAN
|
||||
#define DllExport extern "C" __declspec(dllexport)
|
||||
|
||||
#include <filesystem>
|
||||
#include <Windows.h>
|
||||
#include "..\lib\CoreCLR\CoreCLR.h"
|
||||
#include "..\lib\CoreCLR\boot.h"
|
||||
|
||||
HMODULE g_hModule;
|
||||
|
||||
DllExport DWORD WINAPI Initialize(LPVOID lpParam)
|
||||
{
|
||||
#if defined(_DEBUG)
|
||||
ConsoleSetup(L"Dalamud Boot");
|
||||
#endif
|
||||
|
||||
wchar_t _module_path[MAX_PATH];
|
||||
GetModuleFileNameW(g_hModule, _module_path, sizeof _module_path / 2);
|
||||
std::filesystem::path fs_module_path(_module_path);
|
||||
|
||||
std::wstring runtimeconfig_path = _wcsdup(fs_module_path.replace_filename(L"Dalamud.runtimeconfig.json").c_str());
|
||||
std::wstring module_path = _wcsdup(fs_module_path.replace_filename(L"Dalamud.dll").c_str());
|
||||
|
||||
// =========================================================================== //
|
||||
|
||||
void* entrypoint_vfn;
|
||||
int result = InitializeClrAndGetEntryPoint(
|
||||
runtimeconfig_path,
|
||||
module_path,
|
||||
L"Dalamud.EntryPoint, Dalamud",
|
||||
L"Initialize",
|
||||
L"Dalamud.EntryPoint+InitDelegate, Dalamud",
|
||||
&entrypoint_vfn);
|
||||
|
||||
if (result != 0)
|
||||
return result;
|
||||
|
||||
typedef void (CORECLR_DELEGATE_CALLTYPE* custom_component_entry_point_fn)(LPVOID);
|
||||
custom_component_entry_point_fn entrypoint_fn = reinterpret_cast<custom_component_entry_point_fn>(entrypoint_vfn);
|
||||
|
||||
printf("Initializing Dalamud... ");
|
||||
entrypoint_fn(lpParam);
|
||||
printf("Done!\n");
|
||||
|
||||
// =========================================================================== //
|
||||
|
||||
#if defined(_DEBUG)
|
||||
FreeConsole();
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
BOOL APIENTRY DllMain(const HMODULE hModule, const DWORD dwReason, LPVOID lpReserved) {
|
||||
DisableThreadLibraryCalls(hModule);
|
||||
|
||||
switch (dwReason)
|
||||
{
|
||||
case DLL_PROCESS_ATTACH:
|
||||
g_hModule = hModule;
|
||||
break;
|
||||
case DLL_PROCESS_DETACH:
|
||||
break;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
49
Dalamud.Boot/main.cpp
Normal file
49
Dalamud.Boot/main.cpp
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
#define WIN32_LEAN_AND_MEAN
|
||||
|
||||
#include <filesystem>
|
||||
#include <Windows.h>
|
||||
#include "CoreCLR.h"
|
||||
#include "boot.h"
|
||||
|
||||
int wmain(int argc, char** argv)
|
||||
{
|
||||
#if defined(_DEBUG)
|
||||
ConsoleSetup(L"Dalamud Injector Boot");
|
||||
#endif
|
||||
|
||||
wchar_t _module_path[MAX_PATH];
|
||||
GetModuleFileNameW(NULL, _module_path, sizeof _module_path / 2);
|
||||
std::filesystem::path fs_module_path(_module_path);
|
||||
|
||||
std::wstring runtimeconfig_path = _wcsdup(fs_module_path.replace_filename(L"Dalamud.Injector.runtimeconfig.json").c_str());
|
||||
std::wstring module_path = _wcsdup(fs_module_path.replace_filename(L"Dalamud.Injector.dll").c_str());
|
||||
|
||||
// =========================================================================== //
|
||||
|
||||
void* entrypoint_vfn;
|
||||
int result = InitializeClrAndGetEntryPoint(
|
||||
runtimeconfig_path,
|
||||
module_path,
|
||||
L"Dalamud.Injector.EntryPoint, Dalamud.Injector",
|
||||
L"Main",
|
||||
L"Dalamud.Injector.EntryPoint+MainDelegate, Dalamud.Injector",
|
||||
&entrypoint_vfn);
|
||||
|
||||
if (result != 0)
|
||||
return result;
|
||||
|
||||
typedef void (CORECLR_DELEGATE_CALLTYPE* custom_component_entry_point_fn)(int, char**);
|
||||
custom_component_entry_point_fn entrypoint_fn = reinterpret_cast<custom_component_entry_point_fn>(entrypoint_vfn);
|
||||
|
||||
printf("Running Dalamud Injector... ");
|
||||
entrypoint_fn(argc, argv);
|
||||
printf("Done!\n");
|
||||
|
||||
// =========================================================================== //
|
||||
|
||||
#if defined(_DEBUG)
|
||||
FreeConsole();
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
61
Dalamud.CorePlugin/Dalamud.CorePlugin.csproj
Normal file
61
Dalamud.CorePlugin/Dalamud.CorePlugin.csproj
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<AssemblyName>Dalamud.CorePlugin</AssemblyName>
|
||||
<TargetFramework>net5.0-windows</TargetFramework>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<Platforms>x64;AnyCPU</Platforms>
|
||||
<LangVersion>9.0</LangVersion>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
|
||||
<ProduceReferenceAssembly>false</ProduceReferenceAssembly>
|
||||
<NoWarn>IDE0003</NoWarn>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>$(appData)\XIVLauncher\devPlugins\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>$(appData)\XIVLauncher\devPlugins\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<AdditionalFiles Include="..\stylecop.json" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Lumina" Version="3.3.0" />
|
||||
<PackageReference Include="Lumina.Excel" Version="5.50.0" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
||||
<PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.333">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Dalamud\Dalamud.csproj">
|
||||
<Private>false</Private>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\lib\ImGuiScene\deps\ImGui.NET\src\ImGui.NET-472\ImGui.NET-472.csproj">
|
||||
<Private>false</Private>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\lib\ImGuiScene\ImGuiScene\ImGuiScene.csproj">
|
||||
<Private>false</Private>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\lib\ImGuiScene\deps\SDL2-CS\SDL2-CS.csproj">
|
||||
<Private>false</Private>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
16
Dalamud.CorePlugin/GlobalSuppressions.cs
Normal file
16
Dalamud.CorePlugin/GlobalSuppressions.cs
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
// This file is used by Code Analysis to maintain SuppressMessage
|
||||
// attributes that are applied to this project.
|
||||
// Project-level suppressions either have no target or are given
|
||||
// a specific target and scoped to a namespace, type, member, etc.
|
||||
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
// General
|
||||
[assembly: SuppressMessage("StyleCop.CSharp.ReadabilityRules", "SA1118:Parameter should not span multiple lines", Justification = "Preventing long lines", Scope = "namespaceanddescendants", Target = "~N:Dalamud.CorePlugin")]
|
||||
[assembly: SuppressMessage("StyleCop.CSharp.ReadabilityRules", "SA1124:Do not use regions", Justification = "I like regions", Scope = "namespaceanddescendants", Target = "~N:Dalamud.CorePlugin")]
|
||||
[assembly: SuppressMessage("StyleCop.CSharp.ReadabilityRules", "SA1123:Do not place regions within elements", Justification = "I like regions in elements too", Scope = "namespaceanddescendants", Target = "~N:Dalamud.CorePlugin")]
|
||||
[assembly: SuppressMessage("StyleCop.CSharp.LayoutRules", "SA1503:Braces should not be omitted", Justification = "This is annoying", Scope = "namespaceanddescendants", Target = "~N:Dalamud.CorePlugin")]
|
||||
[assembly: SuppressMessage("StyleCop.CSharp.LayoutRules", "SA1512:Single-line comments should not be followed by blank line", Justification = "I like this better", Scope = "namespaceanddescendants", Target = "~N:Dalamud.CorePlugin")]
|
||||
[assembly: SuppressMessage("StyleCop.CSharp.LayoutRules", "SA1515:Single-line comment should be preceded by blank line", Justification = "I like this better", Scope = "namespaceanddescendants", Target = "~N:Dalamud.CorePlugin")]
|
||||
[assembly: SuppressMessage("StyleCop.CSharp.ReadabilityRules", "SA1127:Generic type constraints should be on their own line", Justification = "I like this better", Scope = "namespaceanddescendants", Target = "~N:Dalamud.CorePlugin")]
|
||||
[assembly: SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1633:File should have header", Justification = "We don't do those yet")]
|
||||
96
Dalamud.CorePlugin/PluginImpl.cs
Normal file
96
Dalamud.CorePlugin/PluginImpl.cs
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
|
||||
using Dalamud.Interface.Windowing;
|
||||
using Dalamud.Plugin;
|
||||
|
||||
namespace Dalamud.CorePlugin
|
||||
{
|
||||
/// <summary>
|
||||
/// This class is a a plugin testbed for developing new Dalamud features with easy access to Dalamud itself.
|
||||
/// Be careful to not commit anything extra.
|
||||
/// </summary>
|
||||
public sealed class PluginImpl : IDalamudPlugin
|
||||
{
|
||||
private readonly WindowSystem windowSystem = new("Dalamud.CorePlugin");
|
||||
private Localization localizationManager;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public string Name => "Dalamud.CorePlugin";
|
||||
|
||||
/// <summary>
|
||||
/// Gets the plugin interface.
|
||||
/// </summary>
|
||||
internal DalamudPluginInterface Interface { get; private set; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Initialize(DalamudPluginInterface pluginInterface)
|
||||
{
|
||||
try
|
||||
{
|
||||
this.InitLoc();
|
||||
|
||||
this.Interface = pluginInterface;
|
||||
|
||||
// this.windowSystem.AddWindow(your_window);
|
||||
|
||||
this.Interface.UiBuilder.OnBuildUi += this.OnDraw;
|
||||
this.Interface.UiBuilder.OnOpenConfigUi += this.OnOpenConfigUi;
|
||||
|
||||
this.Interface.CommandManager.AddHandler("/di", new(this.OnCommand) { HelpMessage = $"Access the {this.Name} plugin." });
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
PluginLog.Error(ex, "kaboom");
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Dispose()
|
||||
{
|
||||
this.Interface.CommandManager.RemoveHandler("/di");
|
||||
|
||||
this.Interface.UiBuilder.OnBuildUi -= this.OnDraw;
|
||||
|
||||
this.windowSystem.RemoveAllWindows();
|
||||
|
||||
this.Interface.Dispose();
|
||||
}
|
||||
|
||||
private void InitLoc()
|
||||
{
|
||||
// CheapLoc needs to be reinitialized here because it tracks the setup by assembly name. New assembly, new setup.
|
||||
this.localizationManager = new Localization(Path.Combine(Dalamud.Instance.AssetDirectory.FullName, "UIRes", "loc", "dalamud"), "dalamud_");
|
||||
if (!string.IsNullOrEmpty(Dalamud.Instance.Configuration.LanguageOverride))
|
||||
{
|
||||
this.localizationManager.SetupWithLangCode(Dalamud.Instance.Configuration.LanguageOverride);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.localizationManager.SetupWithUiCulture();
|
||||
}
|
||||
}
|
||||
|
||||
private void OnDraw()
|
||||
{
|
||||
try
|
||||
{
|
||||
this.windowSystem.Draw();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
PluginLog.Error(ex, "Boom");
|
||||
}
|
||||
}
|
||||
|
||||
private void OnCommand(string command, string args)
|
||||
{
|
||||
// this.window.IsOpen = true;
|
||||
}
|
||||
|
||||
private void OnOpenConfigUi(object sender, EventArgs e)
|
||||
{
|
||||
// this.window.IsOpen = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
58
Dalamud.CorePlugin/PluginWindow.cs
Normal file
58
Dalamud.CorePlugin/PluginWindow.cs
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using Dalamud.Interface;
|
||||
using Dalamud.Interface.Colors;
|
||||
using Dalamud.Interface.Components;
|
||||
using Dalamud.Interface.Windowing;
|
||||
using Dalamud.Plugin.Internal;
|
||||
using Dalamud.Plugin.Internal.Exceptions;
|
||||
using Dalamud.Plugin.Internal.Types;
|
||||
using ImGuiNET;
|
||||
|
||||
namespace Dalamud.CorePlugin
|
||||
{
|
||||
/// <summary>
|
||||
/// Class responsible for drawing the plugin installer.
|
||||
/// </summary>
|
||||
internal class PluginWindow : Window, IDisposable
|
||||
{
|
||||
private static readonly ModuleLog Log = new("CorePlugin");
|
||||
|
||||
private readonly Dalamud dalamud;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="PluginWindow"/> class.
|
||||
/// </summary>
|
||||
/// <param name="dalamud">The Dalamud instance.</param>
|
||||
public PluginWindow(Dalamud dalamud)
|
||||
: base("CorePlugin", ImGuiWindowFlags.NoCollapse | ImGuiWindowFlags.NoResize | ImGuiWindowFlags.NoScrollbar)
|
||||
{
|
||||
this.dalamud = dalamud;
|
||||
this.IsOpen = true;
|
||||
|
||||
this.Size = new Vector2(810, 520);
|
||||
this.SizeCondition = ImGuiCond.Always;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Dispose()
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void OnOpen()
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void Draw()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
113
Dalamud.Injector.Boot/Dalamud.Injector.Boot.vcxproj
Normal file
113
Dalamud.Injector.Boot/Dalamud.Injector.Boot.vcxproj
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{8874326B-E755-4D13-90B4-59AB263A3E6B}</ProjectGuid>
|
||||
<RootNamespace>Dalamud_Injector_Boot</RootNamespace>
|
||||
<Configuration Condition=" '$(Configuration)'=='' ">Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</PropertyGroup>
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<VCProjectVersion>16.0</VCProjectVersion>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
|
||||
<TargetName>Dalamud.Injector</TargetName>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
<OutDir>..\bin\$(Configuration)\</OutDir>
|
||||
<IntDir>obj\$(Configuration)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ItemDefinitionGroup>
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<LanguageStandard>stdcpplatest</LanguageStandard>
|
||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
<PreprocessorDefinitions>CPPDLLTEMPLATE_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableUAC>false</EnableUAC>
|
||||
<AdditionalLibraryDirectories>..\lib\CoreCLR;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<ProgramDatabaseFile>$(OutDir)$(TargetName).Boot.pdb</ProgramDatabaseFile>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)'=='Debug'">
|
||||
<ClCompile>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>false</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<EnableCOMDATFolding>false</EnableCOMDATFolding>
|
||||
<OptimizeReferences>false</OptimizeReferences>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)'=='Release'">
|
||||
<ClCompile>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ItemGroup>
|
||||
<Content Include="..\lib\CoreCLR\nethost\nethost.dll">
|
||||
<Link>nethost.dll</Link>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Image Include="dalamud.ico" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="resources.rc" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\lib\CoreCLR\boot.cpp" />
|
||||
<ClCompile Include="..\lib\CoreCLR\CoreCLR.cpp" />
|
||||
<ClCompile Include="..\lib\CoreCLR\pch.cpp" />
|
||||
<ClCompile Include="main.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\lib\CoreCLR\boot.h" />
|
||||
<ClInclude Include="..\lib\CoreCLR\CoreCLR.h" />
|
||||
<ClInclude Include="..\lib\CoreCLR\core\coreclr_delegates.h" />
|
||||
<ClInclude Include="..\lib\CoreCLR\core\hostfxr.h" />
|
||||
<ClInclude Include="..\lib\CoreCLR\framework.h" />
|
||||
<ClInclude Include="..\lib\CoreCLR\nethost\nethost.h" />
|
||||
<ClInclude Include="..\lib\CoreCLR\pch.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Library Include="..\lib\CoreCLR\nethost\libnethost.lib" />
|
||||
<Library Include="..\lib\CoreCLR\nethost\nethost.lib" />
|
||||
</ItemGroup>
|
||||
<Target Name="RemoveExtraFiles" AfterTargets="PostBuildEvent">
|
||||
<Delete Files="$(OutDir)$(TargetName).lib" />
|
||||
<Delete Files="$(OutDir)$(TargetName).exp" />
|
||||
</Target>
|
||||
</Project>
|
||||
75
Dalamud.Injector.Boot/Dalamud.Injector.Boot.vcxproj.filters
Normal file
75
Dalamud.Injector.Boot/Dalamud.Injector.Boot.vcxproj.filters
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Resource Files">
|
||||
<UniqueIdentifier>{4faac519-3a73-4b2b-96e7-fb597f02c0be}</UniqueIdentifier>
|
||||
<Extensions>ico;rc</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Library Files">
|
||||
<UniqueIdentifier>{6aff1bed-6979-4bc9-94e8-ddafb626e6bf}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Image Include="dalamud.ico">
|
||||
<Filter>Resource Files</Filter>
|
||||
</Image>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="resources.rc">
|
||||
<Filter>Resource Files</Filter>
|
||||
</ResourceCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="main.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\lib\CoreCLR\pch.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\lib\CoreCLR\boot.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\lib\CoreCLR\CoreCLR.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\lib\CoreCLR\framework.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\lib\CoreCLR\pch.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\lib\CoreCLR\boot.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\lib\CoreCLR\CoreCLR.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\lib\CoreCLR\nethost\nethost.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\lib\CoreCLR\core\hostfxr.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\lib\CoreCLR\core\coreclr_delegates.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Library Include="..\lib\CoreCLR\nethost\nethost.lib">
|
||||
<Filter>Library Files</Filter>
|
||||
</Library>
|
||||
<Library Include="..\lib\CoreCLR\nethost\libnethost.lib">
|
||||
<Filter>Library Files</Filter>
|
||||
</Library>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 52 KiB After Width: | Height: | Size: 52 KiB |
49
Dalamud.Injector.Boot/main.cpp
Normal file
49
Dalamud.Injector.Boot/main.cpp
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
#define WIN32_LEAN_AND_MEAN
|
||||
|
||||
#include <filesystem>
|
||||
#include <Windows.h>
|
||||
#include "..\lib\CoreCLR\CoreCLR.h"
|
||||
#include "..\lib\CoreCLR\boot.h"
|
||||
|
||||
int wmain(int argc, char** argv)
|
||||
{
|
||||
#if defined(_DEBUG)
|
||||
ConsoleSetup(L"Dalamud Injector Boot");
|
||||
#endif
|
||||
|
||||
wchar_t _module_path[MAX_PATH];
|
||||
GetModuleFileNameW(NULL, _module_path, sizeof _module_path / 2);
|
||||
std::filesystem::path fs_module_path(_module_path);
|
||||
|
||||
std::wstring runtimeconfig_path = _wcsdup(fs_module_path.replace_filename(L"Dalamud.Injector.runtimeconfig.json").c_str());
|
||||
std::wstring module_path = _wcsdup(fs_module_path.replace_filename(L"Dalamud.Injector.dll").c_str());
|
||||
|
||||
// =========================================================================== //
|
||||
|
||||
void* entrypoint_vfn;
|
||||
int result = InitializeClrAndGetEntryPoint(
|
||||
runtimeconfig_path,
|
||||
module_path,
|
||||
L"Dalamud.Injector.EntryPoint, Dalamud.Injector",
|
||||
L"Main",
|
||||
L"Dalamud.Injector.EntryPoint+MainDelegate, Dalamud.Injector",
|
||||
&entrypoint_vfn);
|
||||
|
||||
if (result != 0)
|
||||
return result;
|
||||
|
||||
typedef void (CORECLR_DELEGATE_CALLTYPE* custom_component_entry_point_fn)(int, char**);
|
||||
custom_component_entry_point_fn entrypoint_fn = reinterpret_cast<custom_component_entry_point_fn>(entrypoint_vfn);
|
||||
|
||||
printf("Running Dalamud Injector... ");
|
||||
entrypoint_fn(argc, argv);
|
||||
printf("Done!\n");
|
||||
|
||||
// =========================================================================== //
|
||||
|
||||
#if defined(_DEBUG)
|
||||
FreeConsole();
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
1
Dalamud.Injector.Boot/resources.rc
Normal file
1
Dalamud.Injector.Boot/resources.rc
Normal file
|
|
@ -0,0 +1 @@
|
|||
MAINICON ICON "dalamud.ico"
|
||||
|
|
@ -1,60 +1,89 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup Label="Target">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<TargetFramework>net48</TargetFramework>
|
||||
<LangVersion>8.0</LangVersion>
|
||||
<Platforms>AnyCPU;x64</Platforms>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Label="Build">
|
||||
<OutputType>WinExe</OutputType>
|
||||
<OutputPath>$(SolutionDir)bin</OutputPath>
|
||||
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>Portable</DebugType>
|
||||
<NoWarn>IDE1006;CS1701;CS1702</NoWarn>
|
||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||
<DocumentationFile>$(SolutionDir)\bin\Dalamud.Injector.xml</DocumentationFile>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<Platforms>x64;AnyCPU</Platforms>
|
||||
<LangVersion>9.0</LangVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Label="Feature">
|
||||
<InjectorVersion>5.2.4.6</InjectorVersion>
|
||||
<Description>XIV Launcher addon injector</Description>
|
||||
<AssemblyVersion>$(InjectorVersion)</AssemblyVersion>
|
||||
<FileVersion>$(InjectorVersion)</FileVersion>
|
||||
<Version>$(InjectorVersion)</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Label="Output">
|
||||
<OutputType>Library</OutputType>
|
||||
<OutputPath>..\bin\$(Configuration)\</OutputPath>
|
||||
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
|
||||
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
|
||||
<GenerateRuntimeConfigurationFiles>true</GenerateRuntimeConfigurationFiles>
|
||||
<ProduceReferenceAssembly>false</ProduceReferenceAssembly>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Label="Documentation">
|
||||
<DocumentationFile></DocumentationFile>
|
||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Label="Build">
|
||||
<EnableDynamicLoading>true</EnableDynamicLoading>
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>portable</DebugType>
|
||||
<Deterministic>true</Deterministic>
|
||||
<Nullable>annotations</Nullable>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<AssemblyVersion>5.2.4.6</AssemblyVersion>
|
||||
<FileVersion>5.2.4.6</FileVersion>
|
||||
<Description>XIVLauncher addon injection</Description>
|
||||
<Version>5.2.4.6</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Label="Configuration">
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)'=='Debug'">
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)'=='Release'">
|
||||
<AppOutputBase>$(MSBuildProjectDirectory)\</AppOutputBase>
|
||||
<PathMap>$(AppOutputBase)=C:\goatsoft\companysecrets\injector\</PathMap>
|
||||
<Deterministic>true</Deterministic>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<GeneratePackageOnBuild>false</GeneratePackageOnBuild>
|
||||
<PackageIcon></PackageIcon>
|
||||
<PackageIconUrl />
|
||||
<ApplicationIcon>dalamud.ico</ApplicationIcon>
|
||||
|
||||
<PropertyGroup Label="Warnings">
|
||||
<NoWarn>IDE1006;CS1591;CS1701;CS1702</NoWarn>
|
||||
<!-- IDE1006 - Naming violation -->
|
||||
<!-- CS1591 - Missing XML comment for publicly visible type or member -->
|
||||
<!-- CS1701 - Runtime policy may be needed -->
|
||||
<!-- CS1702 - Runtime policy may be needed -->
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Remove="stylecop.json" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AdditionalFiles Include="stylecop.json" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="EasyHook" Version="2.7.6270" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="12.0.2" />
|
||||
<PackageReference Include="Iced" Version="1.12.0" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
||||
<PackageReference Include="PeNet" Version="2.6.3" />
|
||||
<PackageReference Include="Reloaded.Memory" Version="4.1.1" />
|
||||
<PackageReference Include="Reloaded.Memory.Buffers" Version="1.3.5" />
|
||||
<PackageReference Include="Serilog" Version="2.10.0" />
|
||||
<PackageReference Include="Serilog.Sinks.Async" Version="1.5.0" />
|
||||
<PackageReference Include="Serilog.Sinks.File" Version="5.0.0" />
|
||||
<PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.333">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\DalamudDebugStub\DalamudDebugStub.vcxproj" />
|
||||
<ProjectReference Include="..\Dalamud\Dalamud.csproj" />
|
||||
<AdditionalFiles Include="..\stylecop.json" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Reference Include="System.Windows.Forms" />
|
||||
<!-- This prevents us from having to include Dalamud itself as a dependency -->
|
||||
<!-- If the files move just update the paths here -->
|
||||
<Compile Include="..\Dalamud\ClientLanguage.cs" />
|
||||
<Compile Include="..\Dalamud\DalamudStartInfo.cs" />
|
||||
<Compile Include="..\Dalamud\Game\GameVersion.cs" />
|
||||
<Compile Include="..\Dalamud\Game\GameVersionConverter.cs" />
|
||||
<Compile Include="..\Dalamud\Interface\Internal\SerilogEventSink.cs" />
|
||||
</ItemGroup>
|
||||
<Target Name="PostBuild" AfterTargets="PostBuildEvent" Condition="'$(Configuration)'=='Release'">
|
||||
<Exec Command="powershell -ExecutionPolicy Unrestricted $(SolutionDir)CreateHashList.ps1 $(OutputPath)" />
|
||||
</Target>
|
||||
</Project>
|
||||
|
|
|
|||
275
Dalamud.Injector/EntryPoint.cs
Normal file
275
Dalamud.Injector/EntryPoint.cs
Normal file
|
|
@ -0,0 +1,275 @@
|
|||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
|
||||
using Dalamud.Game;
|
||||
using Dalamud.Interface.Internal;
|
||||
using Newtonsoft.Json;
|
||||
using Reloaded.Memory.Buffers;
|
||||
using Serilog;
|
||||
using Serilog.Core;
|
||||
using Serilog.Events;
|
||||
|
||||
using static Dalamud.Injector.NativeFunctions;
|
||||
|
||||
namespace Dalamud.Injector
|
||||
{
|
||||
/// <summary>
|
||||
/// Entrypoint to the program.
|
||||
/// </summary>
|
||||
public sealed class EntryPoint
|
||||
{
|
||||
/// <summary>
|
||||
/// A delegate used during initialization of the CLR from Dalamud.Injector.Boot.
|
||||
/// </summary>
|
||||
/// <param name="argc">Count of arguments.</param>
|
||||
/// <param name="argvPtr">char** string arguments.</param>
|
||||
public delegate void MainDelegate(int argc, IntPtr argvPtr);
|
||||
|
||||
/// <summary>
|
||||
/// Start the Dalamud injector.
|
||||
/// </summary>
|
||||
/// <param name="argc">Count of arguments.</param>
|
||||
/// <param name="argvPtr">byte** string arguments.</param>
|
||||
public static void Main(int argc, IntPtr argvPtr)
|
||||
{
|
||||
InitUnhandledException();
|
||||
InitLogging();
|
||||
|
||||
var args = new string[argc];
|
||||
|
||||
unsafe
|
||||
{
|
||||
var argv = (IntPtr*)argvPtr;
|
||||
for (var i = 0; i < argc; i++)
|
||||
{
|
||||
args[i] = Marshal.PtrToStringUni(argv[i]);
|
||||
}
|
||||
}
|
||||
|
||||
var cwd = new FileInfo(Assembly.GetExecutingAssembly().Location).Directory;
|
||||
if (cwd.FullName != Directory.GetCurrentDirectory())
|
||||
{
|
||||
Log.Debug($"Changing cwd to {cwd}");
|
||||
Directory.SetCurrentDirectory(cwd.FullName);
|
||||
}
|
||||
|
||||
var process = GetProcess(args.ElementAtOrDefault(1));
|
||||
var startInfo = GetStartInfo(args.ElementAtOrDefault(2), process);
|
||||
|
||||
startInfo.WorkingDirectory = Directory.GetCurrentDirectory();
|
||||
|
||||
// This seems to help with the STATUS_INTERNAL_ERROR condition
|
||||
Thread.Sleep(1000);
|
||||
|
||||
Inject(process, startInfo);
|
||||
|
||||
Thread.Sleep(1000);
|
||||
}
|
||||
|
||||
private static void InitUnhandledException()
|
||||
{
|
||||
AppDomain.CurrentDomain.UnhandledException += (sender, eventArgs) =>
|
||||
{
|
||||
if (Log.Logger == null)
|
||||
{
|
||||
Console.WriteLine($"A fatal error has occurred: {eventArgs.ExceptionObject}");
|
||||
}
|
||||
else
|
||||
{
|
||||
var exObj = eventArgs.ExceptionObject;
|
||||
if (exObj is Exception ex)
|
||||
{
|
||||
Log.Error(ex, "A fatal error has occurred.");
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.Error($"A fatal error has occurred: {eventArgs.ExceptionObject}");
|
||||
}
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
var caption = "Debug Error";
|
||||
var message =
|
||||
$"Couldn't inject.\nMake sure that Dalamud was not injected into your target process " +
|
||||
$"as a release build before and that the target process can be accessed with VM_WRITE permissions.\n\n" +
|
||||
$"{eventArgs.ExceptionObject}";
|
||||
#else
|
||||
var caption = "XIVLauncher Error";
|
||||
var message =
|
||||
"Failed to inject the XIVLauncher in-game addon.\nPlease try restarting your game and your PC.\n" +
|
||||
"If this keeps happening, please report this error.";
|
||||
#endif
|
||||
_ = MessageBoxW(IntPtr.Zero, message, caption, MessageBoxType.IconError | MessageBoxType.Ok);
|
||||
|
||||
Environment.Exit(0);
|
||||
};
|
||||
}
|
||||
|
||||
private static void InitLogging()
|
||||
{
|
||||
var baseDirectory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
|
||||
|
||||
#if DEBUG
|
||||
var logPath = Path.Combine(baseDirectory, "injector.log");
|
||||
#else
|
||||
var logPath = Path.Combine(baseDirectory, "..", "..", "..", "dalamud.injector.log");
|
||||
#endif
|
||||
|
||||
var levelSwitch = new LoggingLevelSwitch();
|
||||
|
||||
#if DEBUG
|
||||
levelSwitch.MinimumLevel = LogEventLevel.Verbose;
|
||||
#else
|
||||
levelSwitch.MinimumLevel = LogEventLevel.Information;
|
||||
#endif
|
||||
|
||||
Log.Logger = new LoggerConfiguration()
|
||||
.WriteTo.Async(a => a.File(logPath))
|
||||
.WriteTo.Sink(SerilogEventSink.Instance)
|
||||
.MinimumLevel.ControlledBy(levelSwitch)
|
||||
.CreateLogger();
|
||||
}
|
||||
|
||||
private static Process GetProcess(string arg)
|
||||
{
|
||||
Process process;
|
||||
|
||||
var pid = -1;
|
||||
if (arg != default)
|
||||
{
|
||||
pid = int.Parse(arg);
|
||||
}
|
||||
|
||||
switch (pid)
|
||||
{
|
||||
case -1:
|
||||
process = Process.GetProcessesByName("ffxiv_dx11").FirstOrDefault();
|
||||
|
||||
if (process == default)
|
||||
{
|
||||
throw new Exception("Could not find process");
|
||||
}
|
||||
|
||||
break;
|
||||
case -2:
|
||||
var exePath = "C:\\Program Files (x86)\\SquareEnix\\FINAL FANTASY XIV - A Realm Reborn\\game\\ffxiv_dx11.exe";
|
||||
var exeArgs = new StringBuilder()
|
||||
.Append("DEV.TestSID=0 DEV.UseSqPack=1 DEV.DataPathType=1 ")
|
||||
.Append("DEV.LobbyHost01=127.0.0.1 DEV.LobbyPort01=54994 ")
|
||||
.Append("DEV.LobbyHost02=127.0.0.1 DEV.LobbyPort02=54994 ")
|
||||
.Append("DEV.LobbyHost03=127.0.0.1 DEV.LobbyPort03=54994 ")
|
||||
.Append("DEV.LobbyHost04=127.0.0.1 DEV.LobbyPort04=54994 ")
|
||||
.Append("DEV.LobbyHost05=127.0.0.1 DEV.LobbyPort05=54994 ")
|
||||
.Append("DEV.LobbyHost06=127.0.0.1 DEV.LobbyPort06=54994 ")
|
||||
.Append("DEV.LobbyHost07=127.0.0.1 DEV.LobbyPort07=54994 ")
|
||||
.Append("DEV.LobbyHost08=127.0.0.1 DEV.LobbyPort08=54994 ")
|
||||
.Append("SYS.Region=0 language=1 version=1.0.0.0 ")
|
||||
.Append("DEV.MaxEntitledExpansionID=2 DEV.GMServerHost=127.0.0.1 DEV.GameQuitMessageBox=0").ToString();
|
||||
process = Process.Start(exePath, exeArgs);
|
||||
Thread.Sleep(1000);
|
||||
break;
|
||||
default:
|
||||
process = Process.GetProcessById(pid);
|
||||
break;
|
||||
}
|
||||
|
||||
return process;
|
||||
}
|
||||
|
||||
private static DalamudStartInfo GetStartInfo(string arg, Process process)
|
||||
{
|
||||
DalamudStartInfo startInfo;
|
||||
|
||||
if (arg != default)
|
||||
{
|
||||
startInfo = JsonConvert.DeserializeObject<DalamudStartInfo>(Encoding.UTF8.GetString(Convert.FromBase64String(arg)));
|
||||
}
|
||||
else
|
||||
{
|
||||
var ffxivDir = Path.GetDirectoryName(process.MainModule.FileName);
|
||||
var appDataDir = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
|
||||
var xivlauncherDir = Path.Combine(appDataDir, "XIVLauncher");
|
||||
|
||||
var gameVerStr = File.ReadAllText(Path.Combine(ffxivDir, "ffxivgame.ver"));
|
||||
var gameVer = GameVersion.Parse(gameVerStr);
|
||||
|
||||
startInfo = new DalamudStartInfo
|
||||
{
|
||||
WorkingDirectory = null,
|
||||
ConfigurationPath = Path.Combine(xivlauncherDir, "dalamudConfig.json"),
|
||||
PluginDirectory = Path.Combine(xivlauncherDir, "installedPlugins"),
|
||||
DefaultPluginDirectory = Path.Combine(xivlauncherDir, "devPlugins"),
|
||||
AssetDirectory = Path.Combine(xivlauncherDir, "dalamudAssets"),
|
||||
GameVersion = gameVer,
|
||||
Language = ClientLanguage.English,
|
||||
OptOutMbCollection = false,
|
||||
};
|
||||
|
||||
Log.Debug(
|
||||
"Creating a new StartInfo with:\n" +
|
||||
$" WorkingDirectory: {startInfo.WorkingDirectory}\n" +
|
||||
$" ConfigurationPath: {startInfo.ConfigurationPath}\n" +
|
||||
$" PluginDirectory: {startInfo.PluginDirectory}\n" +
|
||||
$" DefaultPluginDirectory: {startInfo.DefaultPluginDirectory}\n" +
|
||||
$" AssetDirectory: {startInfo.AssetDirectory}\n" +
|
||||
$" GameVersion: {startInfo.GameVersion}\n" +
|
||||
$" Language: {startInfo.Language}\n" +
|
||||
$" OptOutMbCollection: {startInfo.OptOutMbCollection}");
|
||||
|
||||
Log.Information("A Dalamud start info was not found in the program arguments. One has been generated for you.");
|
||||
Log.Information("Copy the following contents into the program arguments:");
|
||||
|
||||
var startInfoJson = Convert.ToBase64String(Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(startInfo)));
|
||||
Log.Information(startInfoJson);
|
||||
}
|
||||
|
||||
return startInfo;
|
||||
}
|
||||
|
||||
private static void Inject(Process process, DalamudStartInfo startInfo)
|
||||
{
|
||||
var nethostName = "nethost.dll";
|
||||
var bootName = "Dalamud.Boot.dll";
|
||||
|
||||
var nethostPath = Path.GetFullPath(nethostName);
|
||||
var bootPath = Path.GetFullPath(bootName);
|
||||
|
||||
// ======================================================
|
||||
|
||||
using var injector = new Injector(process);
|
||||
|
||||
injector.LoadLibrary(nethostPath, out _);
|
||||
injector.LoadLibrary(bootPath, out var bootModule);
|
||||
|
||||
// ======================================================
|
||||
|
||||
var startInfoJson = JsonConvert.SerializeObject(startInfo);
|
||||
var startInfoBytes = Encoding.UTF8.GetBytes(startInfoJson);
|
||||
|
||||
using var startInfoBuffer = new MemoryBufferHelper(process).CreatePrivateMemoryBuffer(startInfoBytes.Length + 0x8);
|
||||
var startInfoAddress = startInfoBuffer.Add(startInfoBytes);
|
||||
|
||||
if (startInfoAddress == IntPtr.Zero)
|
||||
throw new Exception("Unable to allocate start info JSON");
|
||||
|
||||
injector.GetFunctionAddress(bootModule, "Initialize", out var initAddress);
|
||||
injector.CallRemoteFunction(initAddress, startInfoAddress, out var exitCode);
|
||||
|
||||
// ======================================================
|
||||
|
||||
if (exitCode > 0)
|
||||
{
|
||||
Log.Error($"Dalamud.Boot::Initialize returned {exitCode}");
|
||||
return;
|
||||
}
|
||||
|
||||
Log.Information("Done");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -6,14 +6,8 @@
|
|||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
// General
|
||||
[assembly: SuppressMessage("StyleCop.CSharp.ReadabilityRules", "SA1118:Parameter should not span multiple lines", Justification = "Preventing long lines", Scope = "namespaceanddescendants", Target = "~N:Dalamud")]
|
||||
[assembly: SuppressMessage("StyleCop.CSharp.ReadabilityRules", "SA1124:Do not use regions", Justification = "I like regions", Scope = "namespaceanddescendants", Target = "~N:Dalamud")]
|
||||
[assembly: SuppressMessage("StyleCop.CSharp.ReadabilityRules", "SA1123:Do not place regions within elements", Justification = "I like regions in elements too", Scope = "namespaceanddescendants", Target = "~N:Dalamud")]
|
||||
[assembly: SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1633:File should have header", Justification = "We don't do those yet")]
|
||||
[assembly: SuppressMessage("StyleCop.CSharp.LayoutRules", "SA1503:Braces should not be omitted", Justification = "This is annoying", Scope = "namespaceanddescendants", Target = "~N:Dalamud")]
|
||||
[assembly: SuppressMessage("StyleCop.CSharp.LayoutRules", "SA1512:Single-line comments should not be followed by blank line", Justification = "I like this better", Scope = "namespaceanddescendants", Target = "~N:Dalamud")]
|
||||
[assembly: SuppressMessage("StyleCop.CSharp.LayoutRules", "SA1515:Single-line comment should be preceded by blank line", Justification = "I like this better", Scope = "namespaceanddescendants", Target = "~N:Dalamud")]
|
||||
[assembly: SuppressMessage("StyleCop.CSharp.ReadabilityRules", "SA1127:Generic type constraints should be on their own line", Justification = "I like this better", Scope = "namespaceanddescendants", Target = "~N:Dalamud")]
|
||||
[assembly: SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1633:File should have header", Justification = "We don't do those yet")]
|
||||
|
||||
// Program.cs
|
||||
[assembly: SuppressMessage("CodeQuality", "IDE0051:Remove unused private members", Justification = "Used during #if DEBUG", Scope = "member", Target = "~M:Dalamud.Injector.Program.NativeInject(System.Diagnostics.Process)")]
|
||||
[assembly: SuppressMessage("Performance", "CA1822:Mark members as static", Justification = "I'll make what I want static", Scope = "namespaceanddescendants", Target = "~N:Dalamud")]
|
||||
|
|
|
|||
303
Dalamud.Injector/Injector.cs
Normal file
303
Dalamud.Injector/Injector.cs
Normal file
|
|
@ -0,0 +1,303 @@
|
|||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
using Iced.Intel;
|
||||
using PeNet;
|
||||
using PeNet.Header.Pe;
|
||||
using Reloaded.Memory.Buffers;
|
||||
using Reloaded.Memory.Sources;
|
||||
using Reloaded.Memory.Utilities;
|
||||
|
||||
using static Dalamud.Injector.NativeFunctions;
|
||||
using static Iced.Intel.AssemblerRegisters;
|
||||
|
||||
namespace Dalamud.Injector
|
||||
{
|
||||
/// <summary>
|
||||
/// This class implements injecting into a remote process. It is a highly stripped down version of the
|
||||
/// https://github.com/Reloaded-Project injector/assembler implementation due to issues with Lutris and
|
||||
/// Wine.
|
||||
/// </summary>
|
||||
internal sealed class Injector : IDisposable
|
||||
{
|
||||
private readonly Process targetProcess;
|
||||
private readonly ExternalMemory extMemory;
|
||||
private readonly CircularBuffer circularBuffer;
|
||||
private readonly PrivateMemoryBuffer privateBuffer;
|
||||
|
||||
private IntPtr loadLibraryShellPtr;
|
||||
private IntPtr loadLibraryRetPtr;
|
||||
|
||||
private IntPtr getProcAddressShellPtr;
|
||||
private IntPtr getProcAddressRetPtr;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Injector"/> class.
|
||||
/// </summary>
|
||||
/// <param name="targetProcess">Process to inject.</param>
|
||||
public Injector(Process targetProcess)
|
||||
{
|
||||
this.targetProcess = targetProcess;
|
||||
|
||||
this.extMemory = new ExternalMemory(targetProcess);
|
||||
this.circularBuffer = new CircularBuffer(4096, this.extMemory);
|
||||
this.privateBuffer = new MemoryBufferHelper(targetProcess).CreatePrivateMemoryBuffer(4096);
|
||||
|
||||
using var kernel32Module = this.GetProcessModule("KERNEL32.DLL");
|
||||
var kernel32PeFile = new PeFile(kernel32Module.FileName);
|
||||
var kernel32Exports = kernel32PeFile.ExportedFunctions;
|
||||
|
||||
this.SetupLoadLibrary(kernel32Module, kernel32Exports);
|
||||
this.SetupGetProcAddress(kernel32Module, kernel32Exports);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finalizes an instance of the <see cref="Injector"/> class.
|
||||
/// </summary>
|
||||
~Injector() => this.Dispose();
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Dispose()
|
||||
{
|
||||
GC.SuppressFinalize(this);
|
||||
|
||||
this.targetProcess?.Dispose();
|
||||
this.circularBuffer?.Dispose();
|
||||
this.privateBuffer?.Dispose();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Load a module by absolute file path.
|
||||
/// </summary>
|
||||
/// <param name="modulePath">Absolute file path.</param>
|
||||
/// <param name="address">Address to the module.</param>
|
||||
public void LoadLibrary(string modulePath, out IntPtr address)
|
||||
{
|
||||
var lpParameter = this.WriteNullTerminatedUnicodeString(modulePath);
|
||||
|
||||
if (lpParameter == IntPtr.Zero)
|
||||
throw new Exception("Unable to allocate LoadLibraryW parameter");
|
||||
|
||||
var threadHandle = CreateRemoteThread(
|
||||
this.targetProcess.Handle,
|
||||
IntPtr.Zero,
|
||||
UIntPtr.Zero,
|
||||
this.loadLibraryShellPtr,
|
||||
lpParameter,
|
||||
CreateThreadFlags.RunImmediately,
|
||||
out _);
|
||||
|
||||
_ = WaitForSingleObject(threadHandle, uint.MaxValue);
|
||||
|
||||
this.extMemory.Read(this.loadLibraryRetPtr, out address);
|
||||
|
||||
if (address == IntPtr.Zero)
|
||||
throw new Exception($"Error calling LoadLibraryW with {modulePath}");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the address of an exported module function.
|
||||
/// </summary>
|
||||
/// <param name="module">Module address.</param>
|
||||
/// <param name="functionName">Name of the exported method.</param>
|
||||
/// <param name="address">Address to the function.</param>
|
||||
public void GetFunctionAddress(IntPtr module, string functionName, out IntPtr address)
|
||||
{
|
||||
var getProcAddressParams = new GetProcAddressParams(module, this.WriteNullTerminatedASCIIString(functionName));
|
||||
var lpParameter = this.circularBuffer.Add(ref getProcAddressParams);
|
||||
|
||||
if (lpParameter == IntPtr.Zero)
|
||||
throw new Exception("Unable to allocate GetProcAddress parameter ptr");
|
||||
|
||||
var threadHandle = CreateRemoteThread(
|
||||
this.targetProcess.Handle,
|
||||
IntPtr.Zero,
|
||||
UIntPtr.Zero,
|
||||
this.getProcAddressShellPtr,
|
||||
lpParameter,
|
||||
CreateThreadFlags.RunImmediately,
|
||||
out _);
|
||||
|
||||
_ = WaitForSingleObject(threadHandle, uint.MaxValue);
|
||||
|
||||
this.extMemory.Read(this.getProcAddressRetPtr, out address);
|
||||
|
||||
if (address == IntPtr.Zero)
|
||||
throw new Exception($"Error calling GetProcAddress with {functionName}");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Call a method in a remote process via CreateRemoteThread.
|
||||
/// </summary>
|
||||
/// <param name="methodAddress">Method address.</param>
|
||||
/// <param name="parameterAddress">Parameter address.</param>
|
||||
/// <param name="exitCode">Thread exit code.</param>
|
||||
public void CallRemoteFunction(IntPtr methodAddress, IntPtr parameterAddress, out uint exitCode)
|
||||
{
|
||||
// Create and initialize a thread at our address and parameter address.
|
||||
var threadHandle = CreateRemoteThread(
|
||||
this.targetProcess.Handle,
|
||||
IntPtr.Zero,
|
||||
UIntPtr.Zero,
|
||||
methodAddress,
|
||||
parameterAddress,
|
||||
CreateThreadFlags.RunImmediately,
|
||||
out _);
|
||||
|
||||
_ = WaitForSingleObject(threadHandle, uint.MaxValue);
|
||||
|
||||
GetExitCodeThread(threadHandle, out exitCode);
|
||||
}
|
||||
|
||||
private void SetupLoadLibrary(ProcessModule kernel32Module, ExportFunction[] kernel32Exports)
|
||||
{
|
||||
var offset = this.GetExportedFunctionOffset(kernel32Exports, "LoadLibraryW");
|
||||
var functionAddr = kernel32Module.BaseAddress + (int)offset;
|
||||
var functionPtr = this.privateBuffer.Add(ref functionAddr);
|
||||
|
||||
if (functionPtr == IntPtr.Zero)
|
||||
throw new Exception("Unable to allocate LoadLibraryW function ptr");
|
||||
|
||||
var dummy = 0L;
|
||||
this.loadLibraryRetPtr = this.privateBuffer.Add(ref dummy);
|
||||
|
||||
if (this.loadLibraryRetPtr == IntPtr.Zero)
|
||||
throw new Exception("Unable to allocate LoadLibraryW return value");
|
||||
|
||||
var func = functionPtr.ToInt64();
|
||||
var retVal = this.loadLibraryRetPtr.ToInt64();
|
||||
|
||||
var asm = new Assembler(64);
|
||||
|
||||
asm.sub(rsp, 40); // sub rsp, 40 // Re-align stack to 16 byte boundary + shadow space.
|
||||
asm.call(__qword_ptr[__qword_ptr[func]]); // call qword [qword func] // CreateRemoteThread lpParameter with string already in ECX.
|
||||
asm.mov(__qword_ptr[__qword_ptr[retVal]], rax); // mov qword [qword retVal], rax //
|
||||
asm.add(rsp, 40); // add rsp, 40 // Re-align stack to 16 byte boundary + shadow space.
|
||||
asm.ret(); // ret // Restore stack ptr. (Callee cleanup)
|
||||
|
||||
var bytes = this.Assemble(asm);
|
||||
this.loadLibraryShellPtr = this.privateBuffer.Add(bytes);
|
||||
|
||||
if (this.loadLibraryShellPtr == IntPtr.Zero)
|
||||
throw new Exception("Unable to allocate LoadLibraryW shellcode");
|
||||
}
|
||||
|
||||
private void SetupGetProcAddress(ProcessModule kernel32Module, ExportFunction[] kernel32Exports)
|
||||
{
|
||||
var offset = this.GetExportedFunctionOffset(kernel32Exports, "GetProcAddress");
|
||||
var functionAddr = kernel32Module.BaseAddress + (int)offset;
|
||||
var functionPtr = this.privateBuffer.Add(ref functionAddr);
|
||||
|
||||
if (functionPtr == IntPtr.Zero)
|
||||
throw new Exception("Unable to allocate GetProcAddress function ptr");
|
||||
|
||||
var dummy = 0L;
|
||||
this.getProcAddressRetPtr = this.privateBuffer.Add(ref dummy);
|
||||
|
||||
if (this.getProcAddressRetPtr == IntPtr.Zero)
|
||||
throw new Exception("Unable to allocate GetProcAddress return value");
|
||||
|
||||
var func = functionPtr.ToInt64();
|
||||
var retVal = this.getProcAddressRetPtr.ToInt64();
|
||||
|
||||
var asm = new Assembler(64);
|
||||
|
||||
asm.sub(rsp, 40); // sub rsp, 40 // Re-align stack to 16 byte boundary +32 shadow space
|
||||
asm.mov(rdx, __qword_ptr[__qword_ptr[rcx + 8]]); // mov rdx, qword [qword rcx + 8] // lpProcName
|
||||
asm.mov(rcx, __qword_ptr[__qword_ptr[rcx + 0]]); // mov rcx, qword [qword rcx + 0] // hModule
|
||||
asm.call(__qword_ptr[__qword_ptr[func]]); // call qword [qword func] //
|
||||
asm.mov(__qword_ptr[__qword_ptr[retVal]], rax); // mov qword [qword retVal] //
|
||||
asm.add(rsp, 40); // add rsp, 40 // Re-align stack to 16 byte boundary + shadow space.
|
||||
asm.ret(); // ret // Restore stack ptr. (Callee cleanup)
|
||||
|
||||
var bytes = this.Assemble(asm);
|
||||
this.getProcAddressShellPtr = this.privateBuffer.Add(bytes);
|
||||
|
||||
if (this.getProcAddressShellPtr == IntPtr.Zero)
|
||||
throw new Exception("Unable to allocate GetProcAddress shellcode");
|
||||
}
|
||||
|
||||
private byte[] Assemble(Assembler assembler)
|
||||
{
|
||||
using var stream = new MemoryStream();
|
||||
assembler.Assemble(new StreamCodeWriter(stream), 0);
|
||||
|
||||
stream.Position = 0;
|
||||
var reader = new StreamCodeReader(stream);
|
||||
|
||||
int next;
|
||||
var bytes = new byte[stream.Length];
|
||||
while ((next = reader.ReadByte()) >= 0)
|
||||
{
|
||||
bytes[stream.Position - 1] = (byte)next;
|
||||
}
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
private ProcessModule GetProcessModule(string moduleName)
|
||||
{
|
||||
var modules = this.targetProcess.Modules;
|
||||
for (var i = 0; i < modules.Count; i++)
|
||||
{
|
||||
var module = modules[i];
|
||||
if (module.ModuleName.Equals(moduleName, StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
return module;
|
||||
}
|
||||
}
|
||||
|
||||
throw new Exception($"Failed to find {moduleName} in target process' modules");
|
||||
}
|
||||
|
||||
private uint GetExportedFunctionOffset(ExportFunction[] exportFunctions, string functionName)
|
||||
{
|
||||
var exportFunction = exportFunctions.FirstOrDefault(func => func.Name == functionName);
|
||||
|
||||
if (exportFunction == default)
|
||||
throw new Exception($"Failed to find exported function {functionName} in target module's exports");
|
||||
|
||||
return exportFunction.Address;
|
||||
}
|
||||
|
||||
private IntPtr WriteNullTerminatedASCIIString(string libraryPath)
|
||||
{
|
||||
var libraryNameBytes = Encoding.ASCII.GetBytes(libraryPath + '\0');
|
||||
var value = this.circularBuffer.Add(libraryNameBytes);
|
||||
|
||||
if (value == IntPtr.Zero)
|
||||
throw new Exception("Unable to write ASCII string to buffer");
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
private IntPtr WriteNullTerminatedUnicodeString(string libraryPath)
|
||||
{
|
||||
var libraryNameBytes = Encoding.Unicode.GetBytes(libraryPath + '\0');
|
||||
var value = this.circularBuffer.Add(libraryNameBytes);
|
||||
|
||||
if (value == IntPtr.Zero)
|
||||
throw new Exception("Unable to write Unicode string to buffer");
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
private struct GetProcAddressParams
|
||||
{
|
||||
public GetProcAddressParams(IntPtr hModule, IntPtr lPProcName)
|
||||
{
|
||||
this.HModule = hModule.ToInt64();
|
||||
this.LPProcName = lPProcName.ToInt64();
|
||||
}
|
||||
|
||||
public long HModule { get; set; }
|
||||
|
||||
public long LPProcName { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,14 +1,234 @@
|
|||
using System;
|
||||
using System.Runtime.ConstrainedExecution;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security;
|
||||
|
||||
namespace Dalamud.Injector
|
||||
{
|
||||
/// <summary>
|
||||
/// Native functions.
|
||||
/// Native user32 functions.
|
||||
/// </summary>
|
||||
internal static class NativeFunctions
|
||||
internal static partial class NativeFunctions
|
||||
{
|
||||
/// <summary>
|
||||
/// MB_* from winuser.
|
||||
/// </summary>
|
||||
public enum MessageBoxType : uint
|
||||
{
|
||||
/// <summary>
|
||||
/// The default value for any of the various subtypes.
|
||||
/// </summary>
|
||||
DefaultValue = 0x0,
|
||||
|
||||
// To indicate the buttons displayed in the message box, specify one of the following values.
|
||||
|
||||
/// <summary>
|
||||
/// The message box contains three push buttons: Abort, Retry, and Ignore.
|
||||
/// </summary>
|
||||
AbortRetryIgnore = 0x2,
|
||||
|
||||
/// <summary>
|
||||
/// The message box contains three push buttons: Cancel, Try Again, Continue. Use this message box type instead
|
||||
/// of MB_ABORTRETRYIGNORE.
|
||||
/// </summary>
|
||||
CancelTryContinue = 0x6,
|
||||
|
||||
/// <summary>
|
||||
/// Adds a Help button to the message box. When the user clicks the Help button or presses F1, the system sends
|
||||
/// a WM_HELP message to the owner.
|
||||
/// </summary>
|
||||
Help = 0x4000,
|
||||
|
||||
/// <summary>
|
||||
/// The message box contains one push button: OK. This is the default.
|
||||
/// </summary>
|
||||
Ok = DefaultValue,
|
||||
|
||||
/// <summary>
|
||||
/// The message box contains two push buttons: OK and Cancel.
|
||||
/// </summary>
|
||||
OkCancel = 0x1,
|
||||
|
||||
/// <summary>
|
||||
/// The message box contains two push buttons: Retry and Cancel.
|
||||
/// </summary>
|
||||
RetryCancel = 0x5,
|
||||
|
||||
/// <summary>
|
||||
/// The message box contains two push buttons: Yes and No.
|
||||
/// </summary>
|
||||
YesNo = 0x4,
|
||||
|
||||
/// <summary>
|
||||
/// The message box contains three push buttons: Yes, No, and Cancel.
|
||||
/// </summary>
|
||||
YesNoCancel = 0x3,
|
||||
|
||||
// To display an icon in the message box, specify one of the following values.
|
||||
|
||||
/// <summary>
|
||||
/// An exclamation-point icon appears in the message box.
|
||||
/// </summary>
|
||||
IconExclamation = 0x30,
|
||||
|
||||
/// <summary>
|
||||
/// An exclamation-point icon appears in the message box.
|
||||
/// </summary>
|
||||
IconWarning = IconExclamation,
|
||||
|
||||
/// <summary>
|
||||
/// An icon consisting of a lowercase letter i in a circle appears in the message box.
|
||||
/// </summary>
|
||||
IconInformation = 0x40,
|
||||
|
||||
/// <summary>
|
||||
/// An icon consisting of a lowercase letter i in a circle appears in the message box.
|
||||
/// </summary>
|
||||
IconAsterisk = IconInformation,
|
||||
|
||||
/// <summary>
|
||||
/// A question-mark icon appears in the message box.
|
||||
/// The question-mark message icon is no longer recommended because it does not clearly represent a specific type
|
||||
/// of message and because the phrasing of a message as a question could apply to any message type. In addition,
|
||||
/// users can confuse the message symbol question mark with Help information. Therefore, do not use this question
|
||||
/// mark message symbol in your message boxes. The system continues to support its inclusion only for backward
|
||||
/// compatibility.
|
||||
/// </summary>
|
||||
IconQuestion = 0x20,
|
||||
|
||||
/// <summary>
|
||||
/// A stop-sign icon appears in the message box.
|
||||
/// </summary>
|
||||
IconStop = 0x10,
|
||||
|
||||
/// <summary>
|
||||
/// A stop-sign icon appears in the message box.
|
||||
/// </summary>
|
||||
IconError = IconStop,
|
||||
|
||||
/// <summary>
|
||||
/// A stop-sign icon appears in the message box.
|
||||
/// </summary>
|
||||
IconHand = IconStop,
|
||||
|
||||
// To indicate the default button, specify one of the following values.
|
||||
|
||||
/// <summary>
|
||||
/// The first button is the default button.
|
||||
/// MB_DEFBUTTON1 is the default unless MB_DEFBUTTON2, MB_DEFBUTTON3, or MB_DEFBUTTON4 is specified.
|
||||
/// </summary>
|
||||
DefButton1 = DefaultValue,
|
||||
|
||||
/// <summary>
|
||||
/// The second button is the default button.
|
||||
/// </summary>
|
||||
DefButton2 = 0x100,
|
||||
|
||||
/// <summary>
|
||||
/// The third button is the default button.
|
||||
/// </summary>
|
||||
DefButton3 = 0x200,
|
||||
|
||||
/// <summary>
|
||||
/// The fourth button is the default button.
|
||||
/// </summary>
|
||||
DefButton4 = 0x300,
|
||||
|
||||
// To indicate the modality of the dialog box, specify one of the following values.
|
||||
|
||||
/// <summary>
|
||||
/// The user must respond to the message box before continuing work in the window identified by the hWnd parameter.
|
||||
/// However, the user can move to the windows of other threads and work in those windows. Depending on the hierarchy
|
||||
/// of windows in the application, the user may be able to move to other windows within the thread. All child windows
|
||||
/// of the parent of the message box are automatically disabled, but pop-up windows are not. MB_APPLMODAL is the
|
||||
/// default if neither MB_SYSTEMMODAL nor MB_TASKMODAL is specified.
|
||||
/// </summary>
|
||||
ApplModal = DefaultValue,
|
||||
|
||||
/// <summary>
|
||||
/// Same as MB_APPLMODAL except that the message box has the WS_EX_TOPMOST style.
|
||||
/// Use system-modal message boxes to notify the user of serious, potentially damaging errors that require immediate
|
||||
/// attention (for example, running out of memory). This flag has no effect on the user's ability to interact with
|
||||
/// windows other than those associated with hWnd.
|
||||
/// </summary>
|
||||
SystemModal = 0x1000,
|
||||
|
||||
/// <summary>
|
||||
/// Same as MB_APPLMODAL except that all the top-level windows belonging to the current thread are disabled if the
|
||||
/// hWnd parameter is NULL. Use this flag when the calling application or library does not have a window handle
|
||||
/// available but still needs to prevent input to other windows in the calling thread without suspending other threads.
|
||||
/// </summary>
|
||||
TaskModal = 0x2000,
|
||||
|
||||
// To specify other options, use one or more of the following values.
|
||||
|
||||
/// <summary>
|
||||
/// Same as desktop of the interactive window station. For more information, see Window Stations. If the current
|
||||
/// input desktop is not the default desktop, MessageBox does not return until the user switches to the default
|
||||
/// desktop.
|
||||
/// </summary>
|
||||
DefaultDesktopOnly = 0x20000,
|
||||
|
||||
/// <summary>
|
||||
/// The text is right-justified.
|
||||
/// </summary>
|
||||
Right = 0x80000,
|
||||
|
||||
/// <summary>
|
||||
/// Displays message and caption text using right-to-left reading order on Hebrew and Arabic systems.
|
||||
/// </summary>
|
||||
RtlReading = 0x100000,
|
||||
|
||||
/// <summary>
|
||||
/// The message box becomes the foreground window. Internally, the system calls the SetForegroundWindow function
|
||||
/// for the message box.
|
||||
/// </summary>
|
||||
SetForeground = 0x10000,
|
||||
|
||||
/// <summary>
|
||||
/// The message box is created with the WS_EX_TOPMOST window style.
|
||||
/// </summary>
|
||||
Topmost = 0x40000,
|
||||
|
||||
/// <summary>
|
||||
/// The caller is a service notifying the user of an event. The function displays a message box on the current active
|
||||
/// desktop, even if there is no user logged on to the computer.
|
||||
/// </summary>
|
||||
ServiceNotification = 0x200000,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Displays a modal dialog box that contains a system icon, a set of buttons, and a brief application-specific message,
|
||||
/// such as status or error information. The message box returns an integer value that indicates which button the user
|
||||
/// clicked.
|
||||
/// </summary>
|
||||
/// <param name="hWnd">
|
||||
/// A handle to the owner window of the message box to be created. If this parameter is NULL, the message box has no
|
||||
/// owner window.
|
||||
/// </param>
|
||||
/// <param name="text">
|
||||
/// The message to be displayed. If the string consists of more than one line, you can separate the lines using a carriage
|
||||
/// return and/or linefeed character between each line.
|
||||
/// </param>
|
||||
/// <param name="caption">
|
||||
/// The dialog box title. If this parameter is NULL, the default title is Error.</param>
|
||||
/// <param name="type">
|
||||
/// The contents and behavior of the dialog box. This parameter can be a combination of flags from the following groups
|
||||
/// of flags.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// If a message box has a Cancel button, the function returns the IDCANCEL value if either the ESC key is pressed or
|
||||
/// the Cancel button is selected. If the message box has no Cancel button, pressing ESC will no effect - unless an
|
||||
/// MB_OK button is present. If an MB_OK button is displayed and the user presses ESC, the return value will be IDOK.
|
||||
/// If the function fails, the return value is zero.To get extended error information, call GetLastError. If the function
|
||||
/// succeeds, the return value is one of the ID* enum values.
|
||||
/// </returns>
|
||||
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
|
||||
public static extern int MessageBoxW(IntPtr hWnd, string text, string caption, MessageBoxType type);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Native kernel32 functions.
|
||||
/// </summary>
|
||||
internal static partial class NativeFunctions
|
||||
{
|
||||
/// <summary>
|
||||
/// MEM_* from memoryapi.
|
||||
|
|
@ -20,14 +240,14 @@ namespace Dalamud.Injector
|
|||
/// To coalesce two adjacent placeholders, specify MEM_RELEASE | MEM_COALESCE_PLACEHOLDERS. When you coalesce
|
||||
/// placeholders, lpAddress and dwSize must exactly match those of the placeholder.
|
||||
/// </summary>
|
||||
CoalescePlaceholders = 0x00000001,
|
||||
CoalescePlaceholders = 0x1,
|
||||
|
||||
/// <summary>
|
||||
/// Frees an allocation back to a placeholder (after you've replaced a placeholder with a private allocation using
|
||||
/// VirtualAlloc2 or Virtual2AllocFromApp). To split a placeholder into two placeholders, specify
|
||||
/// MEM_RELEASE | MEM_PRESERVE_PLACEHOLDER.
|
||||
/// </summary>
|
||||
PreservePlaceholder = 0x00000002,
|
||||
PreservePlaceholder = 0x2,
|
||||
|
||||
/// <summary>
|
||||
/// Allocates memory charges (from the overall size of memory and the paging files on disk) for the specified reserved
|
||||
|
|
@ -88,7 +308,7 @@ namespace Dalamud.Injector
|
|||
/// the specified address range is intact. If the function fails, at least some of the data in the address range
|
||||
/// has been replaced with zeroes. This value cannot be used with any other value. If MEM_RESET_UNDO is called on
|
||||
/// an address range which was not MEM_RESET earlier, the behavior is undefined. When you specify MEM_RESET, the
|
||||
/// VirtualAllocEx function ignores the value of flProtect. However, you must still set flProtect to a valid
|
||||
/// VirtualAllocEx function ignores the value of flProtect. However, you must still set flProtect to a valid
|
||||
/// protection value, such as PAGE_NOACCESS.
|
||||
/// </summary>
|
||||
ResetUndo = 0x1000000,
|
||||
|
|
@ -122,6 +342,28 @@ namespace Dalamud.Injector
|
|||
LargePages = 0x20000000,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unprefixed flags from CreateRemoteThread.
|
||||
/// </summary>
|
||||
[Flags]
|
||||
public enum CreateThreadFlags
|
||||
{
|
||||
/// <summary>
|
||||
/// The thread runs immediately after creation.
|
||||
/// </summary>
|
||||
RunImmediately = 0x0,
|
||||
|
||||
/// <summary>
|
||||
/// The thread is created in a suspended state, and does not run until the ResumeThread function is called.
|
||||
/// </summary>
|
||||
CreateSuspended = 0x4,
|
||||
|
||||
/// <summary>
|
||||
/// The dwStackSize parameter specifies the initial reserve size of the stack. If this flag is not specified, dwStackSize specifies the commit size.
|
||||
/// </summary>
|
||||
StackSizeParamIsReservation = 0x10000,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// PAGE_* from memoryapi.
|
||||
/// </summary>
|
||||
|
|
@ -198,7 +440,7 @@ namespace Dalamud.Injector
|
|||
/// The default behavior for VirtualProtect protection change to executable is to mark all locations as valid call
|
||||
/// targets for CFG.
|
||||
/// </summary>
|
||||
TargetsNoUpdate = 0x40000000,
|
||||
TargetsNoUpdate = TargetsInvalid,
|
||||
|
||||
/// <summary>
|
||||
/// Pages in the region become guard pages. Any attempt to access a guard page causes the system to raise a
|
||||
|
|
@ -312,23 +554,33 @@ namespace Dalamud.Injector
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Closes an open object handle.
|
||||
/// WAIT_* from synchapi.
|
||||
/// </summary>
|
||||
/// <param name="hObject">
|
||||
/// A valid handle to an open object.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// If the function succeeds, the return value is nonzero. If the function fails, the return value is zero.To get extended
|
||||
/// error information, call GetLastError. If the application is running under a debugger, the function will throw an
|
||||
/// exception if it receives either a handle value that is not valid or a pseudo-handle value. This can happen if you
|
||||
/// close a handle twice, or if you call CloseHandle on a handle returned by the FindFirstFile function instead of calling
|
||||
/// the FindClose function.
|
||||
/// </returns>
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
|
||||
[SuppressUnmanagedCodeSecurity]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
public static extern bool CloseHandle(IntPtr hObject);
|
||||
public enum WaitResult
|
||||
{
|
||||
/// <summary>
|
||||
/// The specified object is a mutex object that was not released by the thread that owned the mutex object
|
||||
/// before the owning thread terminated.Ownership of the mutex object is granted to the calling thread and
|
||||
/// the mutex state is set to nonsignaled. If the mutex was protecting persistent state information, you
|
||||
/// should check it for consistency.
|
||||
/// </summary>
|
||||
Abandoned = 0x80,
|
||||
|
||||
/// <summary>
|
||||
/// The state of the specified object is signaled.
|
||||
/// </summary>
|
||||
Object0 = 0x0,
|
||||
|
||||
/// <summary>
|
||||
/// The time-out interval elapsed, and the object's state is nonsignaled.
|
||||
/// </summary>
|
||||
Timeout = 0x102,
|
||||
|
||||
/// <summary>
|
||||
/// The function has failed. To get extended error information, call GetLastError.
|
||||
/// </summary>
|
||||
WAIT_FAILED = 0xFFFFFFF,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a thread that runs in the virtual address space of another process. Use the CreateRemoteThreadEx function
|
||||
|
|
@ -336,23 +588,23 @@ namespace Dalamud.Injector
|
|||
/// </summary>
|
||||
/// <param name="hProcess">
|
||||
/// A handle to the process in which the thread is to be created. The handle must have the PROCESS_CREATE_THREAD,
|
||||
/// PROCESS_QUERY_INFORMATION, PROCESS_VM_OPERATION, PROCESS_VM_WRITE, and PROCESS_VM_READ access rights, and may fail
|
||||
/// without these rights on certain platforms. For more information, see Process Security and Access Rights.
|
||||
/// PROCESS_QUERY_INFORMATION, PROCESS_VM_OPERATION, PROCESS_VM_WRITE, and PROCESS_VM_READ access rights, and may fail without
|
||||
/// these rights on certain platforms. For more information, see Process Security and Access Rights.
|
||||
/// </param>
|
||||
/// <param name="lpThreadAttributes">
|
||||
/// A pointer to a SECURITY_ATTRIBUTES structure that specifies a security descriptor for the new thread and determines
|
||||
/// whether child processes can inherit the returned handle. If lpThreadAttributes is NULL, the thread gets a default
|
||||
/// security descriptor and the handle cannot be inherited. The access control lists (ACL) in the default security descriptor
|
||||
/// for a thread come from the primary token of the creator.
|
||||
/// A pointer to a SECURITY_ATTRIBUTES structure that specifies a security descriptor for the new thread and determines whether
|
||||
/// child processes can inherit the returned handle. If lpThreadAttributes is NULL, the thread gets a default security descriptor
|
||||
/// and the handle cannot be inherited. The access control lists (ACL) in the default security descriptor for a thread come from
|
||||
/// the primary token of the creator.
|
||||
/// </param>
|
||||
/// <param name="dwStackSize">
|
||||
/// The initial size of the stack, in bytes. The system rounds this value to the nearest page. If this parameter is
|
||||
/// 0 (zero), the new thread uses the default size for the executable. For more information, see Thread Stack Size.
|
||||
/// The initial size of the stack, in bytes. The system rounds this value to the nearest page. If this parameter is 0 (zero), the
|
||||
/// new thread uses the default size for the executable. For more information, see Thread Stack Size.
|
||||
/// </param>
|
||||
/// <param name="lpStartAddress">
|
||||
/// A pointer to the application-defined function of type LPTHREAD_START_ROUTINE to be executed by the thread and
|
||||
/// represents the starting address of the thread in the remote process. The function must exist in the remote process.
|
||||
/// For more information, see ThreadProc.
|
||||
/// A pointer to the application-defined function of type LPTHREAD_START_ROUTINE to be executed by the thread and represents the
|
||||
/// starting address of the thread in the remote process. The function must exist in the remote process. For more information,
|
||||
/// see ThreadProc.
|
||||
/// </param>
|
||||
/// <param name="lpParameter">
|
||||
/// A pointer to a variable to be passed to the thread function.
|
||||
|
|
@ -361,92 +613,43 @@ namespace Dalamud.Injector
|
|||
/// The flags that control the creation of the thread.
|
||||
/// </param>
|
||||
/// <param name="lpThreadId">
|
||||
/// A pointer to a variable that receives the thread identifier. If this parameter is NULL, the thread identifier is
|
||||
/// not returned.
|
||||
/// A pointer to a variable that receives the thread identifier. If this parameter is NULL, the thread identifier is not returned.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// If the function succeeds, the return value is a handle to the new thread. If the function fails, the return value
|
||||
/// is NULL.To get extended error information, call GetLastError. Note that CreateRemoteThread may succeed even if
|
||||
/// lpStartAddress points to data, code, or is not accessible. If the start address is invalid when the thread runs,
|
||||
/// an exception occurs, and the thread terminates. Thread termination due to a invalid start address is handled as
|
||||
/// an error exit for the thread's process. This behavior is similar to the asynchronous nature of CreateProcess, where
|
||||
/// the process is created even if it refers to invalid or missing dynamic-link libraries (DLL).
|
||||
/// If the function succeeds, the return value is a handle to the new thread. If the function fails, the return value is
|
||||
/// NULL.To get extended error information, call GetLastError. Note that CreateRemoteThread may succeed even if lpStartAddress
|
||||
/// points to data, code, or is not accessible. If the start address is invalid when the thread runs, an exception occurs, and
|
||||
/// the thread terminates. Thread termination due to a invalid start address is handled as an error exit for the thread's process.
|
||||
/// This behavior is similar to the asynchronous nature of CreateProcess, where the process is created even if it refers to
|
||||
/// invalid or missing dynamic-link libraries (DLL).
|
||||
/// </returns>
|
||||
[DllImport("kernel32.dll")]
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
public static extern IntPtr CreateRemoteThread(
|
||||
IntPtr hProcess,
|
||||
IntPtr lpThreadAttributes,
|
||||
uint dwStackSize,
|
||||
UIntPtr dwStackSize,
|
||||
IntPtr lpStartAddress,
|
||||
IntPtr lpParameter,
|
||||
uint dwCreationFlags,
|
||||
IntPtr lpThreadId);
|
||||
CreateThreadFlags dwCreationFlags,
|
||||
out uint lpThreadId);
|
||||
|
||||
/// <summary>
|
||||
/// See https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-getmodulehandlew.
|
||||
/// Retrieves a module handle for the specified module. The module must have been loaded by the calling process. To
|
||||
/// avoid the race conditions described in the Remarks section, use the GetModuleHandleEx function.
|
||||
/// Retrieves the termination status of the specified thread.
|
||||
/// </summary>
|
||||
/// <param name="lpModuleName">
|
||||
/// The name of the loaded module (either a .dll or .exe file). If the file name extension is omitted, the default library
|
||||
/// extension .dll is appended. The file name string can include a trailing point character (.) to indicate that the
|
||||
/// module name has no extension. The string does not have to specify a path. When specifying a path, be sure to use
|
||||
/// backslashes (\), not forward slashes (/). The name is compared (case independently) to the names of modules currently
|
||||
/// mapped into the address space of the calling process. If this parameter is NULL, GetModuleHandle returns a handle
|
||||
/// to the file used to create the calling process (.exe file). The GetModuleHandle function does not retrieve handles
|
||||
/// for modules that were loaded using the LOAD_LIBRARY_AS_DATAFILE flag.For more information, see LoadLibraryEx.
|
||||
/// <param name="hThread">
|
||||
/// A handle to the thread. The handle must have the THREAD_QUERY_INFORMATION or THREAD_QUERY_LIMITED_INFORMATION
|
||||
/// access right.For more information, see Thread Security and Access Rights.
|
||||
/// </param>
|
||||
/// <param name="lpExitCode">
|
||||
/// A pointer to a variable to receive the thread termination status.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// If the function succeeds, the return value is a handle to the specified module. If the function fails, the return
|
||||
/// value is NULL.To get extended error information, call GetLastError.
|
||||
/// </returns>
|
||||
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
|
||||
public static extern IntPtr GetModuleHandle(string lpModuleName);
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves the address of an exported function or variable from the specified dynamic-link library (DLL).
|
||||
/// </summary>
|
||||
/// <param name="hModule">
|
||||
/// A handle to the DLL module that contains the function or variable. The LoadLibrary, LoadLibraryEx, LoadPackagedLibrary,
|
||||
/// or GetModuleHandle function returns this handle. The GetProcAddress function does not retrieve addresses from modules
|
||||
/// that were loaded using the LOAD_LIBRARY_AS_DATAFILE flag.For more information, see LoadLibraryEx.
|
||||
/// </param>
|
||||
/// <param name="procName">
|
||||
/// The function or variable name, or the function's ordinal value. If this parameter is an ordinal value, it must be
|
||||
/// in the low-order word; the high-order word must be zero.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// If the function succeeds, the return value is the address of the exported function or variable. If the function
|
||||
/// fails, the return value is NULL.To get extended error information, call GetLastError.
|
||||
/// </returns>
|
||||
[DllImport("kernel32", CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError = true)]
|
||||
public static extern IntPtr GetProcAddress(IntPtr hModule, string procName);
|
||||
|
||||
/// <summary>
|
||||
/// See https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-openprocess.
|
||||
/// Opens an existing local process object.
|
||||
/// </summary>
|
||||
/// <param name="processAccess">
|
||||
/// The access to the process object. This access right is checked against the security descriptor for the process.
|
||||
/// This parameter can be one or more of the process access rights. If the caller has enabled the SeDebugPrivilege
|
||||
/// privilege, the requested access is granted regardless of the contents of the security descriptor.
|
||||
/// </param>
|
||||
/// <param name="bInheritHandle">
|
||||
/// If this value is TRUE, processes created by this process will inherit the handle. Otherwise, the processes do
|
||||
/// not inherit this handle.
|
||||
/// </param>
|
||||
/// <param name="processId">
|
||||
/// The identifier of the local process to be opened.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// If the function succeeds, the return value is an open handle to the specified process. If the function fails, the
|
||||
/// return value is NULL.To get extended error information, call GetLastError.
|
||||
/// If the function succeeds, the return value is nonzero. If the function fails, the return value is zero. To get
|
||||
/// extended error information, call GetLastError.
|
||||
/// </returns>
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
public static extern IntPtr OpenProcess(
|
||||
ProcessAccessFlags processAccess,
|
||||
bool bInheritHandle,
|
||||
int processId);
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
public static extern bool GetExitCodeThread(IntPtr hThread, out uint lpExitCode);
|
||||
|
||||
/// <summary>
|
||||
/// See https://docs.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-virtualallocex.
|
||||
|
|
@ -530,6 +733,27 @@ namespace Dalamud.Injector
|
|||
int dwSize,
|
||||
AllocationType dwFreeType);
|
||||
|
||||
/// <summary>
|
||||
/// Waits until the specified object is in the signaled state or the time-out interval elapses. To enter an alertable wait
|
||||
/// state, use the WaitForSingleObjectEx function.To wait for multiple objects, use WaitForMultipleObjects.
|
||||
/// </summary>
|
||||
/// <param name="hHandle">
|
||||
/// A handle to the object. For a list of the object types whose handles can be specified, see the following Remarks section.
|
||||
/// If this handle is closed while the wait is still pending, the function's behavior is undefined. The handle must have the
|
||||
/// SYNCHRONIZE access right. For more information, see Standard Access Rights.
|
||||
/// </param>
|
||||
/// <param name="dwMilliseconds">
|
||||
/// The time-out interval, in milliseconds. If a nonzero value is specified, the function waits until the object is signaled
|
||||
/// or the interval elapses. If dwMilliseconds is zero, the function does not enter a wait state if the object is not signaled;
|
||||
/// it always returns immediately. If dwMilliseconds is INFINITE, the function will return only when the object is signaled.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// If the function succeeds, the return value indicates the event that caused the function to return.
|
||||
/// It can be one of the WaitResult values.
|
||||
/// </returns>
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
public static extern uint WaitForSingleObject(IntPtr hHandle, uint dwMilliseconds);
|
||||
|
||||
/// <summary>
|
||||
/// Writes data to an area of memory in a specified process. The entire area to be written to must be accessible or
|
||||
/// the operation fails.
|
||||
|
|
|
|||
|
|
@ -1,208 +0,0 @@
|
|||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Windows.Forms;
|
||||
|
||||
using EasyHook;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Dalamud.Injector
|
||||
{
|
||||
/// <summary>
|
||||
/// Application entrypoint.
|
||||
/// </summary>
|
||||
internal static class Program
|
||||
{
|
||||
private static Process process = null;
|
||||
|
||||
private static void Main(string[] args)
|
||||
{
|
||||
AppDomain.CurrentDomain.UnhandledException += (sender, eventArgs) =>
|
||||
{
|
||||
File.WriteAllText("InjectorException.txt", eventArgs.ExceptionObject.ToString());
|
||||
#if !DEBUG
|
||||
MessageBox.Show("Failed to inject the XIVLauncher in-game addon.\nPlease try restarting your game and your PC.\nIf this keeps happening, please report this error.", "XIVLauncher Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||
#else
|
||||
MessageBox.Show("Couldn't inject.\nMake sure that Dalamud was not injected into your target process as a release build before and that the target process can be accessed with VM_WRITE permissions.\n\n" + eventArgs.ExceptionObject, "Debug Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||
#endif
|
||||
Environment.Exit(0);
|
||||
};
|
||||
|
||||
var pid = -1;
|
||||
if (args.Length >= 1)
|
||||
{
|
||||
pid = int.Parse(args[0]);
|
||||
}
|
||||
|
||||
switch (pid)
|
||||
{
|
||||
case -1:
|
||||
process = Process.GetProcessesByName("ffxiv_dx11")[0];
|
||||
break;
|
||||
case -2:
|
||||
process = Process.Start(
|
||||
"C:\\Program Files (x86)\\SquareEnix\\FINAL FANTASY XIV - A Realm Reborn\\game\\ffxiv_dx11.exe",
|
||||
"DEV.TestSID=0 DEV.UseSqPack=1 DEV.DataPathType=1 DEV.LobbyHost01=127.0.0.1 DEV.LobbyPort01=54994 DEV.LobbyHost02=127.0.0.1 DEV.LobbyPort02=54994 DEV.LobbyHost03=127.0.0.1 DEV.LobbyPort03=54994 DEV.LobbyHost04=127.0.0.1 DEV.LobbyPort04=54994 DEV.LobbyHost05=127.0.0.1 DEV.LobbyPort05=54994 DEV.LobbyHost06=127.0.0.1 DEV.LobbyPort06=54994 DEV.LobbyHost07=127.0.0.1 DEV.LobbyPort07=54994 DEV.LobbyHost08=127.0.0.1 DEV.LobbyPort08=54994 SYS.Region=0 language=1 version=1.0.0.0 DEV.MaxEntitledExpansionID=2 DEV.GMServerHost=127.0.0.1 DEV.GameQuitMessageBox=0");
|
||||
Thread.Sleep(1000);
|
||||
break;
|
||||
default:
|
||||
process = Process.GetProcessById(pid);
|
||||
break;
|
||||
}
|
||||
|
||||
DalamudStartInfo startInfo;
|
||||
if (args.Length <= 1)
|
||||
{
|
||||
startInfo = GetDefaultStartInfo();
|
||||
Console.WriteLine("\nA Dalamud start info was not found in the program arguments. One has been generated for you.");
|
||||
Console.WriteLine("\nCopy the following contents into the program arguments:");
|
||||
Console.WriteLine();
|
||||
Console.WriteLine(Convert.ToBase64String(Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(startInfo))));
|
||||
}
|
||||
else
|
||||
{
|
||||
startInfo = JsonConvert.DeserializeObject<DalamudStartInfo>(Encoding.UTF8.GetString(Convert.FromBase64String(args[1])));
|
||||
}
|
||||
|
||||
startInfo.WorkingDirectory = Directory.GetCurrentDirectory();
|
||||
|
||||
// Seems to help with the STATUS_INTERNAL_ERROR condition
|
||||
Thread.Sleep(1000);
|
||||
|
||||
// Thread.Sleep(10000);
|
||||
|
||||
// Inject to process
|
||||
Inject(process, startInfo);
|
||||
|
||||
Thread.Sleep(1000);
|
||||
|
||||
#if DEBUG
|
||||
// Inject exception handler
|
||||
// NativeInject(process);
|
||||
#endif
|
||||
}
|
||||
|
||||
private static void Inject(Process process, DalamudStartInfo info)
|
||||
{
|
||||
Console.WriteLine($"Injecting to {process.Id}");
|
||||
|
||||
// File check
|
||||
var libPath = Path.GetFullPath("Dalamud.dll");
|
||||
if (!File.Exists(libPath))
|
||||
{
|
||||
Console.WriteLine($"Can't find a dll on {libPath}");
|
||||
return;
|
||||
}
|
||||
|
||||
RemoteHooking.Inject(process.Id, InjectionOptions.DoNotRequireStrongName, libPath, libPath, info);
|
||||
|
||||
Console.WriteLine("Injected");
|
||||
}
|
||||
|
||||
private static void NativeInject(Process process)
|
||||
{
|
||||
var libPath = Path.GetFullPath("DalamudDebugStub.dll");
|
||||
|
||||
var pathBytes = Encoding.Unicode.GetBytes(libPath);
|
||||
var len = pathBytes.Length + 1;
|
||||
|
||||
Console.WriteLine($"Injecting {libPath}...");
|
||||
|
||||
var handle = NativeFunctions.OpenProcess(
|
||||
NativeFunctions.ProcessAccessFlags.AllAccess,
|
||||
false,
|
||||
process.Id);
|
||||
|
||||
if (handle == IntPtr.Zero)
|
||||
{
|
||||
throw new Win32Exception(Marshal.GetLastWin32Error(), "Could not OpenProcess");
|
||||
}
|
||||
|
||||
var dllMem = NativeFunctions.VirtualAllocEx(
|
||||
handle,
|
||||
IntPtr.Zero,
|
||||
len,
|
||||
NativeFunctions.AllocationType.Commit,
|
||||
NativeFunctions.MemoryProtection.ReadWrite);
|
||||
|
||||
if (dllMem == IntPtr.Zero)
|
||||
{
|
||||
throw new Win32Exception(Marshal.GetLastWin32Error(), $"Could not alloc memory {Marshal.GetLastWin32Error():X}");
|
||||
}
|
||||
|
||||
Console.WriteLine($"dll path at {dllMem.ToInt64():X}");
|
||||
|
||||
if (!NativeFunctions.WriteProcessMemory(
|
||||
handle,
|
||||
dllMem,
|
||||
pathBytes,
|
||||
len,
|
||||
out var bytesWritten))
|
||||
{
|
||||
throw new Win32Exception(Marshal.GetLastWin32Error(), "Could not write DLL");
|
||||
}
|
||||
|
||||
Console.WriteLine($"Wrote {bytesWritten}");
|
||||
|
||||
var kernel32 = NativeFunctions.GetModuleHandle("Kernel32.dll");
|
||||
var loadLibA = NativeFunctions.GetProcAddress(kernel32, "LoadLibraryW");
|
||||
|
||||
var remoteThread = NativeFunctions.CreateRemoteThread(
|
||||
handle,
|
||||
IntPtr.Zero,
|
||||
0,
|
||||
loadLibA,
|
||||
dllMem,
|
||||
0,
|
||||
IntPtr.Zero);
|
||||
|
||||
if (remoteThread == IntPtr.Zero)
|
||||
{
|
||||
throw new Win32Exception(Marshal.GetLastWin32Error(), $"Could not CreateRemoteThread");
|
||||
}
|
||||
|
||||
/*
|
||||
TODO kill myself
|
||||
VirtualFreeEx(
|
||||
handle,
|
||||
dllMem,
|
||||
0,
|
||||
AllocationType.Release);
|
||||
*/
|
||||
|
||||
NativeFunctions.CloseHandle(remoteThread);
|
||||
NativeFunctions.CloseHandle(handle);
|
||||
}
|
||||
|
||||
private static DalamudStartInfo GetDefaultStartInfo()
|
||||
{
|
||||
var ffxivDir = Path.GetDirectoryName(process.MainModule.FileName);
|
||||
var startInfo = new DalamudStartInfo
|
||||
{
|
||||
WorkingDirectory = null,
|
||||
ConfigurationPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "XIVLauncher", "dalamudConfig.json"),
|
||||
PluginDirectory = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "XIVLauncher", "installedPlugins"),
|
||||
DefaultPluginDirectory = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "XIVLauncher", "devPlugins"),
|
||||
AssetDirectory = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "XIVLauncher", "dalamudAssets"),
|
||||
|
||||
GameVersion = File.ReadAllText(Path.Combine(ffxivDir, "ffxivgame.ver")),
|
||||
Language = ClientLanguage.English,
|
||||
};
|
||||
|
||||
Console.WriteLine("Creating a StartInfo with:\n" +
|
||||
$"ConfigurationPath: {startInfo.ConfigurationPath}\n" +
|
||||
$"PluginDirectory: {startInfo.PluginDirectory}\n" +
|
||||
$"DefaultPluginDirectory: {startInfo.DefaultPluginDirectory}\n" +
|
||||
$"Language: {startInfo.Language}\n" +
|
||||
$"GameVersion: {startInfo.GameVersion}\n" +
|
||||
$"OptOutMbCollection: {startInfo.OptOutMbCollection}\n" +
|
||||
$"AssetDirectory: {startInfo.AssetDirectory}");
|
||||
|
||||
return startInfo;
|
||||
}
|
||||
}
|
||||
}
|
||||
79
Dalamud.Injector/RemotePinnedData.cs
Normal file
79
Dalamud.Injector/RemotePinnedData.cs
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
using static Dalamud.Injector.NativeFunctions;
|
||||
|
||||
namespace Dalamud.Injector
|
||||
{
|
||||
/// <summary>
|
||||
/// Pin an arbitrary string to a remote process.
|
||||
/// </summary>
|
||||
internal class RemotePinnedData : IDisposable
|
||||
{
|
||||
private readonly Process process;
|
||||
private readonly byte[] data;
|
||||
private readonly IntPtr allocAddr;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="RemotePinnedData"/> class.
|
||||
/// </summary>
|
||||
/// <param name="process">Process to write in.</param>
|
||||
/// <param name="data">Data to write.</param>
|
||||
public unsafe RemotePinnedData(Process process, byte[] data)
|
||||
{
|
||||
this.process = process;
|
||||
this.data = data;
|
||||
|
||||
this.allocAddr = VirtualAllocEx(
|
||||
this.process.Handle,
|
||||
IntPtr.Zero,
|
||||
this.data.Length,
|
||||
AllocationType.Commit,
|
||||
MemoryProtection.ReadWrite);
|
||||
|
||||
if (this.allocAddr == IntPtr.Zero || Marshal.GetLastWin32Error() != 0)
|
||||
{
|
||||
throw new Exception("Error allocating memory");
|
||||
}
|
||||
|
||||
var result = WriteProcessMemory(
|
||||
this.process.Handle,
|
||||
this.allocAddr,
|
||||
this.data,
|
||||
this.data.Length,
|
||||
out _);
|
||||
|
||||
if (!result || Marshal.GetLastWin32Error() != 0)
|
||||
{
|
||||
throw new Exception("Error writing memory");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the address of the pinned data.
|
||||
/// </summary>
|
||||
public IntPtr Address => this.allocAddr;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Dispose()
|
||||
{
|
||||
if (this.allocAddr == IntPtr.Zero)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var result = VirtualFreeEx(
|
||||
this.process.Handle,
|
||||
this.allocAddr,
|
||||
0,
|
||||
AllocationType.Release);
|
||||
|
||||
if (!result || Marshal.GetLastWin32Error() != 0)
|
||||
{
|
||||
throw new Exception("Error freeing memory");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,96 +1,70 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="..\packages\xunit.runner.console.2.4.1\build\xunit.runner.console.props" Condition="Exists('..\packages\xunit.runner.console.2.4.1\build\xunit.runner.console.props')" />
|
||||
<Import Project="..\packages\xunit.runner.visualstudio.2.4.3\build\net452\xunit.runner.visualstudio.props" Condition="Exists('..\packages\xunit.runner.visualstudio.2.4.3\build\net452\xunit.runner.visualstudio.props')" />
|
||||
<Import Project="..\packages\xunit.core.2.4.1\build\xunit.core.props" Condition="Exists('..\packages\xunit.core.2.4.1\build\xunit.core.props')" />
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{C8004563-1806-4329-844F-0EF6274291FC}</ProjectGuid>
|
||||
<ProjectTypeGuids>{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>Dalamud.Test</RootNamespace>
|
||||
<AssemblyName>Dalamud.Test</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Xml" />
|
||||
<Reference Include="xunit.abstractions, Version=2.0.0.0, Culture=neutral, PublicKeyToken=8d05b1bb7a6fdb6c">
|
||||
<HintPath>..\packages\xunit.abstractions.2.0.3\lib\net35\xunit.abstractions.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="xunit.assert, Version=2.4.1.0, Culture=neutral, PublicKeyToken=8d05b1bb7a6fdb6c">
|
||||
<HintPath>..\packages\xunit.assert.2.4.1\lib\netstandard1.1\xunit.assert.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="xunit.core, Version=2.4.1.0, Culture=neutral, PublicKeyToken=8d05b1bb7a6fdb6c">
|
||||
<HintPath>..\packages\xunit.extensibility.core.2.4.1\lib\net452\xunit.core.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="xunit.execution.desktop, Version=2.4.1.0, Culture=neutral, PublicKeyToken=8d05b1bb7a6fdb6c">
|
||||
<HintPath>..\packages\xunit.extensibility.execution.2.4.1\lib\net452\xunit.execution.desktop.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="LocalizationTests.cs" />
|
||||
<Compile Include="Game\Text\Sanitizer\SanitizerTests.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Dalamud\Dalamud.csproj">
|
||||
<Project>{b92dab43-2279-4a2c-96e3-d9d5910edbea}</Project>
|
||||
<Name>Dalamud</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Analyzer Include="..\packages\xunit.analyzers.0.10.0\analyzers\dotnet\cs\xunit.analyzers.dll" />
|
||||
</ItemGroup>
|
||||
<ItemGroup />
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
<PropertyGroup>
|
||||
<ErrorText>This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105.The missing file is {0}.</ErrorText>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup Label="Target">
|
||||
<TargetFramework>net5.0-windows</TargetFramework>
|
||||
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<Platforms>x64;AnyCPU</Platforms>
|
||||
<LangVersion>9.0</LangVersion>
|
||||
</PropertyGroup>
|
||||
<Error Condition="!Exists('..\packages\xunit.core.2.4.1\build\xunit.core.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\xunit.core.2.4.1\build\xunit.core.props'))" />
|
||||
<Error Condition="!Exists('..\packages\xunit.core.2.4.1\build\xunit.core.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\xunit.core.2.4.1\build\xunit.core.targets'))" />
|
||||
<Error Condition="!Exists('..\packages\xunit.runner.visualstudio.2.4.3\build\net452\xunit.runner.visualstudio.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\xunit.runner.visualstudio.2.4.3\build\net452\xunit.runner.visualstudio.props'))" />
|
||||
<Error Condition="!Exists('..\packages\xunit.runner.console.2.4.1\build\xunit.runner.console.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\xunit.runner.console.2.4.1\build\xunit.runner.console.props'))" />
|
||||
</Target>
|
||||
<Import Project="..\packages\xunit.core.2.4.1\build\xunit.core.targets" Condition="Exists('..\packages\xunit.core.2.4.1\build\xunit.core.targets')" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
</Target>
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
||||
|
||||
<PropertyGroup Label="Feature">
|
||||
<RootNamespace>Dalamud.Test</RootNamespace>
|
||||
<AssemblyTitle>Dalamud.Test</AssemblyTitle>
|
||||
<AssemblyName>Dalamud.Test</AssemblyName>
|
||||
<Product>Dalamud.Test</Product>
|
||||
<Description>Unit tests for Dalamud</Description>
|
||||
<Company>goatcorp</Company>
|
||||
<Copyright>Copyright © goatcorp 2021</Copyright>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Label="Output">
|
||||
<OutputType>Library</OutputType>
|
||||
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
|
||||
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Label="Configuration">
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Label="Configuration" Condition=" '$(Configuration)' == 'Debug' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Label="Configuration" Condition=" '$(Configuration)' == 'Release' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Dalamud\Dalamud.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.10.0" />
|
||||
<PackageReference Include="xunit" Version="2.4.1" />
|
||||
<PackageReference Include="xunit.abstractions" Version="2.0.3" />
|
||||
<PackageReference Include="xunit.analyzers" Version="0.10.0" />
|
||||
<PackageReference Include="xunit.assert" Version="2.4.1" />
|
||||
<PackageReference Include="xunit.core" Version="2.4.1" />
|
||||
<PackageReference Include="xunit.extensibility.core" Version="2.4.1" />
|
||||
<PackageReference Include="xunit.extensibility.execution" Version="2.4.1" />
|
||||
<PackageReference Include="xunit.runner.console" Version="2.4.1">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
|
|
|||
58
Dalamud.Test/Game/GameVersionTests.cs
Normal file
58
Dalamud.Test/Game/GameVersionTests.cs
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
using Dalamud.Game;
|
||||
using Xunit;
|
||||
|
||||
namespace Dalamud.Test.Game
|
||||
{
|
||||
public class GameVersionTests
|
||||
{
|
||||
[Theory]
|
||||
[InlineData("any", "any")]
|
||||
[InlineData("2021.01.01.0000.0000", "2021.01.01.0000.0000")]
|
||||
public void VersionEquality(string ver1, string ver2)
|
||||
{
|
||||
var v1 = GameVersion.Parse(ver1);
|
||||
var v2 = GameVersion.Parse(ver2);
|
||||
|
||||
Assert.Equal(v1, v2);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("2020.06.15.0000.0000", "any")]
|
||||
[InlineData("2021.01.01.0000.0000", "2021.01.01.0000.0001")]
|
||||
[InlineData("2021.01.01.0000.0000", "2021.01.01.0001.0000")]
|
||||
[InlineData("2021.01.01.0000.0000", "2021.01.02.0000.0000")]
|
||||
[InlineData("2021.01.01.0000.0000", "2021.02.01.0000.0000")]
|
||||
[InlineData("2021.01.01.0000.0000", "2022.01.01.0000.0000")]
|
||||
public void VersionComparison(string ver1, string ver2)
|
||||
{
|
||||
var v1 = GameVersion.Parse(ver1);
|
||||
var v2 = GameVersion.Parse(ver2);
|
||||
|
||||
Assert.True(v1.CompareTo(v2) < 0);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("2020.06.15.0000.0000")]
|
||||
[InlineData("2021.01.01.0000")]
|
||||
[InlineData("2021.01.01")]
|
||||
[InlineData("2021.01")]
|
||||
[InlineData("2021")]
|
||||
public void VersionConstructor(string ver)
|
||||
{
|
||||
var v = GameVersion.Parse(ver);
|
||||
|
||||
Assert.True(v != null);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("2020.06.15.0000.0000.0000")]
|
||||
[InlineData("")]
|
||||
public void VersionConstructorInvalid(string ver)
|
||||
{
|
||||
var result = GameVersion.TryParse(ver, out var v);
|
||||
|
||||
Assert.False(result);
|
||||
Assert.Null(v);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,29 +1,29 @@
|
|||
// ReSharper disable StringLiteralTypo
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Xunit;
|
||||
|
||||
namespace Dalamud.Test.Game.Text.Sanitizer {
|
||||
|
||||
public class SanitizerTests {
|
||||
// ReSharper disable StringLiteralTypo
|
||||
namespace Dalamud.Test.Game.Text.Sanitizer
|
||||
{
|
||||
public class SanitizerTests
|
||||
{
|
||||
private global::Dalamud.Game.Text.Sanitizer.Sanitizer sanitizer;
|
||||
|
||||
[Theory]
|
||||
[InlineData( ClientLanguage.English, "Pixie Cotton Hood of Healing", "Pixie Cotton Hood of Healing" )]
|
||||
[InlineData( ClientLanguage.Japanese, "アラガントームストーン:真理", "アラガントームストーン:真理" )]
|
||||
[InlineData( ClientLanguage.German, "Anemos-Pan\x02\x16\x01\x03zer\x02\x16\x01\x03hand\x02\x16\x01\x03schu\x02\x16\x01\x03he des Drachenbluts", "Anemos-Panzerhandschuhe des Drachenbluts" )]
|
||||
[InlineData( ClientLanguage.German, "Bienen-Spatha †", "Bienen-Spatha" )]
|
||||
[InlineData( ClientLanguage.French, "Le Diademe\x02\x1D\x01\x03: terrains de chasse|Le Diademe\x02\x1D\x01\x03: terrains de chasse", "Le Diademe: terrains de chasse|Le Diademe: terrains de chasse" )]
|
||||
[InlineData( ClientLanguage.French, "Cuir de bœuf", "Cuir de boeuf" )]
|
||||
public void StringsAreSanitizedCorrectly(
|
||||
ClientLanguage clientLanguage, string unsanitizedString, string sanitizedString)
|
||||
[InlineData(ClientLanguage.English, "Pixie Cotton Hood of Healing", "Pixie Cotton Hood of Healing")]
|
||||
[InlineData(ClientLanguage.Japanese, "アラガントームストーン:真理", "アラガントームストーン:真理")]
|
||||
[InlineData(ClientLanguage.German, "Anemos-Pan\x02\x16\x01\x03zer\x02\x16\x01\x03hand\x02\x16\x01\x03schu\x02\x16\x01\x03he des Drachenbluts", "Anemos-Panzerhandschuhe des Drachenbluts")]
|
||||
[InlineData(ClientLanguage.German, "Bienen-Spatha †", "Bienen-Spatha")]
|
||||
[InlineData(ClientLanguage.French, "Le Diademe\x02\x1D\x01\x03: terrains de chasse|Le Diademe\x02\x1D\x01\x03: terrains de chasse", "Le Diademe: terrains de chasse|Le Diademe: terrains de chasse")]
|
||||
[InlineData(ClientLanguage.French, "Cuir de bœuf", "Cuir de boeuf")]
|
||||
public void StringsAreSanitizedCorrectly(ClientLanguage clientLanguage, string unsanitizedString, string sanitizedString)
|
||||
{
|
||||
var sanitizedStrings = new List<string> {unsanitizedString};
|
||||
var sanitizedStrings = new List<string> { unsanitizedString };
|
||||
|
||||
sanitizer = new global::Dalamud.Game.Text.Sanitizer.Sanitizer(clientLanguage);
|
||||
Assert.Equal(sanitizedString, sanitizer.Sanitize(unsanitizedString));
|
||||
Assert.Equal(sanitizedString, sanitizer.Sanitize(sanitizedStrings).First());
|
||||
|
||||
|
||||
sanitizer = new global::Dalamud.Game.Text.Sanitizer.Sanitizer(ClientLanguage.English);
|
||||
Assert.Equal(sanitizedString, sanitizer.Sanitize(unsanitizedString, clientLanguage));
|
||||
Assert.Equal(sanitizedString, sanitizer.Sanitize(sanitizedStrings, clientLanguage).First());
|
||||
|
|
|
|||
|
|
@ -1,20 +1,24 @@
|
|||
using System.IO;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using Xunit;
|
||||
|
||||
namespace Dalamud.Test {
|
||||
public class LocalizationTests {
|
||||
namespace Dalamud.Test
|
||||
{
|
||||
public class LocalizationTests
|
||||
{
|
||||
private readonly Localization localization;
|
||||
private string currentLangCode;
|
||||
|
||||
public LocalizationTests() {
|
||||
|
||||
public LocalizationTests()
|
||||
{
|
||||
var workingDir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
|
||||
this.localization = new Localization(workingDir, "dalamud_");
|
||||
this.localization.OnLocalizationChanged += code => this.currentLangCode = code;
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SetupWithFallbacks_EventInvoked() {
|
||||
public void SetupWithFallbacks_EventInvoked()
|
||||
{
|
||||
this.localization.SetupWithFallbacks();
|
||||
Assert.Equal("en", this.currentLangCode);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,35 +0,0 @@
|
|||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("Dalamud.Test")]
|
||||
[assembly: AssemblyDescription("Unit tests for Dalamud")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("goatcorp")]
|
||||
[assembly: AssemblyProduct("Dalamud.Test")]
|
||||
[assembly: AssemblyCopyright("Copyright © goatcorp 2021")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("C8004563-1806-4329-844F-0EF6274291FC")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="xunit" version="2.4.1" targetFramework="net472" />
|
||||
<package id="xunit.abstractions" version="2.0.3" targetFramework="net472" />
|
||||
<package id="xunit.analyzers" version="0.10.0" targetFramework="net472" />
|
||||
<package id="xunit.assert" version="2.4.1" targetFramework="net472" />
|
||||
<package id="xunit.core" version="2.4.1" targetFramework="net472" />
|
||||
<package id="xunit.extensibility.core" version="2.4.1" targetFramework="net472" />
|
||||
<package id="xunit.extensibility.execution" version="2.4.1" targetFramework="net472" />
|
||||
<package id="xunit.runner.console" version="2.4.1" targetFramework="net472" developmentDependency="true" />
|
||||
<package id="xunit.runner.visualstudio" version="2.4.3" targetFramework="net472" developmentDependency="true" />
|
||||
</packages>
|
||||
223
Dalamud.sln
223
Dalamud.sln
|
|
@ -1,137 +1,162 @@
|
|||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 16
|
||||
VisualStudioVersion = 16.0.29215.179
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.0.31410.414
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{CEF7D22B-CB85-400E-BD64-349A30E3C097}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
.editorconfig = .editorconfig
|
||||
.gitignore = .gitignore
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "build", "build\build.csproj", "{94E5B016-02B1-459B-97D9-E783F28764B2}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Dalamud", "Dalamud\Dalamud.csproj", "{B92DAB43-2279-4A2C-96E3-D9D5910EDBEA}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Dalamud.Boot", "Dalamud.Boot\Dalamud.Boot.vcxproj", "{55198DC3-A03D-408E-A8EB-2077780C8576}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Dalamud.Injector", "Dalamud.Injector\Dalamud.Injector.csproj", "{5B832F73-5F54-4ADC-870F-D0095EF72C9A}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ImGuiScene", "lib\ImGuiScene\ImGuiScene\ImGuiScene.csproj", "{C0E7E797-4FBF-4F46-BC57-463F3719BA7A}"
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Dalamud.Injector.Boot", "Dalamud.Injector.Boot\Dalamud.Injector.Boot.vcxproj", "{8874326B-E755-4D13-90B4-59AB263A3E6B}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SDL2-CS", "lib\ImGuiScene\deps\SDL2-CS\SDL2-CS.csproj", "{85480198-8711-4355-830E-72FD794AD3F6}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ImGui.NET-472", "lib\ImGuiScene\deps\ImGui.NET\src\ImGui.NET-472\ImGui.NET-472.csproj", "{0483026E-C6CE-4B1A-AA68-46544C08140B}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Dalamud.Test", "Dalamud.Test\Dalamud.Test.csproj", "{C8004563-1806-4329-844F-0EF6274291FC}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Interface", "Interface", "{E15BDA6D-E881-4482-94BA-BE5527E917FF}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DalamudDebugStub", "DalamudDebugStub\DalamudDebugStub.vcxproj", "{9FDA9A5C-50C6-4333-8DCE-DFEB89363F2A}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ImGui.NET-472", "lib\ImGuiScene\deps\ImGui.NET\src\ImGui.NET-472\ImGui.NET-472.csproj", "{0483026E-C6CE-4B1A-AA68-46544C08140B}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FFXIVClientStructs", "lib\FFXIVClientStructs\FFXIVClientStructs.csproj", "{3DBAEE68-9D94-4807-BCB1-E42EDD52B489}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ImGuiScene", "lib\ImGuiScene\ImGuiScene\ImGuiScene.csproj", "{C0E7E797-4FBF-4F46-BC57-463F3719BA7A}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dalamud.Test", "Dalamud.Test\Dalamud.Test.csproj", "{C8004563-1806-4329-844F-0EF6274291FC}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SDL2-CS", "lib\ImGuiScene\deps\SDL2-CS\SDL2-CS.csproj", "{2F7FF0A8-B619-4572-86C7-71E46FE22FB8}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Dalamud.CorePlugin", "Dalamud.CorePlugin\Dalamud.CorePlugin.csproj", "{4AFDB34A-7467-4D41-B067-53BC4101D9D0}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FFXIVClientStructs", "lib\FFXIVClientStructs\FFXIVClientStructs\FFXIVClientStructs.csproj", "{C9B87BD7-AF49-41C3-91F1-D550ADEB7833}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FFXIVClientStructs.Common", "lib\FFXIVClientStructs\FFXIVClientStructs.Common\FFXIVClientStructs.Common.csproj", "{F3F0CC3A-DE2E-403F-88B4-B47C62582477}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FFXIVClientStructs.Generators", "lib\FFXIVClientStructs\FFXIVClientStructs.Generators\FFXIVClientStructs.Generators.csproj", "{05AB2F46-268B-4915-806F-DDF813E2D59D}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Debug|x64 = Debug|x64
|
||||
Debug|x86 = Debug|x86
|
||||
Release|Any CPU = Release|Any CPU
|
||||
Release|x64 = Release|x64
|
||||
Release|x86 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{B92DAB43-2279-4A2C-96E3-D9D5910EDBEA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{B92DAB43-2279-4A2C-96E3-D9D5910EDBEA}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{94E5B016-02B1-459B-97D9-E783F28764B2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{94E5B016-02B1-459B-97D9-E783F28764B2}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{94E5B016-02B1-459B-97D9-E783F28764B2}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{94E5B016-02B1-459B-97D9-E783F28764B2}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{94E5B016-02B1-459B-97D9-E783F28764B2}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{94E5B016-02B1-459B-97D9-E783F28764B2}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{94E5B016-02B1-459B-97D9-E783F28764B2}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{94E5B016-02B1-459B-97D9-E783F28764B2}.Release|x64.Build.0 = Release|Any CPU
|
||||
{B92DAB43-2279-4A2C-96E3-D9D5910EDBEA}.Debug|Any CPU.ActiveCfg = Debug|x64
|
||||
{B92DAB43-2279-4A2C-96E3-D9D5910EDBEA}.Debug|Any CPU.Build.0 = Debug|x64
|
||||
{B92DAB43-2279-4A2C-96E3-D9D5910EDBEA}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{B92DAB43-2279-4A2C-96E3-D9D5910EDBEA}.Debug|x64.Build.0 = Debug|x64
|
||||
{B92DAB43-2279-4A2C-96E3-D9D5910EDBEA}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{B92DAB43-2279-4A2C-96E3-D9D5910EDBEA}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{B92DAB43-2279-4A2C-96E3-D9D5910EDBEA}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{B92DAB43-2279-4A2C-96E3-D9D5910EDBEA}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{B92DAB43-2279-4A2C-96E3-D9D5910EDBEA}.Release|Any CPU.ActiveCfg = Release|x64
|
||||
{B92DAB43-2279-4A2C-96E3-D9D5910EDBEA}.Release|Any CPU.Build.0 = Release|x64
|
||||
{B92DAB43-2279-4A2C-96E3-D9D5910EDBEA}.Release|x64.ActiveCfg = Release|x64
|
||||
{B92DAB43-2279-4A2C-96E3-D9D5910EDBEA}.Release|x64.Build.0 = Release|x64
|
||||
{B92DAB43-2279-4A2C-96E3-D9D5910EDBEA}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{B92DAB43-2279-4A2C-96E3-D9D5910EDBEA}.Release|x86.Build.0 = Release|Any CPU
|
||||
{5B832F73-5F54-4ADC-870F-D0095EF72C9A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{5B832F73-5F54-4ADC-870F-D0095EF72C9A}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{55198DC3-A03D-408E-A8EB-2077780C8576}.Debug|Any CPU.ActiveCfg = Debug|x64
|
||||
{55198DC3-A03D-408E-A8EB-2077780C8576}.Debug|Any CPU.Build.0 = Debug|x64
|
||||
{55198DC3-A03D-408E-A8EB-2077780C8576}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{55198DC3-A03D-408E-A8EB-2077780C8576}.Debug|x64.Build.0 = Debug|x64
|
||||
{55198DC3-A03D-408E-A8EB-2077780C8576}.Release|Any CPU.ActiveCfg = Release|x64
|
||||
{55198DC3-A03D-408E-A8EB-2077780C8576}.Release|Any CPU.Build.0 = Release|x64
|
||||
{55198DC3-A03D-408E-A8EB-2077780C8576}.Release|x64.ActiveCfg = Release|x64
|
||||
{55198DC3-A03D-408E-A8EB-2077780C8576}.Release|x64.Build.0 = Release|x64
|
||||
{5B832F73-5F54-4ADC-870F-D0095EF72C9A}.Debug|Any CPU.ActiveCfg = Debug|x64
|
||||
{5B832F73-5F54-4ADC-870F-D0095EF72C9A}.Debug|Any CPU.Build.0 = Debug|x64
|
||||
{5B832F73-5F54-4ADC-870F-D0095EF72C9A}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{5B832F73-5F54-4ADC-870F-D0095EF72C9A}.Debug|x64.Build.0 = Debug|x64
|
||||
{5B832F73-5F54-4ADC-870F-D0095EF72C9A}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{5B832F73-5F54-4ADC-870F-D0095EF72C9A}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{5B832F73-5F54-4ADC-870F-D0095EF72C9A}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{5B832F73-5F54-4ADC-870F-D0095EF72C9A}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{5B832F73-5F54-4ADC-870F-D0095EF72C9A}.Release|Any CPU.ActiveCfg = Release|x64
|
||||
{5B832F73-5F54-4ADC-870F-D0095EF72C9A}.Release|Any CPU.Build.0 = Release|x64
|
||||
{5B832F73-5F54-4ADC-870F-D0095EF72C9A}.Release|x64.ActiveCfg = Release|x64
|
||||
{5B832F73-5F54-4ADC-870F-D0095EF72C9A}.Release|x64.Build.0 = Release|x64
|
||||
{5B832F73-5F54-4ADC-870F-D0095EF72C9A}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{5B832F73-5F54-4ADC-870F-D0095EF72C9A}.Release|x86.Build.0 = Release|Any CPU
|
||||
{C0E7E797-4FBF-4F46-BC57-463F3719BA7A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{C0E7E797-4FBF-4F46-BC57-463F3719BA7A}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{C0E7E797-4FBF-4F46-BC57-463F3719BA7A}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{C0E7E797-4FBF-4F46-BC57-463F3719BA7A}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{C0E7E797-4FBF-4F46-BC57-463F3719BA7A}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{C0E7E797-4FBF-4F46-BC57-463F3719BA7A}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{C0E7E797-4FBF-4F46-BC57-463F3719BA7A}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{C0E7E797-4FBF-4F46-BC57-463F3719BA7A}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{C0E7E797-4FBF-4F46-BC57-463F3719BA7A}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{C0E7E797-4FBF-4F46-BC57-463F3719BA7A}.Release|x64.Build.0 = Release|Any CPU
|
||||
{C0E7E797-4FBF-4F46-BC57-463F3719BA7A}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{C0E7E797-4FBF-4F46-BC57-463F3719BA7A}.Release|x86.Build.0 = Release|Any CPU
|
||||
{85480198-8711-4355-830E-72FD794AD3F6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{85480198-8711-4355-830E-72FD794AD3F6}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{85480198-8711-4355-830E-72FD794AD3F6}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{85480198-8711-4355-830E-72FD794AD3F6}.Debug|x64.Build.0 = Debug|x64
|
||||
{85480198-8711-4355-830E-72FD794AD3F6}.Debug|x86.ActiveCfg = Debug|x86
|
||||
{85480198-8711-4355-830E-72FD794AD3F6}.Debug|x86.Build.0 = Debug|x86
|
||||
{85480198-8711-4355-830E-72FD794AD3F6}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{85480198-8711-4355-830E-72FD794AD3F6}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{85480198-8711-4355-830E-72FD794AD3F6}.Release|x64.ActiveCfg = Release|x64
|
||||
{85480198-8711-4355-830E-72FD794AD3F6}.Release|x64.Build.0 = Release|x64
|
||||
{85480198-8711-4355-830E-72FD794AD3F6}.Release|x86.ActiveCfg = Release|x86
|
||||
{85480198-8711-4355-830E-72FD794AD3F6}.Release|x86.Build.0 = Release|x86
|
||||
{0483026E-C6CE-4B1A-AA68-46544C08140B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{0483026E-C6CE-4B1A-AA68-46544C08140B}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{0483026E-C6CE-4B1A-AA68-46544C08140B}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{0483026E-C6CE-4B1A-AA68-46544C08140B}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{0483026E-C6CE-4B1A-AA68-46544C08140B}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{0483026E-C6CE-4B1A-AA68-46544C08140B}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{0483026E-C6CE-4B1A-AA68-46544C08140B}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{0483026E-C6CE-4B1A-AA68-46544C08140B}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{0483026E-C6CE-4B1A-AA68-46544C08140B}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{0483026E-C6CE-4B1A-AA68-46544C08140B}.Release|x64.Build.0 = Release|Any CPU
|
||||
{0483026E-C6CE-4B1A-AA68-46544C08140B}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{0483026E-C6CE-4B1A-AA68-46544C08140B}.Release|x86.Build.0 = Release|Any CPU
|
||||
{9FDA9A5C-50C6-4333-8DCE-DFEB89363F2A}.Debug|Any CPU.ActiveCfg = Debug|x64
|
||||
{9FDA9A5C-50C6-4333-8DCE-DFEB89363F2A}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{9FDA9A5C-50C6-4333-8DCE-DFEB89363F2A}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{9FDA9A5C-50C6-4333-8DCE-DFEB89363F2A}.Release|Any CPU.ActiveCfg = Release|x64
|
||||
{9FDA9A5C-50C6-4333-8DCE-DFEB89363F2A}.Release|Any CPU.Build.0 = Release|x64
|
||||
{9FDA9A5C-50C6-4333-8DCE-DFEB89363F2A}.Release|x64.ActiveCfg = Release|x64
|
||||
{9FDA9A5C-50C6-4333-8DCE-DFEB89363F2A}.Release|x64.Build.0 = Release|x64
|
||||
{9FDA9A5C-50C6-4333-8DCE-DFEB89363F2A}.Release|x86.ActiveCfg = Release|Win32
|
||||
{9FDA9A5C-50C6-4333-8DCE-DFEB89363F2A}.Release|x86.Build.0 = Release|Win32
|
||||
{3DBAEE68-9D94-4807-BCB1-E42EDD52B489}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{3DBAEE68-9D94-4807-BCB1-E42EDD52B489}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{3DBAEE68-9D94-4807-BCB1-E42EDD52B489}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{3DBAEE68-9D94-4807-BCB1-E42EDD52B489}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{3DBAEE68-9D94-4807-BCB1-E42EDD52B489}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{3DBAEE68-9D94-4807-BCB1-E42EDD52B489}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{3DBAEE68-9D94-4807-BCB1-E42EDD52B489}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{3DBAEE68-9D94-4807-BCB1-E42EDD52B489}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{3DBAEE68-9D94-4807-BCB1-E42EDD52B489}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{3DBAEE68-9D94-4807-BCB1-E42EDD52B489}.Release|x64.Build.0 = Release|Any CPU
|
||||
{3DBAEE68-9D94-4807-BCB1-E42EDD52B489}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{3DBAEE68-9D94-4807-BCB1-E42EDD52B489}.Release|x86.Build.0 = Release|Any CPU
|
||||
{C8004563-1806-4329-844F-0EF6274291FC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{C8004563-1806-4329-844F-0EF6274291FC}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{C8004563-1806-4329-844F-0EF6274291FC}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{C8004563-1806-4329-844F-0EF6274291FC}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{C8004563-1806-4329-844F-0EF6274291FC}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{C8004563-1806-4329-844F-0EF6274291FC}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{C8004563-1806-4329-844F-0EF6274291FC}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{C8004563-1806-4329-844F-0EF6274291FC}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{C8004563-1806-4329-844F-0EF6274291FC}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{C8004563-1806-4329-844F-0EF6274291FC}.Release|x64.Build.0 = Release|Any CPU
|
||||
{C8004563-1806-4329-844F-0EF6274291FC}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{C8004563-1806-4329-844F-0EF6274291FC}.Release|x86.Build.0 = Release|Any CPU
|
||||
{8874326B-E755-4D13-90B4-59AB263A3E6B}.Debug|Any CPU.ActiveCfg = Debug|x64
|
||||
{8874326B-E755-4D13-90B4-59AB263A3E6B}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{8874326B-E755-4D13-90B4-59AB263A3E6B}.Debug|x64.Build.0 = Debug|x64
|
||||
{8874326B-E755-4D13-90B4-59AB263A3E6B}.Release|Any CPU.ActiveCfg = Release|x64
|
||||
{8874326B-E755-4D13-90B4-59AB263A3E6B}.Release|x64.ActiveCfg = Release|x64
|
||||
{8874326B-E755-4D13-90B4-59AB263A3E6B}.Release|x64.Build.0 = Release|x64
|
||||
{C8004563-1806-4329-844F-0EF6274291FC}.Debug|Any CPU.ActiveCfg = Debug|x64
|
||||
{C8004563-1806-4329-844F-0EF6274291FC}.Debug|Any CPU.Build.0 = Debug|x64
|
||||
{C8004563-1806-4329-844F-0EF6274291FC}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{C8004563-1806-4329-844F-0EF6274291FC}.Debug|x64.Build.0 = Debug|x64
|
||||
{C8004563-1806-4329-844F-0EF6274291FC}.Release|Any CPU.ActiveCfg = Release|x64
|
||||
{C8004563-1806-4329-844F-0EF6274291FC}.Release|Any CPU.Build.0 = Release|x64
|
||||
{C8004563-1806-4329-844F-0EF6274291FC}.Release|x64.ActiveCfg = Release|x64
|
||||
{C8004563-1806-4329-844F-0EF6274291FC}.Release|x64.Build.0 = Release|x64
|
||||
{0483026E-C6CE-4B1A-AA68-46544C08140B}.Debug|Any CPU.ActiveCfg = Debug|x64
|
||||
{0483026E-C6CE-4B1A-AA68-46544C08140B}.Debug|Any CPU.Build.0 = Debug|x64
|
||||
{0483026E-C6CE-4B1A-AA68-46544C08140B}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{0483026E-C6CE-4B1A-AA68-46544C08140B}.Debug|x64.Build.0 = Debug|x64
|
||||
{0483026E-C6CE-4B1A-AA68-46544C08140B}.Release|Any CPU.ActiveCfg = Release|x64
|
||||
{0483026E-C6CE-4B1A-AA68-46544C08140B}.Release|Any CPU.Build.0 = Release|x64
|
||||
{0483026E-C6CE-4B1A-AA68-46544C08140B}.Release|x64.ActiveCfg = Release|x64
|
||||
{0483026E-C6CE-4B1A-AA68-46544C08140B}.Release|x64.Build.0 = Release|x64
|
||||
{C0E7E797-4FBF-4F46-BC57-463F3719BA7A}.Debug|Any CPU.ActiveCfg = Debug|x64
|
||||
{C0E7E797-4FBF-4F46-BC57-463F3719BA7A}.Debug|Any CPU.Build.0 = Debug|x64
|
||||
{C0E7E797-4FBF-4F46-BC57-463F3719BA7A}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{C0E7E797-4FBF-4F46-BC57-463F3719BA7A}.Debug|x64.Build.0 = Debug|x64
|
||||
{C0E7E797-4FBF-4F46-BC57-463F3719BA7A}.Release|Any CPU.ActiveCfg = Release|x64
|
||||
{C0E7E797-4FBF-4F46-BC57-463F3719BA7A}.Release|Any CPU.Build.0 = Release|x64
|
||||
{C0E7E797-4FBF-4F46-BC57-463F3719BA7A}.Release|x64.ActiveCfg = Release|x64
|
||||
{C0E7E797-4FBF-4F46-BC57-463F3719BA7A}.Release|x64.Build.0 = Release|x64
|
||||
{2F7FF0A8-B619-4572-86C7-71E46FE22FB8}.Debug|Any CPU.ActiveCfg = Debug|x64
|
||||
{2F7FF0A8-B619-4572-86C7-71E46FE22FB8}.Debug|Any CPU.Build.0 = Debug|x64
|
||||
{2F7FF0A8-B619-4572-86C7-71E46FE22FB8}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{2F7FF0A8-B619-4572-86C7-71E46FE22FB8}.Debug|x64.Build.0 = Debug|x64
|
||||
{2F7FF0A8-B619-4572-86C7-71E46FE22FB8}.Release|Any CPU.ActiveCfg = Release|x64
|
||||
{2F7FF0A8-B619-4572-86C7-71E46FE22FB8}.Release|Any CPU.Build.0 = Release|x64
|
||||
{2F7FF0A8-B619-4572-86C7-71E46FE22FB8}.Release|x64.ActiveCfg = Release|x64
|
||||
{2F7FF0A8-B619-4572-86C7-71E46FE22FB8}.Release|x64.Build.0 = Release|x64
|
||||
{4AFDB34A-7467-4D41-B067-53BC4101D9D0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{4AFDB34A-7467-4D41-B067-53BC4101D9D0}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{4AFDB34A-7467-4D41-B067-53BC4101D9D0}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{4AFDB34A-7467-4D41-B067-53BC4101D9D0}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{4AFDB34A-7467-4D41-B067-53BC4101D9D0}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{4AFDB34A-7467-4D41-B067-53BC4101D9D0}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{4AFDB34A-7467-4D41-B067-53BC4101D9D0}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{4AFDB34A-7467-4D41-B067-53BC4101D9D0}.Release|x64.Build.0 = Release|Any CPU
|
||||
{C9B87BD7-AF49-41C3-91F1-D550ADEB7833}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{C9B87BD7-AF49-41C3-91F1-D550ADEB7833}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{C9B87BD7-AF49-41C3-91F1-D550ADEB7833}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{C9B87BD7-AF49-41C3-91F1-D550ADEB7833}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{C9B87BD7-AF49-41C3-91F1-D550ADEB7833}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{C9B87BD7-AF49-41C3-91F1-D550ADEB7833}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{C9B87BD7-AF49-41C3-91F1-D550ADEB7833}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{C9B87BD7-AF49-41C3-91F1-D550ADEB7833}.Release|x64.Build.0 = Release|Any CPU
|
||||
{F3F0CC3A-DE2E-403F-88B4-B47C62582477}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{F3F0CC3A-DE2E-403F-88B4-B47C62582477}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{F3F0CC3A-DE2E-403F-88B4-B47C62582477}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{F3F0CC3A-DE2E-403F-88B4-B47C62582477}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{F3F0CC3A-DE2E-403F-88B4-B47C62582477}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{F3F0CC3A-DE2E-403F-88B4-B47C62582477}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{F3F0CC3A-DE2E-403F-88B4-B47C62582477}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{F3F0CC3A-DE2E-403F-88B4-B47C62582477}.Release|x64.Build.0 = Release|Any CPU
|
||||
{05AB2F46-268B-4915-806F-DDF813E2D59D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{05AB2F46-268B-4915-806F-DDF813E2D59D}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{05AB2F46-268B-4915-806F-DDF813E2D59D}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{05AB2F46-268B-4915-806F-DDF813E2D59D}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{05AB2F46-268B-4915-806F-DDF813E2D59D}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{05AB2F46-268B-4915-806F-DDF813E2D59D}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{05AB2F46-268B-4915-806F-DDF813E2D59D}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{05AB2F46-268B-4915-806F-DDF813E2D59D}.Release|x64.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(NestedProjects) = preSolution
|
||||
{C0E7E797-4FBF-4F46-BC57-463F3719BA7A} = {E15BDA6D-E881-4482-94BA-BE5527E917FF}
|
||||
{85480198-8711-4355-830E-72FD794AD3F6} = {E15BDA6D-E881-4482-94BA-BE5527E917FF}
|
||||
{0483026E-C6CE-4B1A-AA68-46544C08140B} = {E15BDA6D-E881-4482-94BA-BE5527E917FF}
|
||||
{C0E7E797-4FBF-4F46-BC57-463F3719BA7A} = {E15BDA6D-E881-4482-94BA-BE5527E917FF}
|
||||
{2F7FF0A8-B619-4572-86C7-71E46FE22FB8} = {E15BDA6D-E881-4482-94BA-BE5527E917FF}
|
||||
{C9B87BD7-AF49-41C3-91F1-D550ADEB7833} = {E15BDA6D-E881-4482-94BA-BE5527E917FF}
|
||||
{F3F0CC3A-DE2E-403F-88B4-B47C62582477} = {E15BDA6D-E881-4482-94BA-BE5527E917FF}
|
||||
{05AB2F46-268B-4915-806F-DDF813E2D59D} = {E15BDA6D-E881-4482-94BA-BE5527E917FF}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {79B65AC9-C940-410E-AB61-7EA7E12C7599}
|
||||
|
|
|
|||
|
|
@ -7,19 +7,19 @@ using Newtonsoft.Json;
|
|||
using Serilog;
|
||||
using Serilog.Events;
|
||||
|
||||
namespace Dalamud.Configuration
|
||||
namespace Dalamud.Configuration.Internal
|
||||
{
|
||||
/// <summary>
|
||||
/// Class containing Dalamud settings.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class DalamudConfiguration
|
||||
internal sealed class DalamudConfiguration
|
||||
{
|
||||
[JsonIgnore]
|
||||
private string configPath;
|
||||
|
||||
/// <summary>
|
||||
/// Delegate for the <see cref="DalamudConfiguration.OnDalamudConfigurationSaved"/> event that occurs when the dalamud configuration is saved.
|
||||
/// Delegate for the <see cref="OnDalamudConfigurationSaved"/> event that occurs when the dalamud configuration is saved.
|
||||
/// </summary>
|
||||
/// <param name="dalamudConfiguration">The current dalamud configuration.</param>
|
||||
public delegate void DalamudConfigurationSavedDelegate(DalamudConfiguration dalamudConfiguration);
|
||||
|
|
@ -69,15 +69,25 @@ namespace Dalamud.Configuration
|
|||
/// </summary>
|
||||
public bool DoDalamudTest { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether or not XL should download the Dalamud .NET runtime.
|
||||
/// </summary>
|
||||
public bool DoDalamudRuntime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a list of custom repos.
|
||||
/// </summary>
|
||||
public List<ThirdRepoSetting> ThirdRepoList { get; set; } = new List<ThirdRepoSetting>();
|
||||
public List<ThirdPartyRepoSettings> ThirdRepoList { get; set; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a list of hidden plugins.
|
||||
/// </summary>
|
||||
public List<string> HiddenPluginInternalName { get; set; } = new List<string>();
|
||||
public List<string> HiddenPluginInternalName { get; set; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a list of additional settings for devPlugins.
|
||||
/// </summary>
|
||||
public List<DevPluginSettings> DevPluginSettings { get; set; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the global UI scale.
|
||||
|
|
@ -150,7 +160,7 @@ namespace Dalamud.Configuration
|
|||
public bool IsAntiAntiDebugEnabled { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// Specifies the kind of beta to download when <see cref="DoDalamudTest"/> is set to true.
|
||||
/// Gets or sets the kind of beta to download when <see cref="DoDalamudTest"/> is set to true.
|
||||
/// </summary>
|
||||
public string DalamudBetaKind { get; set; }
|
||||
|
||||
33
Dalamud/Configuration/Internal/DevPluginSettings.cs
Normal file
33
Dalamud/Configuration/Internal/DevPluginSettings.cs
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
namespace Dalamud.Configuration.Internal
|
||||
{
|
||||
/// <summary>
|
||||
/// Settings for DevPlugins.
|
||||
/// </summary>
|
||||
internal sealed class DevPluginSettings
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="DevPluginSettings"/> class.
|
||||
/// </summary>
|
||||
/// <param name="dllFile">Filename of the DLL representing this plugin.</param>
|
||||
public DevPluginSettings(string dllFile)
|
||||
{
|
||||
this.DllFile = dllFile;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the path to a plugin DLL. This is automatically generated for any plugins in the devPlugins folder. However by
|
||||
/// specifiying this value manually, you can add arbitrary files outside the normal file paths.
|
||||
/// </summary>
|
||||
public string DllFile { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether this plugin should automatically start when Dalamud boots up.
|
||||
/// </summary>
|
||||
public bool StartOnBoot { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether this plugin should automatically reload on file change.
|
||||
/// </summary>
|
||||
public bool AutomaticReloading { get; set; } = false;
|
||||
}
|
||||
}
|
||||
|
|
@ -3,7 +3,7 @@ namespace Dalamud.Configuration
|
|||
/// <summary>
|
||||
/// Third party repository for dalamud plugins.
|
||||
/// </summary>
|
||||
public class ThirdRepoSetting
|
||||
internal sealed class ThirdPartyRepoSettings
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the third party repo url.
|
||||
|
|
@ -16,16 +16,14 @@ namespace Dalamud.Configuration
|
|||
public bool IsEnabled { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Create new instance of third party repo object.
|
||||
/// Gets or sets a short name for the repo url.
|
||||
/// </summary>
|
||||
/// <returns>New instance of third party repo.</returns>
|
||||
public ThirdRepoSetting Clone()
|
||||
{
|
||||
return new ThirdRepoSetting
|
||||
{
|
||||
Url = this.Url,
|
||||
IsEnabled = this.IsEnabled,
|
||||
};
|
||||
}
|
||||
public string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Clone this object.
|
||||
/// </summary>
|
||||
/// <returns>A shallow copy of this object.</returns>
|
||||
public ThirdPartyRepoSettings Clone() => this.MemberwiseClone() as ThirdPartyRepoSettings;
|
||||
}
|
||||
}
|
||||
|
|
@ -7,7 +7,7 @@ namespace Dalamud.Configuration
|
|||
/// <summary>
|
||||
/// Configuration to store settings for a dalamud plugin.
|
||||
/// </summary>
|
||||
public class PluginConfigurations
|
||||
public sealed class PluginConfigurations
|
||||
{
|
||||
private readonly DirectoryInfo configDirectory;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using Dalamud.Configuration;
|
||||
using Dalamud.Configuration.Internal;
|
||||
using Dalamud.Data;
|
||||
using Dalamud.Game;
|
||||
using Dalamud.Game.Addon;
|
||||
|
|
@ -13,17 +13,24 @@ using Dalamud.Game.Command;
|
|||
using Dalamud.Game.Internal;
|
||||
using Dalamud.Game.Network;
|
||||
using Dalamud.Game.Text.SeStringHandling;
|
||||
using Dalamud.Interface;
|
||||
using Dalamud.Plugin;
|
||||
using Dalamud.Hooking.Internal;
|
||||
using Dalamud.Interface.Internal;
|
||||
using Dalamud.Memory;
|
||||
using Dalamud.Plugin.Internal;
|
||||
using Serilog;
|
||||
using Serilog.Core;
|
||||
|
||||
#if DEBUG
|
||||
// This allows for rapid prototyping of Dalamud modules with access to internal objects.
|
||||
[assembly: InternalsVisibleTo("Dalamud.CorePlugin")]
|
||||
#endif
|
||||
|
||||
namespace Dalamud
|
||||
{
|
||||
/// <summary>
|
||||
/// The main Dalamud class containing all subsystems.
|
||||
/// </summary>
|
||||
public sealed class Dalamud : IDisposable
|
||||
internal sealed class Dalamud : IDisposable
|
||||
{
|
||||
#region Internals
|
||||
|
||||
|
|
@ -31,8 +38,6 @@ namespace Dalamud
|
|||
|
||||
private readonly ManualResetEvent finishUnloadSignal;
|
||||
|
||||
private readonly string baseDirectory;
|
||||
|
||||
private bool hasDisposedPlugins = false;
|
||||
|
||||
#endregion
|
||||
|
|
@ -46,11 +51,14 @@ namespace Dalamud
|
|||
/// <param name="configuration">The Dalamud configuration.</param>
|
||||
public Dalamud(DalamudStartInfo info, LoggingLevelSwitch loggingLevelSwitch, ManualResetEvent finishSignal, DalamudConfiguration configuration)
|
||||
{
|
||||
#if DEBUG
|
||||
Instance = this;
|
||||
#endif
|
||||
this.StartInfo = info;
|
||||
this.LogLevelSwitch = loggingLevelSwitch;
|
||||
this.Configuration = configuration;
|
||||
|
||||
this.baseDirectory = info.WorkingDirectory;
|
||||
// this.baseDirectory = info.WorkingDirectory;
|
||||
|
||||
this.unloadSignal = new ManualResetEvent(false);
|
||||
this.unloadSignal.Reset();
|
||||
|
|
@ -59,6 +67,13 @@ namespace Dalamud
|
|||
this.finishUnloadSignal.Reset();
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
/// <summary>
|
||||
/// Gets the Dalamud singleton instance.
|
||||
/// </summary>
|
||||
internal static Dalamud Instance { get; private set; }
|
||||
#endif
|
||||
|
||||
#region Native Game Subsystems
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -76,6 +91,11 @@ namespace Dalamud
|
|||
/// </summary>
|
||||
internal WinSockHandlers WinSock2 { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets Hook management subsystem.
|
||||
/// </summary>
|
||||
internal HookManager HookManager { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets ImGui Interface subsystem.
|
||||
/// </summary>
|
||||
|
|
@ -95,11 +115,6 @@ namespace Dalamud
|
|||
/// </summary>
|
||||
internal PluginManager PluginManager { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets Plugin Repository subsystem.
|
||||
/// </summary>
|
||||
internal PluginRepository PluginRepository { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets Data provider subsystem.
|
||||
/// </summary>
|
||||
|
|
@ -205,6 +220,7 @@ namespace Dalamud
|
|||
// Initialize the process information.
|
||||
this.TargetModule = Process.GetCurrentProcess().MainModule;
|
||||
this.SigScanner = new SigScanner(this.TargetModule, true);
|
||||
this.HookManager = new HookManager(this);
|
||||
|
||||
// Initialize game subsystem
|
||||
this.Framework = new Framework(this.SigScanner, this);
|
||||
|
|
@ -289,6 +305,7 @@ namespace Dalamud
|
|||
Log.Information("[T2] Data OK!");
|
||||
|
||||
this.SeStringManager = new SeStringManager(this.Data);
|
||||
MemoryHelper.Initialize(this); // For SeString handling
|
||||
|
||||
Log.Information("[T2] SeString OK!");
|
||||
|
||||
|
|
@ -327,28 +344,18 @@ namespace Dalamud
|
|||
{
|
||||
Log.Information("[T3] START!");
|
||||
|
||||
this.PluginRepository =
|
||||
new PluginRepository(this, this.StartInfo.PluginDirectory, this.StartInfo.GameVersion);
|
||||
|
||||
Log.Information("[T3] PREPO OK!");
|
||||
|
||||
if (!bool.Parse(Environment.GetEnvironmentVariable("DALAMUD_NOT_HAVE_PLUGINS") ?? "false"))
|
||||
{
|
||||
try
|
||||
{
|
||||
this.PluginRepository.CleanupPlugins();
|
||||
|
||||
Log.Information("[T3] PRC OK!");
|
||||
|
||||
this.PluginManager = new PluginManager(
|
||||
this,
|
||||
this.StartInfo.PluginDirectory,
|
||||
this.StartInfo.DefaultPluginDirectory);
|
||||
this.PluginManager.LoadSynchronousPlugins();
|
||||
|
||||
Task.Run(() => this.PluginManager.LoadDeferredPlugins());
|
||||
|
||||
this.PluginManager = new PluginManager(this);
|
||||
Log.Information("[T3] PM OK!");
|
||||
|
||||
this.PluginManager.CleanupPlugins();
|
||||
Log.Information("[T3] PMC OK!");
|
||||
|
||||
this.PluginManager.LoadAllPlugins();
|
||||
Log.Information("[T3] PML OK!");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
|
@ -357,8 +364,6 @@ namespace Dalamud
|
|||
}
|
||||
|
||||
this.DalamudUi = new DalamudInterface(this);
|
||||
this.InterfaceManager.OnDraw += this.DalamudUi.Draw;
|
||||
|
||||
Log.Information("[T3] DUI OK!");
|
||||
|
||||
Troubleshooting.LogTroubleshooting(this, this.InterfaceManager != null);
|
||||
|
|
@ -410,16 +415,9 @@ namespace Dalamud
|
|||
// use any resources that it freed in its own Dispose method
|
||||
this.InterfaceManager?.Dispose();
|
||||
|
||||
try
|
||||
{
|
||||
this.PluginManager.UnloadPlugins();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error(ex, "Plugin unload failed.");
|
||||
}
|
||||
|
||||
this.DalamudUi?.Dispose();
|
||||
|
||||
this.PluginManager?.Dispose();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -436,20 +434,23 @@ namespace Dalamud
|
|||
}
|
||||
|
||||
this.Framework?.Dispose();
|
||||
|
||||
this.ClientState?.Dispose();
|
||||
|
||||
this.unloadSignal?.Dispose();
|
||||
|
||||
this.WinSock2?.Dispose();
|
||||
|
||||
this.SigScanner?.Dispose();
|
||||
|
||||
this.Data?.Dispose();
|
||||
|
||||
this.AntiDebug?.Dispose();
|
||||
|
||||
this.SystemMenu?.Dispose();
|
||||
|
||||
this.HookManager?.Dispose();
|
||||
|
||||
this.SigScanner?.Dispose();
|
||||
|
||||
Log.Debug("Dalamud::Dispose() OK!");
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
|
|
|||
|
|
@ -1,105 +1,124 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup Label="Target">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<TargetFramework>net472</TargetFramework>
|
||||
<TargetFramework>net5.0-windows</TargetFramework>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<Platforms>x64;AnyCPU</Platforms>
|
||||
<LangVersion>9.0</LangVersion>
|
||||
<Platforms>AnyCPU;x64</Platforms>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Label="Build">
|
||||
<OutputType>Library</OutputType>
|
||||
<OutputPath></OutputPath>
|
||||
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<DocumentationFile>$(SolutionDir)\bin\Dalamud.xml</DocumentationFile>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Label="Feature">
|
||||
<DalamudVersion>5.2.7.0</DalamudVersion>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<Description>XIV Launcher addon framework</Description>
|
||||
<AssemblyVersion>$(DalamudVersion)</AssemblyVersion>
|
||||
<Version>$(DalamudVersion)</Version>
|
||||
<FileVersion>$(DalamudVersion)</FileVersion>
|
||||
</PropertyGroup>
|
||||
<ItemGroup Label="Resources">
|
||||
<None Include="$(SolutionDir)/Resources/**/*" CopyToOutputDirectory="PreserveNewest" Visible="false" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)'=='Release'">
|
||||
<AppOutputBase>$(MSBuildProjectDirectory)\</AppOutputBase>
|
||||
<PathMap>$(AppOutputBase)=C:\goatsoft\companysecrets\dalamud\</PathMap>
|
||||
|
||||
<PropertyGroup Label="Output">
|
||||
<OutputType>Library</OutputType>
|
||||
<OutputPath>..\bin\$(Configuration)\</OutputPath>
|
||||
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
|
||||
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
|
||||
<GenerateRuntimeConfigurationFiles>true</GenerateRuntimeConfigurationFiles>
|
||||
<ProduceReferenceAssembly>false</ProduceReferenceAssembly>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Label="Documentation">
|
||||
<DocumentationFile>$(OutputPath)Dalamud.xml</DocumentationFile>
|
||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Label="Build">
|
||||
<UseWindowsForms>true</UseWindowsForms>
|
||||
<EnableDynamicLoading>true</EnableDynamicLoading>
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>portable</DebugType>
|
||||
<Deterministic>true</Deterministic>
|
||||
<Nullable>annotations</Nullable>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<GeneratePackageOnBuild>false</GeneratePackageOnBuild>
|
||||
|
||||
<PropertyGroup Label="Configuration">
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||
<PropertyGroup Label="Configuration" Condition="'$(Configuration)'=='Debug'">
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<NoWarn>IDE0017;IDE0044;IDE0047;IDE0048;IDE1006;CS1573;CS1591;CS1701;CS1702</NoWarn>
|
||||
<!-- IDE0017 - Use object initializers -->
|
||||
<!-- IDE0044 - Add readonly modifier -->
|
||||
<!-- IDE0047 - Parentheses preferences -->
|
||||
<!-- IDE0048 - Parentheses preferences -->
|
||||
<!-- IDE1006 - Naming preferences -->
|
||||
<!-- CS1573 - Parameter has no matching param tag in the XML comment -->
|
||||
<PropertyGroup Label="Configuration" Condition="'$(Configuration)'=='Release'">
|
||||
<AppOutputBase>$(MSBuildProjectDirectory)\</AppOutputBase>
|
||||
<PathMap>$(AppOutputBase)=C:\goatsoft\companysecrets\dalamud\</PathMap>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Label="Warnings">
|
||||
<NoWarn>IDE0003;IDE1006;CS1591;CS1701;CS1702</NoWarn>
|
||||
<!-- IDE1006 - Naming violation -->
|
||||
<!-- CS1591 - Missing XML comment for publicly visible type or member -->
|
||||
<!-- CS1701 - Runtime policy may be needed -->
|
||||
<!-- CS1702 - Runtime policy may be needed -->
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Remove="Resources\Lumina.Generated.dll" />
|
||||
<None Remove="stylecop.json" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AdditionalFiles Include="stylecop.json" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="CheapLoc" Version="1.1.3" />
|
||||
<PackageReference Include="JetBrains.Annotations" Version="2020.3.0" />
|
||||
<PackageReference Include="Lumina" Version="3.1.0" />
|
||||
<PackageReference Include="CheapLoc" Version="1.1.5" />
|
||||
<PackageReference Include="CoreHook" Version="1.0.4" />
|
||||
<PackageReference Include="JetBrains.Annotations" Version="2021.1.0" />
|
||||
<PackageReference Include="Lib.Harmony" Version="2.1.0" />
|
||||
<PackageReference Include="Lumina" Version="3.3.0" />
|
||||
<PackageReference Include="Lumina.Excel" Version="5.50.0" />
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Scripting" Version="3.0.0" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="12.0.2" />
|
||||
<PackageReference Include="PropertyChanged.Fody" Version="2.6.1" />
|
||||
<PackageReference Include="Serilog" Version="2.6.0" />
|
||||
<PackageReference Include="Serilog.Sinks.Async" Version="1.1.0" />
|
||||
<PackageReference Include="Serilog.Sinks.File" Version="4.0.0" />
|
||||
<PackageReference Include="EasyHook" Version="2.7.6270" />
|
||||
<PackageReference Include="SharpDX.Desktop" Version="4.2.0" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
||||
<PackageReference Include="McMaster.NETCore.Plugins" Version="1.4.0" />
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Scripting" Version="3.10.0" />
|
||||
<PackageReference Include="PropertyChanged.Fody" Version="3.4.0">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Serilog" Version="2.10.0" />
|
||||
<PackageReference Include="Serilog.Sinks.Async" Version="1.5.0" />
|
||||
<PackageReference Include="Serilog.Sinks.File" Version="5.0.0" />
|
||||
<PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.333">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="System.Collections.Immutable" Version="5.0.0" />
|
||||
<PackageReference Include="System.Drawing.Common" Version="5.0.2" />
|
||||
<PackageReference Include="System.Reflection.MetadataLoadContext" Version="5.0.1" />
|
||||
<PackageReference Include="System.Resources.Extensions" Version="5.0.0" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System.Net.Http" />
|
||||
<ProjectReference Include="..\lib\FFXIVClientStructs\FFXIVClientStructs\FFXIVClientStructs.csproj" />
|
||||
<ProjectReference Include="..\lib\ImGuiScene\deps\ImGui.NET\src\ImGui.NET-472\ImGui.NET-472.csproj" />
|
||||
<ProjectReference Include="..\lib\ImGuiScene\deps\SDL2-CS\SDL2-CS.csproj" />
|
||||
<ProjectReference Include="..\lib\ImGuiScene\ImGuiScene\ImGuiScene.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<AdditionalFiles Include="..\stylecop.json" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Update="Properties\Resources.Designer.cs">
|
||||
<DesignTime>True</DesignTime>
|
||||
<AutoGen>True</AutoGen>
|
||||
<DependentUpon>Resources.resx</DependentUpon>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Update="Properties\Resources.resx">
|
||||
<Generator>ResXFileCodeGenerator</Generator>
|
||||
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
|
||||
</EmbeddedResource>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\lib\FFXIVClientStructs\FFXIVClientStructs.csproj" />
|
||||
<ProjectReference Include="..\lib\ImGuiScene\deps\ImGui.NET\src\ImGui.NET-472\ImGui.NET-472.csproj" />
|
||||
<ProjectReference Include="..\lib\ImGuiScene\deps\SDL2-CS\SDL2-CS.csproj" />
|
||||
<ProjectReference Include="..\lib\ImGuiScene\ImGuiScene\ImGuiScene.csproj" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ContentWithTargetPath Include="Resources\Lumina.Generated.dll">
|
||||
<None Include="corehook64.dll">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
<TargetPath>Lumina.Generated.dll</TargetPath>
|
||||
</ContentWithTargetPath>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
<Target Name="AddRuntimeDependenciesToContent" BeforeTargets="GetCopyToOutputDirectoryItems" DependsOnTargets="GenerateBuildDependencyFile;GenerateBuildRuntimeConfigurationFiles">
|
||||
<ItemGroup>
|
||||
<ContentWithTargetPath Include="$(ProjectDepsFilePath)" CopyToOutputDirectory="PreserveNewest" TargetPath="$(ProjectDepsFileName)" />
|
||||
<ContentWithTargetPath Include="$(ProjectRuntimeConfigFilePath)" CopyToOutputDirectory="PreserveNewest" TargetPath="$(ProjectRuntimeConfigFileName)" />
|
||||
</ItemGroup>
|
||||
</Target>
|
||||
|
||||
<Target Name="GetGitHash" BeforeTargets="WriteGitHash" Condition="'$(BuildHash)' == ''">
|
||||
<PropertyGroup>
|
||||
<!-- temp file for the git version (lives in "obj" folder)-->
|
||||
|
|
|
|||
|
|
@ -1,12 +1,15 @@
|
|||
using System;
|
||||
|
||||
using Dalamud.Game;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Dalamud
|
||||
{
|
||||
/// <summary>
|
||||
/// Class containing information needed to initialize Dalamud.
|
||||
/// Struct containing information needed to initialize Dalamud.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public sealed class DalamudStartInfo
|
||||
public struct DalamudStartInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// The working directory of the XIVLauncher installations.
|
||||
|
|
@ -41,7 +44,8 @@ namespace Dalamud
|
|||
/// <summary>
|
||||
/// The current game version code.
|
||||
/// </summary>
|
||||
public string GameVersion;
|
||||
[JsonConverter(typeof(GameVersionConverter))]
|
||||
public GameVersion GameVersion;
|
||||
|
||||
/// <summary>
|
||||
/// Whether or not market board information should be uploaded by default.
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ using System.Threading;
|
|||
|
||||
using Dalamud.Data.LuminaExtensions;
|
||||
using Dalamud.Interface;
|
||||
using Dalamud.Interface.Internal;
|
||||
using ImGuiScene;
|
||||
using JetBrains.Annotations;
|
||||
using Lumina;
|
||||
|
|
@ -21,7 +22,7 @@ namespace Dalamud.Data
|
|||
/// <summary>
|
||||
/// This class provides data for Dalamud-internal features, but can also be used by plugins if needed.
|
||||
/// </summary>
|
||||
public class DataManager : IDisposable
|
||||
public sealed class DataManager : IDisposable
|
||||
{
|
||||
private const string IconFileFormat = "ui/icon/{0:D3}000/{1}{2:D6}.tex";
|
||||
private readonly InterfaceManager interfaceManager;
|
||||
|
|
@ -32,6 +33,7 @@ namespace Dalamud.Data
|
|||
private GameData gameData;
|
||||
|
||||
private Thread luminaResourceThread;
|
||||
private CancellationTokenSource luminaCancellationTokenSource;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="DataManager"/> class.
|
||||
|
|
@ -41,8 +43,9 @@ namespace Dalamud.Data
|
|||
internal DataManager(ClientLanguage language, InterfaceManager interfaceManager)
|
||||
{
|
||||
this.interfaceManager = interfaceManager;
|
||||
|
||||
// Set up default values so plugins do not null-reference when data is being loaded.
|
||||
this.ServerOpCodes = new ReadOnlyDictionary<string, ushort>(new Dictionary<string, ushort>());
|
||||
this.ClientOpCodes = this.ServerOpCodes = new ReadOnlyDictionary<string, ushort>(new Dictionary<string, ushort>());
|
||||
|
||||
this.Language = language;
|
||||
}
|
||||
|
|
@ -99,7 +102,7 @@ namespace Dalamud.Data
|
|||
ClientLanguage.English => Lumina.Data.Language.English,
|
||||
ClientLanguage.German => Lumina.Data.Language.German,
|
||||
ClientLanguage.French => Lumina.Data.Language.French,
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(this.Language), $"Unknown Language: {this.Language}"),
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(language), $"Unknown Language: {language}"),
|
||||
};
|
||||
return this.Excel.GetSheet<T>(lang);
|
||||
}
|
||||
|
|
@ -162,7 +165,7 @@ namespace Dalamud.Data
|
|||
ClientLanguage.English => "en/",
|
||||
ClientLanguage.German => "de/",
|
||||
ClientLanguage.French => "fr/",
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(this.Language), $"Unknown Language: {this.Language}"),
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(iconLanguage), $"Unknown Language: {iconLanguage}"),
|
||||
};
|
||||
|
||||
return this.GetIcon(type, iconId);
|
||||
|
|
@ -232,7 +235,7 @@ namespace Dalamud.Data
|
|||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
this.luminaResourceThread.Abort();
|
||||
this.luminaCancellationTokenSource.Cancel();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -245,14 +248,14 @@ namespace Dalamud.Data
|
|||
{
|
||||
Log.Verbose("Starting data load...");
|
||||
|
||||
var zoneOpCodeDict =
|
||||
JsonConvert.DeserializeObject<Dictionary<string, ushort>>(File.ReadAllText(Path.Combine(baseDir, "UIRes", "serveropcode.json")));
|
||||
var zoneOpCodeDict = JsonConvert.DeserializeObject<Dictionary<string, ushort>>(
|
||||
File.ReadAllText(Path.Combine(baseDir, "UIRes", "serveropcode.json")));
|
||||
this.ServerOpCodes = new ReadOnlyDictionary<string, ushort>(zoneOpCodeDict);
|
||||
|
||||
Log.Verbose("Loaded {0} ServerOpCodes.", zoneOpCodeDict.Count);
|
||||
|
||||
var clientOpCodeDict =
|
||||
JsonConvert.DeserializeObject<Dictionary<string, ushort>>(File.ReadAllText(Path.Combine(baseDir, "UIRes", "clientopcode.json")));
|
||||
var clientOpCodeDict = JsonConvert.DeserializeObject<Dictionary<string, ushort>>(
|
||||
File.ReadAllText(Path.Combine(baseDir, "UIRes", "clientopcode.json")));
|
||||
this.ClientOpCodes = new ReadOnlyDictionary<string, ushort>(clientOpCodeDict);
|
||||
|
||||
Log.Verbose("Loaded {0} ClientOpCodes.", clientOpCodeDict.Count);
|
||||
|
|
@ -273,9 +276,7 @@ namespace Dalamud.Data
|
|||
ClientLanguage.English => Lumina.Data.Language.English,
|
||||
ClientLanguage.German => Lumina.Data.Language.German,
|
||||
ClientLanguage.French => Lumina.Data.Language.French,
|
||||
_ => throw new ArgumentOutOfRangeException(
|
||||
nameof(this.Language),
|
||||
@"Unknown Language: " + this.Language),
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(this.Language), $"Unknown Language: {this.Language}"),
|
||||
},
|
||||
};
|
||||
|
||||
|
|
@ -289,9 +290,12 @@ namespace Dalamud.Data
|
|||
|
||||
this.IsDataReady = true;
|
||||
|
||||
this.luminaResourceThread = new Thread(() =>
|
||||
this.luminaCancellationTokenSource = new();
|
||||
|
||||
var luminaCancellationToken = this.luminaCancellationTokenSource.Token;
|
||||
this.luminaResourceThread = new(() =>
|
||||
{
|
||||
while (true)
|
||||
while (!luminaCancellationToken.IsCancellationRequested)
|
||||
{
|
||||
if (this.gameData.FileHandleManager.HasPendingFileLoads)
|
||||
{
|
||||
|
|
@ -302,8 +306,6 @@ namespace Dalamud.Data
|
|||
Thread.Sleep(5);
|
||||
}
|
||||
}
|
||||
|
||||
// ReSharper disable once FunctionNeverReturns
|
||||
});
|
||||
this.luminaResourceThread.Start();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,12 +1,13 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using Dalamud.Configuration;
|
||||
using Dalamud.Interface;
|
||||
using EasyHook;
|
||||
using Dalamud.Configuration.Internal;
|
||||
using Dalamud.Interface.Internal;
|
||||
using Newtonsoft.Json;
|
||||
using Serilog;
|
||||
using Serilog.Core;
|
||||
using Serilog.Events;
|
||||
|
|
@ -16,31 +17,41 @@ namespace Dalamud
|
|||
/// <summary>
|
||||
/// The main entrypoint for the Dalamud system.
|
||||
/// </summary>
|
||||
public sealed class EntryPoint : IEntryPoint
|
||||
public sealed class EntryPoint
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="EntryPoint"/> class.
|
||||
/// A delegate used during initialization of the CLR from Dalamud.Boot.
|
||||
/// </summary>
|
||||
/// <param name="ctx">The <see cref="RemoteHooking.IContext"/> used to load the DLL.</param>
|
||||
/// <param name="info">The <see cref="DalamudStartInfo"/> containing information needed to initialize Dalamud.</param>
|
||||
public EntryPoint(RemoteHooking.IContext ctx, DalamudStartInfo info)
|
||||
/// <param name="infoPtr">Pointer to a serialized <see cref="DalamudStartInfo"/> data.</param>
|
||||
public delegate void InitDelegate(IntPtr infoPtr);
|
||||
|
||||
/// <summary>
|
||||
/// Initialize Dalamud.
|
||||
/// </summary>
|
||||
/// <param name="infoPtr">Pointer to a serialized <see cref="DalamudStartInfo"/> data.</param>
|
||||
public static void Initialize(IntPtr infoPtr)
|
||||
{
|
||||
// Required by EasyHook
|
||||
var infoStr = Marshal.PtrToStringAnsi(infoPtr);
|
||||
var info = JsonConvert.DeserializeObject<DalamudStartInfo>(infoStr);
|
||||
|
||||
new Thread(() => RunThread(info)).Start();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initialize all Dalamud subsystems and start running on the main thread.
|
||||
/// </summary>
|
||||
/// <param name="ctx">The <see cref="RemoteHooking.IContext"/> used to load the DLL.</param>
|
||||
/// <param name="info">The <see cref="DalamudStartInfo"/> containing information needed to initialize Dalamud.</param>
|
||||
public void Run(RemoteHooking.IContext ctx, DalamudStartInfo info)
|
||||
private static void RunThread(DalamudStartInfo info)
|
||||
{
|
||||
// Load configuration first to get some early persistent state, like log level
|
||||
var configuration = DalamudConfiguration.Load(info.ConfigurationPath);
|
||||
|
||||
// Setup logger
|
||||
var (logger, levelSwitch) = this.NewLogger(info.WorkingDirectory, configuration.LogLevel);
|
||||
Log.Logger = logger;
|
||||
var levelSwitch = InitLogging(info.WorkingDirectory);
|
||||
|
||||
// Log any unhandled exception.
|
||||
AppDomain.CurrentDomain.UnhandledException += OnUnhandledException;
|
||||
TaskScheduler.UnobservedTaskException += OnUnobservedTaskException;
|
||||
|
||||
var finishSignal = new ManualResetEvent(false);
|
||||
|
||||
|
|
@ -50,12 +61,7 @@ namespace Dalamud
|
|||
Log.Information("Initializing a session..");
|
||||
|
||||
// This is due to GitHub not supporting TLS 1.0, so we enable all TLS versions globally
|
||||
System.Net.ServicePointManager.SecurityProtocol =
|
||||
SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12 | SecurityProtocolType.Tls | SecurityProtocolType.Ssl3;
|
||||
|
||||
// Log any unhandled exception.
|
||||
AppDomain.CurrentDomain.UnhandledException += this.OnUnhandledException;
|
||||
TaskScheduler.UnobservedTaskException += this.OnUnobservedTaskException;
|
||||
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12 | SecurityProtocolType.Tls;
|
||||
|
||||
var dalamud = new Dalamud(info, levelSwitch, finishSignal, configuration);
|
||||
Log.Information("Starting a session..");
|
||||
|
|
@ -72,7 +78,8 @@ namespace Dalamud
|
|||
}
|
||||
finally
|
||||
{
|
||||
AppDomain.CurrentDomain.UnhandledException -= this.OnUnhandledException;
|
||||
TaskScheduler.UnobservedTaskException -= OnUnobservedTaskException;
|
||||
AppDomain.CurrentDomain.UnhandledException -= OnUnhandledException;
|
||||
|
||||
Log.Information("Session has ended.");
|
||||
Log.CloseAndFlush();
|
||||
|
|
@ -81,7 +88,7 @@ namespace Dalamud
|
|||
}
|
||||
}
|
||||
|
||||
private (Logger Logger, LoggingLevelSwitch LevelSwitch) NewLogger(string baseDirectory, LogEventLevel logLevel)
|
||||
private static LoggingLevelSwitch InitLogging(string baseDirectory)
|
||||
{
|
||||
#if DEBUG
|
||||
var logPath = Path.Combine(baseDirectory, "dalamud.log");
|
||||
|
|
@ -96,33 +103,32 @@ namespace Dalamud
|
|||
#else
|
||||
levelSwitch.MinimumLevel = logLevel;
|
||||
#endif
|
||||
|
||||
var newLogger = new LoggerConfiguration()
|
||||
Log.Logger = new LoggerConfiguration()
|
||||
.WriteTo.Async(a => a.File(logPath))
|
||||
.WriteTo.Sink(SerilogEventSink.Instance)
|
||||
.MinimumLevel.ControlledBy(levelSwitch)
|
||||
.CreateLogger();
|
||||
|
||||
return (newLogger, levelSwitch);
|
||||
return levelSwitch;
|
||||
}
|
||||
|
||||
private void OnUnhandledException(object sender, UnhandledExceptionEventArgs arg)
|
||||
private static void OnUnhandledException(object sender, UnhandledExceptionEventArgs args)
|
||||
{
|
||||
switch (arg.ExceptionObject)
|
||||
switch (args.ExceptionObject)
|
||||
{
|
||||
case Exception ex:
|
||||
Log.Fatal(ex, "Unhandled exception on AppDomain");
|
||||
break;
|
||||
default:
|
||||
Log.Fatal("Unhandled SEH object on AppDomain: {Object}", arg.ExceptionObject);
|
||||
Log.Fatal("Unhandled SEH object on AppDomain: {Object}", args.ExceptionObject);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnUnobservedTaskException(object sender, UnobservedTaskExceptionEventArgs e)
|
||||
private static void OnUnobservedTaskException(object sender, UnobservedTaskExceptionEventArgs args)
|
||||
{
|
||||
if (!e.Observed)
|
||||
Log.Error(e.Exception, "Unobserved exception in Task.");
|
||||
if (!args.Observed)
|
||||
Log.Error(args.Exception, "Unobserved exception in Task.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,16 @@
|
|||
<xs:documentation>Used to control if the On_PropertyName_Changed feature is enabled.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="TriggerDependentProperties" type="xs:boolean">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Used to control if the Dependent properties feature is enabled.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="EnableIsChangedProperty" type="xs:boolean">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Used to control if the IsChanged property feature is enabled.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="EventInvokerNames" type="xs:string">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Used to change the name of the method that fires the notify event. This is a string that accepts multiple values in a comma separated form.</xs:documentation>
|
||||
|
|
@ -31,6 +41,16 @@
|
|||
<xs:documentation>Used to control if equality checks should use the static Equals method resolved from the base class.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="SuppressWarnings" type="xs:boolean">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Used to turn off build warnings from this weaver.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="SuppressOnPropertyNameChangedWarning" type="xs:boolean">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Used to turn off build warnings about mismatched On_PropertyName_Changed methods.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
</xs:all>
|
||||
|
|
|
|||
|
|
@ -16,11 +16,11 @@ namespace Dalamud.Game.Addon
|
|||
internal sealed unsafe partial class DalamudSystemMenu
|
||||
{
|
||||
private readonly Dalamud dalamud;
|
||||
private AtkValueChangeType atkValueChangeType;
|
||||
private AtkValueSetString atkValueSetString;
|
||||
private Hook<AgentHudOpenSystemMenuPrototype> hookAgentHudOpenSystemMenu;
|
||||
private readonly AtkValueChangeType atkValueChangeType;
|
||||
private readonly AtkValueSetString atkValueSetString;
|
||||
private readonly Hook<AgentHudOpenSystemMenuPrototype> hookAgentHudOpenSystemMenu;
|
||||
// TODO: Make this into events in Framework.Gui
|
||||
private Hook<UiModuleRequestMainCommand> hookUiModuleRequestMainCommand;
|
||||
private readonly Hook<UiModuleRequestMainCommand> hookUiModuleRequestMainCommand;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="DalamudSystemMenu"/> class.
|
||||
|
|
@ -34,13 +34,10 @@ namespace Dalamud.Game.Addon
|
|||
|
||||
this.hookAgentHudOpenSystemMenu = new Hook<AgentHudOpenSystemMenuPrototype>(openSystemMenuAddress, this.AgentHudOpenSystemMenuDetour);
|
||||
|
||||
var atkValueChangeTypeAddress =
|
||||
this.dalamud.SigScanner.ScanText("E8 ?? ?? ?? ?? 45 84 F6 48 8D 4C 24 ??");
|
||||
this.atkValueChangeType =
|
||||
Marshal.GetDelegateForFunctionPointer<AtkValueChangeType>(atkValueChangeTypeAddress);
|
||||
var atkValueChangeTypeAddress = this.dalamud.SigScanner.ScanText("E8 ?? ?? ?? ?? 45 84 F6 48 8D 4C 24 ??");
|
||||
this.atkValueChangeType = Marshal.GetDelegateForFunctionPointer<AtkValueChangeType>(atkValueChangeTypeAddress);
|
||||
|
||||
var atkValueSetStringAddress =
|
||||
this.dalamud.SigScanner.ScanText("E8 ?? ?? ?? ?? 41 03 ED");
|
||||
var atkValueSetStringAddress = this.dalamud.SigScanner.ScanText("E8 ?? ?? ?? ?? 41 03 ED");
|
||||
this.atkValueSetString = Marshal.GetDelegateForFunctionPointer<AtkValueSetString>(atkValueSetStringAddress);
|
||||
|
||||
var uiModuleRequestMainCommandAddress = this.dalamud.SigScanner.ScanText("40 53 56 48 81 EC ?? ?? ?? ?? 48 8B 05 ?? ?? ?? ?? 48 33 C4 48 89 84 24 ?? ?? ?? ?? 48 8B 01 8B DA 48 8B F1 FF 90 ?? ?? ?? ??");
|
||||
|
|
@ -140,10 +137,10 @@ namespace Dalamud.Game.Addon
|
|||
switch (commandId)
|
||||
{
|
||||
case 69420:
|
||||
this.dalamud.DalamudUi.TogglePluginInstaller();
|
||||
this.dalamud.DalamudUi.TogglePluginInstallerWindow();
|
||||
break;
|
||||
case 69421:
|
||||
this.dalamud.DalamudUi.ToggleSettings();
|
||||
this.dalamud.DalamudUi.ToggleSettingsWindow();
|
||||
break;
|
||||
default:
|
||||
this.hookUiModuleRequestMainCommand.Original(thisPtr, commandId);
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ using CheapLoc;
|
|||
using Dalamud.Game.Text;
|
||||
using Dalamud.Game.Text.SeStringHandling;
|
||||
using Dalamud.Game.Text.SeStringHandling.Payloads;
|
||||
using Dalamud.Interface;
|
||||
using Dalamud.Interface.Internal.Windows;
|
||||
using Serilog;
|
||||
|
||||
namespace Dalamud.Game
|
||||
|
|
@ -21,39 +21,39 @@ namespace Dalamud.Game
|
|||
/// </summary>
|
||||
public class ChatHandlers
|
||||
{
|
||||
private static readonly Dictionary<string, string> UnicodeToDiscordEmojiDict = new()
|
||||
{
|
||||
{ "", "<:ffxive071:585847382210642069>" },
|
||||
{ "", "<:ffxive083:585848592699490329>" },
|
||||
};
|
||||
// private static readonly Dictionary<string, string> UnicodeToDiscordEmojiDict = new()
|
||||
// {
|
||||
// { "", "<:ffxive071:585847382210642069>" },
|
||||
// { "", "<:ffxive083:585848592699490329>" },
|
||||
// };
|
||||
|
||||
private readonly Dictionary<XivChatType, Color> handledChatTypeColors = new()
|
||||
{
|
||||
{ XivChatType.CrossParty, Color.DodgerBlue },
|
||||
{ XivChatType.Party, Color.DodgerBlue },
|
||||
{ XivChatType.FreeCompany, Color.DeepSkyBlue },
|
||||
{ XivChatType.CrossLinkShell1, Color.ForestGreen },
|
||||
{ XivChatType.CrossLinkShell2, Color.ForestGreen },
|
||||
{ XivChatType.CrossLinkShell3, Color.ForestGreen },
|
||||
{ XivChatType.CrossLinkShell4, Color.ForestGreen },
|
||||
{ XivChatType.CrossLinkShell5, Color.ForestGreen },
|
||||
{ XivChatType.CrossLinkShell6, Color.ForestGreen },
|
||||
{ XivChatType.CrossLinkShell7, Color.ForestGreen },
|
||||
{ XivChatType.CrossLinkShell8, Color.ForestGreen },
|
||||
{ XivChatType.Ls1, Color.ForestGreen },
|
||||
{ XivChatType.Ls2, Color.ForestGreen },
|
||||
{ XivChatType.Ls3, Color.ForestGreen },
|
||||
{ XivChatType.Ls4, Color.ForestGreen },
|
||||
{ XivChatType.Ls5, Color.ForestGreen },
|
||||
{ XivChatType.Ls6, Color.ForestGreen },
|
||||
{ XivChatType.Ls7, Color.ForestGreen },
|
||||
{ XivChatType.Ls8, Color.ForestGreen },
|
||||
{ XivChatType.TellIncoming, Color.HotPink },
|
||||
{ XivChatType.PvPTeam, Color.SandyBrown },
|
||||
{ XivChatType.Urgent, Color.DarkViolet },
|
||||
{ XivChatType.NoviceNetwork, Color.SaddleBrown },
|
||||
{ XivChatType.Echo, Color.Gray },
|
||||
};
|
||||
// private readonly Dictionary<XivChatType, Color> handledChatTypeColors = new()
|
||||
// {
|
||||
// { XivChatType.CrossParty, Color.DodgerBlue },
|
||||
// { XivChatType.Party, Color.DodgerBlue },
|
||||
// { XivChatType.FreeCompany, Color.DeepSkyBlue },
|
||||
// { XivChatType.CrossLinkShell1, Color.ForestGreen },
|
||||
// { XivChatType.CrossLinkShell2, Color.ForestGreen },
|
||||
// { XivChatType.CrossLinkShell3, Color.ForestGreen },
|
||||
// { XivChatType.CrossLinkShell4, Color.ForestGreen },
|
||||
// { XivChatType.CrossLinkShell5, Color.ForestGreen },
|
||||
// { XivChatType.CrossLinkShell6, Color.ForestGreen },
|
||||
// { XivChatType.CrossLinkShell7, Color.ForestGreen },
|
||||
// { XivChatType.CrossLinkShell8, Color.ForestGreen },
|
||||
// { XivChatType.Ls1, Color.ForestGreen },
|
||||
// { XivChatType.Ls2, Color.ForestGreen },
|
||||
// { XivChatType.Ls3, Color.ForestGreen },
|
||||
// { XivChatType.Ls4, Color.ForestGreen },
|
||||
// { XivChatType.Ls5, Color.ForestGreen },
|
||||
// { XivChatType.Ls6, Color.ForestGreen },
|
||||
// { XivChatType.Ls7, Color.ForestGreen },
|
||||
// { XivChatType.Ls8, Color.ForestGreen },
|
||||
// { XivChatType.TellIncoming, Color.HotPink },
|
||||
// { XivChatType.PvPTeam, Color.SandyBrown },
|
||||
// { XivChatType.Urgent, Color.DarkViolet },
|
||||
// { XivChatType.NoviceNetwork, Color.SaddleBrown },
|
||||
// { XivChatType.Echo, Color.Gray },
|
||||
// };
|
||||
|
||||
private readonly Regex rmtRegex = new(
|
||||
@"4KGOLD|We have sufficient stock|VPK\.OM|Gil for free|www\.so9\.com|Fast & Convenient|Cheap & Safety Guarantee|【Code|A O A U E|igfans|4KGOLD\.COM|Cheapest Gil with|pvp and bank on google|Selling Cheap GIL|ff14mogstation\.com|Cheap Gil 1000k|gilsforyou|server 1000K =|gils_selling|E A S Y\.C O M|bonus code|mins delivery guarantee|Sell cheap|Salegm\.com|cheap Mog|Off Code:|FF14Mog.com|使用する5%オ|Off Code( *):|offers Fantasia",
|
||||
|
|
@ -96,14 +96,14 @@ namespace Dalamud.Game
|
|||
private readonly Regex urlRegex = new(@"(http|ftp|https)://([\w_-]+(?:(?:\.[\w_-]+)+))([\w.,@?^=%&:/~+#-]*[\w@?^=%&/~+#-])?", RegexOptions.Compiled);
|
||||
|
||||
private readonly Dalamud dalamud;
|
||||
private DalamudLinkPayload openInstallerWindowLink;
|
||||
private readonly DalamudLinkPayload openInstallerWindowLink;
|
||||
private bool hasSeenLoadingMsg;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ChatHandlers"/> class.
|
||||
/// </summary>
|
||||
/// <param name="dalamud">Dalamud instance.</param>
|
||||
public ChatHandlers(Dalamud dalamud)
|
||||
internal ChatHandlers(Dalamud dalamud)
|
||||
{
|
||||
this.dalamud = dalamud;
|
||||
|
||||
|
|
@ -121,24 +121,24 @@ namespace Dalamud.Game
|
|||
/// </summary>
|
||||
public string LastLink { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Convert a string to SeString and wrap in italics payloads.
|
||||
/// </summary>
|
||||
/// <param name="text">Text to convert.</param>
|
||||
/// <returns>SeString payload of italicized text.</returns>
|
||||
private static SeString MakeItalics(string text)
|
||||
{
|
||||
// TODO: when the code OnCharMessage is switched to SeString, this can be a straight insertion of the
|
||||
// italics payloads only, and be a lot cleaner
|
||||
var italicString = new SeString(new List<Payload>(new Payload[]
|
||||
{
|
||||
EmphasisItalicPayload.ItalicsOn,
|
||||
new TextPayload(text),
|
||||
EmphasisItalicPayload.ItalicsOff,
|
||||
}));
|
||||
|
||||
return italicString;
|
||||
}
|
||||
// /// <summary>
|
||||
// /// Convert a string to SeString and wrap in italics payloads.
|
||||
// /// </summary>
|
||||
// /// <param name="text">Text to convert.</param>
|
||||
// /// <returns>SeString payload of italicized text.</returns>
|
||||
// private static SeString MakeItalics(string text)
|
||||
// {
|
||||
// // TODO: when the code OnCharMessage is switched to SeString, this can be a straight insertion of the
|
||||
// // italics payloads only, and be a lot cleaner
|
||||
// var italicString = new SeString(new List<Payload>(new Payload[]
|
||||
// {
|
||||
// EmphasisItalicPayload.ItalicsOn,
|
||||
// new TextPayload(text),
|
||||
// EmphasisItalicPayload.ItalicsOff,
|
||||
// }));
|
||||
//
|
||||
// return italicString;
|
||||
// }
|
||||
|
||||
private void OnCheckMessageHandled(XivChatType type, uint senderid, ref SeString sender, ref SeString message, ref bool isHandled)
|
||||
{
|
||||
|
|
@ -243,13 +243,13 @@ namespace Dalamud.Game
|
|||
var assemblyVersion = Assembly.GetAssembly(typeof(ChatHandlers)).GetName().Version.ToString();
|
||||
|
||||
this.dalamud.Framework.Gui.Chat.Print(string.Format(Loc.Localize("DalamudWelcome", "Dalamud vD{0} loaded."), assemblyVersion)
|
||||
+ string.Format(Loc.Localize("PluginsWelcome", " {0} plugin(s) loaded."), this.dalamud.PluginManager.Plugins.Count));
|
||||
+ string.Format(Loc.Localize("PluginsWelcome", " {0} plugin(s) loaded."), this.dalamud.PluginManager.InstalledPlugins.Count));
|
||||
|
||||
if (this.dalamud.Configuration.PrintPluginsWelcomeMsg)
|
||||
{
|
||||
foreach (var plugin in this.dalamud.PluginManager.Plugins.OrderBy(x => x.Plugin.Name))
|
||||
foreach (var plugin in this.dalamud.PluginManager.InstalledPlugins.OrderBy(plugin => plugin.Name))
|
||||
{
|
||||
this.dalamud.Framework.Gui.Chat.Print(string.Format(Loc.Localize("DalamudPluginLoaded", " 》 {0} v{1} loaded."), plugin.Plugin.Name, plugin.Definition.AssemblyVersion));
|
||||
this.dalamud.Framework.Gui.Chat.Print(string.Format(Loc.Localize("DalamudPluginLoaded", " 》 {0} v{1} loaded."), plugin.Name, plugin.Manifest.AssemblyVersion));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -261,16 +261,15 @@ namespace Dalamud.Game
|
|||
Type = XivChatType.Notice,
|
||||
});
|
||||
|
||||
if (DalamudChangelogWindow.WarrantsChangelog)
|
||||
#pragma warning disable CS0162 // Unreachable code detected
|
||||
this.dalamud.DalamudUi.OpenChangelog();
|
||||
#pragma warning restore CS0162 // Unreachable code detected
|
||||
if (this.dalamud.DalamudUi.WarrantsChangelog)
|
||||
this.dalamud.DalamudUi.OpenChangelogWindow();
|
||||
|
||||
this.dalamud.Configuration.LastVersion = assemblyVersion;
|
||||
this.dalamud.Configuration.Save();
|
||||
}
|
||||
|
||||
Task.Run(() => this.dalamud.PluginRepository.UpdatePlugins(!this.dalamud.Configuration.AutoUpdatePlugins)).ContinueWith(t =>
|
||||
Task.Run(() => this.dalamud.PluginManager.UpdatePlugins(!this.dalamud.Configuration.AutoUpdatePlugins))
|
||||
.ContinueWith(t =>
|
||||
{
|
||||
if (t.IsFaulted)
|
||||
{
|
||||
|
|
@ -278,13 +277,13 @@ namespace Dalamud.Game
|
|||
}
|
||||
else
|
||||
{
|
||||
var updatedPlugins = t.Result.UpdatedPlugins;
|
||||
var updatedPlugins = t.Result;
|
||||
|
||||
if (updatedPlugins != null && updatedPlugins.Any())
|
||||
{
|
||||
if (this.dalamud.Configuration.AutoUpdatePlugins)
|
||||
{
|
||||
this.dalamud.PluginRepository.PrintUpdatedPlugins(updatedPlugins, Loc.Localize("DalamudPluginAutoUpdate", "Auto-update:"));
|
||||
this.dalamud.PluginManager.PrintUpdatedPlugins(updatedPlugins, Loc.Localize("DalamudPluginAutoUpdate", "Auto-update:"));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
|||
|
|
@ -34,14 +34,14 @@ namespace Dalamud.Game.ClientState.Actors
|
|||
/// </summary>
|
||||
/// <param name="dalamud">The Dalamud instance.</param>
|
||||
/// <param name="addressResolver">The ClientStateAddressResolver instance.</param>
|
||||
public ActorTable(Dalamud dalamud, ClientStateAddressResolver addressResolver)
|
||||
internal ActorTable(Dalamud dalamud, ClientStateAddressResolver addressResolver)
|
||||
{
|
||||
this.address = addressResolver;
|
||||
this.dalamud = dalamud;
|
||||
|
||||
dalamud.Framework.OnUpdateEvent += this.Framework_OnUpdateEvent;
|
||||
|
||||
Log.Verbose("Actor table address {ActorTable}", this.address.ActorTable);
|
||||
Log.Verbose($"Actor table address 0x{this.address.ActorTable.ToInt64():X}");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ namespace Dalamud.Game.ClientState.Actors.Resolvers
|
|||
/// Initializes a new instance of the <see cref="BaseResolver"/> class.
|
||||
/// </summary>
|
||||
/// <param name="dalamud">The Dalamud instance.</param>
|
||||
public BaseResolver(Dalamud dalamud)
|
||||
internal BaseResolver(Dalamud dalamud)
|
||||
{
|
||||
this.dalamud = dalamud;
|
||||
}
|
||||
|
|
@ -19,6 +19,6 @@ namespace Dalamud.Game.ClientState.Actors.Resolvers
|
|||
/// <summary>
|
||||
/// Gets the Dalamud instance.
|
||||
/// </summary>
|
||||
protected Dalamud Dalamud => this.dalamud;
|
||||
internal Dalamud Dalamud => this.dalamud;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ namespace Dalamud.Game.ClientState.Actors.Resolvers
|
|||
/// </summary>
|
||||
/// <param name="id">The ID of the classJob.</param>
|
||||
/// <param name="dalamud">The Dalamud instance.</param>
|
||||
public ClassJob(byte id, Dalamud dalamud)
|
||||
internal ClassJob(byte id, Dalamud dalamud)
|
||||
: base(dalamud)
|
||||
{
|
||||
this.Id = id;
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ namespace Dalamud.Game.ClientState.Actors.Resolvers
|
|||
/// </summary>
|
||||
/// <param name="id">The ID of the world.</param>
|
||||
/// <param name="dalamud">The Dalamud instance.</param>
|
||||
public World(ushort id, Dalamud dalamud)
|
||||
internal World(ushort id, Dalamud dalamud)
|
||||
: base(dalamud)
|
||||
{
|
||||
this.Id = id;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
using System;
|
||||
using System.Text;
|
||||
|
||||
using Dalamud.Game.ClientState.Structs;
|
||||
using Serilog;
|
||||
|
||||
namespace Dalamud.Game.ClientState.Actors.Types
|
||||
{
|
||||
|
|
@ -22,7 +21,7 @@ namespace Dalamud.Game.ClientState.Actors.Types
|
|||
/// <param name="actorStruct">The memory representation of the base actor.</param>
|
||||
/// <param name="dalamud">A dalamud reference needed to access game data in Resolvers.</param>
|
||||
/// <param name="address">The address of this actor in memory.</param>
|
||||
public Actor(IntPtr address, Structs.Actor actorStruct, Dalamud dalamud)
|
||||
internal Actor(IntPtr address, Structs.Actor actorStruct, Dalamud dalamud)
|
||||
{
|
||||
this.actorStruct = actorStruct;
|
||||
this.dalamud = dalamud;
|
||||
|
|
@ -94,7 +93,7 @@ namespace Dalamud.Game.ClientState.Actors.Types
|
|||
/// <summary>
|
||||
/// Gets the <see cref="Dalamud"/> backing instance.
|
||||
/// </summary>
|
||||
protected Dalamud Dalamud => this.dalamud;
|
||||
internal Dalamud Dalamud => this.dalamud;
|
||||
|
||||
/// <inheritdoc/>
|
||||
bool IEquatable<Actor>.Equals(Actor other) => this.ActorId == other.ActorId;
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ namespace Dalamud.Game.ClientState.Actors.Types
|
|||
/// <param name="actorStruct">The memory representation of the base actor.</param>
|
||||
/// <param name="dalamud">A dalamud reference needed to access game data in Resolvers.</param>
|
||||
/// <param name="address">The address of this actor in memory.</param>
|
||||
protected Chara(IntPtr address, Structs.Actor actorStruct, Dalamud dalamud)
|
||||
internal Chara(IntPtr address, Structs.Actor actorStruct, Dalamud dalamud)
|
||||
: base(address, actorStruct, dalamud)
|
||||
{
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ namespace Dalamud.Game.ClientState.Actors.Types.NonPlayer
|
|||
/// <param name="actorStruct">The memory representation of the base actor.</param>
|
||||
/// <param name="dalamud">A dalamud reference needed to access game data in Resolvers.</param>
|
||||
/// <param name="address">The address of this actor in memory.</param>
|
||||
public BattleNpc(IntPtr address, Structs.Actor actorStruct, Dalamud dalamud)
|
||||
internal BattleNpc(IntPtr address, Structs.Actor actorStruct, Dalamud dalamud)
|
||||
: base(address, actorStruct, dalamud)
|
||||
{
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ namespace Dalamud.Game.ClientState.Actors.Types.NonPlayer
|
|||
/// <param name="actorStruct">The memory representation of the base actor.</param>
|
||||
/// <param name="dalamud">A dalamud reference needed to access game data in Resolvers.</param>
|
||||
/// <param name="address">The address of this actor in memory.</param>
|
||||
public EventObj(IntPtr address, Structs.Actor actorStruct, Dalamud dalamud)
|
||||
internal EventObj(IntPtr address, Structs.Actor actorStruct, Dalamud dalamud)
|
||||
: base(address, actorStruct, dalamud)
|
||||
{
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ namespace Dalamud.Game.ClientState.Actors.Types.NonPlayer
|
|||
/// <param name="actorStruct">The memory representation of the base actor.</param>
|
||||
/// <param name="dalamud">A dalamud reference needed to access game data in Resolvers.</param>
|
||||
/// <param name="address">The address of this actor in memory.</param>
|
||||
public Npc(IntPtr address, Structs.Actor actorStruct, Dalamud dalamud)
|
||||
internal Npc(IntPtr address, Structs.Actor actorStruct, Dalamud dalamud)
|
||||
: base(address, actorStruct, dalamud)
|
||||
{
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ namespace Dalamud.Game.ClientState.Actors.Types
|
|||
/// <param name="actorStruct">The memory representation of the base actor.</param>
|
||||
/// <param name="dalamud">A dalamud reference needed to access game data in Resolvers.</param>
|
||||
/// <param name="address">The address of this actor in memory.</param>
|
||||
public PlayerCharacter(IntPtr address, Structs.Actor actorStruct, Dalamud dalamud)
|
||||
internal PlayerCharacter(IntPtr address, Structs.Actor actorStruct, Dalamud dalamud)
|
||||
: base(address, actorStruct, dalamud)
|
||||
{
|
||||
var companyTagBytes = new byte[5];
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ namespace Dalamud.Game.ClientState
|
|||
/// <summary>
|
||||
/// This class represents the state of the game client at the time of access.
|
||||
/// </summary>
|
||||
public class ClientState : INotifyPropertyChanged, IDisposable
|
||||
public sealed class ClientState : INotifyPropertyChanged, IDisposable
|
||||
{
|
||||
/// <summary>
|
||||
/// The table of all present actors.
|
||||
|
|
@ -80,7 +80,7 @@ namespace Dalamud.Game.ClientState
|
|||
/// <param name="dalamud">Dalamud instance.</param>
|
||||
/// <param name="startInfo">StartInfo of the current Dalamud launch.</param>
|
||||
/// <param name="scanner">Sig scanner.</param>
|
||||
public ClientState(Dalamud dalamud, DalamudStartInfo startInfo, SigScanner scanner)
|
||||
internal ClientState(Dalamud dalamud, DalamudStartInfo startInfo, SigScanner scanner)
|
||||
{
|
||||
this.dalamud = dalamud;
|
||||
this.address = new ClientStateAddressResolver();
|
||||
|
|
@ -104,7 +104,7 @@ namespace Dalamud.Game.ClientState
|
|||
|
||||
this.Targets = new Targets(dalamud, this.address);
|
||||
|
||||
Log.Verbose("SetupTerritoryType address {SetupTerritoryType}", this.address.SetupTerritoryType);
|
||||
Log.Verbose($"SetupTerritoryType address 0x{this.address.SetupTerritoryType.ToInt64():X}");
|
||||
|
||||
this.setupTerritoryTypeHook = new Hook<SetupTerritoryTypeDelegate>(this.address.SetupTerritoryType, this.SetupTerritoryTypeDetour);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
using System;
|
||||
using System;
|
||||
|
||||
using Dalamud.Game.ClientState.Structs;
|
||||
using Dalamud.Hooking;
|
||||
|
|
@ -12,7 +12,7 @@ namespace Dalamud.Game.ClientState
|
|||
///
|
||||
/// Will block game's gamepad input if <see cref="ImGuiConfigFlags.NavEnableGamepad"/> is set.
|
||||
/// </summary>
|
||||
public unsafe class GamepadState
|
||||
public unsafe class GamepadState : IDisposable
|
||||
{
|
||||
private readonly Hook<ControllerPoll> gamepadPoll;
|
||||
|
||||
|
|
@ -29,12 +29,8 @@ namespace Dalamud.Game.ClientState
|
|||
/// <param name="resolver">Resolver knowing the pointer to the GamepadPoll function.</param>
|
||||
public GamepadState(ClientStateAddressResolver resolver)
|
||||
{
|
||||
#if DEBUG
|
||||
Log.Verbose("GamepadPoll address {GamepadPoll}", resolver.GamepadPoll);
|
||||
#endif
|
||||
this.gamepadPoll = new Hook<ControllerPoll>(
|
||||
resolver.GamepadPoll,
|
||||
(ControllerPoll)this.GamepadPollDetour);
|
||||
Log.Verbose($"GamepadPoll address 0x{resolver.GamepadPoll.ToInt64():X}");
|
||||
this.gamepadPoll = new Hook<ControllerPoll>(resolver.GamepadPoll, this.GamepadPollDetour);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ namespace Dalamud.Game.ClientState
|
|||
{
|
||||
this.Address = addressResolver;
|
||||
|
||||
Log.Verbose("JobGaugeData address {JobGaugeData}", this.Address.JobGaugeData);
|
||||
Log.Verbose($"JobGaugeData address 0x{this.Address.JobGaugeData.ToInt64():X}");
|
||||
}
|
||||
|
||||
private ClientStateAddressResolver Address { get; }
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ namespace Dalamud.Game.ClientState
|
|||
{
|
||||
this.bufferBase = moduleBaseAddress + Marshal.ReadInt32(addressResolver.KeyboardState);
|
||||
|
||||
Log.Verbose($"Keyboard state buffer address {this.bufferBase}");
|
||||
Log.Verbose($"Keyboard state buffer address 0x{this.bufferBase.ToInt64():X}");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ namespace Dalamud.Game.ClientState
|
|||
/// </summary>
|
||||
/// <param name="dalamud">The Dalamud instance.</param>
|
||||
/// <param name="addressResolver">The ClientStateAddressResolver instance.</param>
|
||||
public PartyList(Dalamud dalamud, ClientStateAddressResolver addressResolver)
|
||||
internal PartyList(Dalamud dalamud, ClientStateAddressResolver addressResolver)
|
||||
{
|
||||
this.address = addressResolver;
|
||||
this.dalamud = dalamud;
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ namespace Dalamud.Game.ClientState.Structs.JobGauge
|
|||
/// <summary>
|
||||
/// Gets the next step in the current dance.
|
||||
/// </summary>
|
||||
/// <returns>The next dance step action ID.</returns>
|
||||
public ulong NextStep() => (ulong)(15999 + this.stepOrder[this.NumCompleteSteps] - 1);
|
||||
|
||||
/// <summary>
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ namespace Dalamud.Game.Command
|
|||
/// </summary>
|
||||
/// <param name="dalamud">The Dalamud instance.</param>
|
||||
/// <param name="language">The client language requested.</param>
|
||||
public CommandManager(Dalamud dalamud, ClientLanguage language)
|
||||
internal CommandManager(Dalamud dalamud, ClientLanguage language)
|
||||
{
|
||||
this.dalamud = dalamud;
|
||||
|
||||
|
|
@ -128,7 +128,8 @@ namespace Dalamud.Game.Command
|
|||
/// <returns>If adding was successful.</returns>
|
||||
public bool AddHandler(string command, CommandInfo info)
|
||||
{
|
||||
if (info == null) throw new ArgumentNullException(nameof(info), "Command handler is null.");
|
||||
if (info == null)
|
||||
throw new ArgumentNullException(nameof(info), "Command handler is null.");
|
||||
|
||||
try
|
||||
{
|
||||
|
|
|
|||
383
Dalamud/Game/GameVersion.cs
Normal file
383
Dalamud/Game/GameVersion.cs
Normal file
|
|
@ -0,0 +1,383 @@
|
|||
using System;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Dalamud.Game
|
||||
{
|
||||
/// <summary>
|
||||
/// A GameVersion object contains give hierarchical numeric components: year, month,
|
||||
/// day, major and minor. All components may be unspecified, which is represented
|
||||
/// internally as a -1. By definition, an unspecified component matches anything
|
||||
/// (both unspecified and specified), and an unspecified component is "less than" any
|
||||
/// specified component. It will also equal the string "any" if all components are
|
||||
/// unspecified. The value can be retrieved from the ffxivgame.ver file in your game
|
||||
/// installation directory.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public sealed class GameVersion : ICloneable, IComparable, IComparable<GameVersion>, IEquatable<GameVersion>
|
||||
{
|
||||
private static readonly GameVersion AnyVersion = new();
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="GameVersion"/> class.
|
||||
/// </summary>
|
||||
/// <param name="version">Version string to parse.</param>
|
||||
[JsonConstructor]
|
||||
public GameVersion(string version)
|
||||
{
|
||||
var ver = Parse(version);
|
||||
this.Year = ver.Year;
|
||||
this.Month = ver.Month;
|
||||
this.Day = ver.Day;
|
||||
this.Major = ver.Major;
|
||||
this.Minor = ver.Minor;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="GameVersion"/> class.
|
||||
/// </summary>
|
||||
/// <param name="year">The year.</param>
|
||||
/// <param name="month">The month.</param>
|
||||
/// <param name="day">The day.</param>
|
||||
/// <param name="major">The major version.</param>
|
||||
/// <param name="minor">The minor version.</param>
|
||||
public GameVersion(int year, int month, int day, int major, int minor)
|
||||
{
|
||||
if ((this.Year = year) < 0)
|
||||
throw new ArgumentOutOfRangeException(nameof(year));
|
||||
|
||||
if ((this.Month = month) < 0)
|
||||
throw new ArgumentOutOfRangeException(nameof(month));
|
||||
|
||||
if ((this.Day = day) < 0)
|
||||
throw new ArgumentOutOfRangeException(nameof(day));
|
||||
|
||||
if ((this.Major = major) < 0)
|
||||
throw new ArgumentOutOfRangeException(nameof(major));
|
||||
|
||||
if ((this.Minor = minor) < 0)
|
||||
throw new ArgumentOutOfRangeException(nameof(minor));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="GameVersion"/> class.
|
||||
/// </summary>
|
||||
/// <param name="year">The year.</param>
|
||||
/// <param name="month">The month.</param>
|
||||
/// <param name="day">The day.</param>
|
||||
/// <param name="major">The major version.</param>
|
||||
public GameVersion(int year, int month, int day, int major)
|
||||
{
|
||||
if ((this.Year = year) < 0)
|
||||
throw new ArgumentOutOfRangeException(nameof(year));
|
||||
|
||||
if ((this.Month = month) < 0)
|
||||
throw new ArgumentOutOfRangeException(nameof(month));
|
||||
|
||||
if ((this.Day = day) < 0)
|
||||
throw new ArgumentOutOfRangeException(nameof(day));
|
||||
|
||||
if ((this.Major = major) < 0)
|
||||
throw new ArgumentOutOfRangeException(nameof(major));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="GameVersion"/> class.
|
||||
/// </summary>
|
||||
/// <param name="year">The year.</param>
|
||||
/// <param name="month">The month.</param>
|
||||
/// <param name="day">The day.</param>
|
||||
public GameVersion(int year, int month, int day)
|
||||
{
|
||||
if ((this.Year = year) < 0)
|
||||
throw new ArgumentOutOfRangeException(nameof(year));
|
||||
|
||||
if ((this.Month = month) < 0)
|
||||
throw new ArgumentOutOfRangeException(nameof(month));
|
||||
|
||||
if ((this.Day = day) < 0)
|
||||
throw new ArgumentOutOfRangeException(nameof(day));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="GameVersion"/> class.
|
||||
/// </summary>
|
||||
/// <param name="year">The year.</param>
|
||||
/// <param name="month">The month.</param>
|
||||
public GameVersion(int year, int month)
|
||||
{
|
||||
if ((this.Year = year) < 0)
|
||||
throw new ArgumentOutOfRangeException(nameof(year));
|
||||
|
||||
if ((this.Month = month) < 0)
|
||||
throw new ArgumentOutOfRangeException(nameof(month));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="GameVersion"/> class.
|
||||
/// </summary>
|
||||
/// <param name="year">The year.</param>
|
||||
public GameVersion(int year)
|
||||
{
|
||||
if ((this.Year = year) < 0)
|
||||
throw new ArgumentOutOfRangeException(nameof(year));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="GameVersion"/> class.
|
||||
/// </summary>
|
||||
public GameVersion()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the default "any" game version.
|
||||
/// </summary>
|
||||
public static GameVersion Any => AnyVersion;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the year component.
|
||||
/// </summary>
|
||||
public int Year { get; } = -1;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the month component.
|
||||
/// </summary>
|
||||
public int Month { get; } = -1;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the day component.
|
||||
/// </summary>
|
||||
public int Day { get; } = -1;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the major version component.
|
||||
/// </summary>
|
||||
public int Major { get; } = -1;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the minor version component.
|
||||
/// </summary>
|
||||
public int Minor { get; } = -1;
|
||||
|
||||
public static implicit operator GameVersion(string ver)
|
||||
{
|
||||
return Parse(ver);
|
||||
}
|
||||
|
||||
public static bool operator ==(GameVersion v1, GameVersion v2)
|
||||
{
|
||||
if (v1 is null)
|
||||
{
|
||||
return v2 is null;
|
||||
}
|
||||
|
||||
return v1.Equals(v2);
|
||||
}
|
||||
|
||||
public static bool operator !=(GameVersion v1, GameVersion v2)
|
||||
{
|
||||
return !(v1 == v2);
|
||||
}
|
||||
|
||||
public static bool operator <(GameVersion v1, GameVersion v2)
|
||||
{
|
||||
if (v1 is null)
|
||||
throw new ArgumentNullException(nameof(v1));
|
||||
|
||||
return v1.CompareTo(v2) < 0;
|
||||
}
|
||||
|
||||
public static bool operator <=(GameVersion v1, GameVersion v2)
|
||||
{
|
||||
if (v1 is null)
|
||||
throw new ArgumentNullException(nameof(v1));
|
||||
|
||||
return v1.CompareTo(v2) <= 0;
|
||||
}
|
||||
|
||||
public static bool operator >(GameVersion v1, GameVersion v2)
|
||||
{
|
||||
return v2 < v1;
|
||||
}
|
||||
|
||||
public static bool operator >=(GameVersion v1, GameVersion v2)
|
||||
{
|
||||
return v2 <= v1;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse a version string. YYYY.MM.DD.majr.minr or "any".
|
||||
/// </summary>
|
||||
/// <param name="input">Input to parse.</param>
|
||||
/// <returns>GameVersion object.</returns>
|
||||
public static GameVersion Parse(string input)
|
||||
{
|
||||
if (input == null)
|
||||
throw new ArgumentNullException(nameof(input));
|
||||
|
||||
if (input.ToLower(CultureInfo.InvariantCulture) == "any")
|
||||
return new GameVersion();
|
||||
|
||||
var parts = input.Split('.');
|
||||
var tplParts = parts.Select(p =>
|
||||
{
|
||||
var result = int.TryParse(p, out var value);
|
||||
return (result, value);
|
||||
}).ToArray();
|
||||
|
||||
if (tplParts.Any(t => !t.result))
|
||||
throw new FormatException("Bad formatting");
|
||||
|
||||
var intParts = tplParts.Select(t => t.value).ToArray();
|
||||
var len = intParts.Length;
|
||||
|
||||
if (len == 1)
|
||||
return new GameVersion(intParts[0]);
|
||||
else if (len == 2)
|
||||
return new GameVersion(intParts[0], intParts[1]);
|
||||
else if (len == 3)
|
||||
return new GameVersion(intParts[0], intParts[1], intParts[2]);
|
||||
else if (len == 4)
|
||||
return new GameVersion(intParts[0], intParts[1], intParts[2], intParts[3]);
|
||||
else if (len == 5)
|
||||
return new GameVersion(intParts[0], intParts[1], intParts[2], intParts[3], intParts[4]);
|
||||
else
|
||||
throw new ArgumentException("Too many parts");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Try to parse a version string. YYYY.MM.DD.majr.minr or "any".
|
||||
/// </summary>
|
||||
/// <param name="input">Input to parse.</param>
|
||||
/// <param name="result">GameVersion object.</param>
|
||||
/// <returns>Success or failure.</returns>
|
||||
public static bool TryParse(string input, out GameVersion result)
|
||||
{
|
||||
try
|
||||
{
|
||||
result = Parse(input);
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
result = null;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public object Clone() => new GameVersion(this.Year, this.Month, this.Day, this.Major, this.Minor);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public int CompareTo(object obj)
|
||||
{
|
||||
if (obj == null)
|
||||
return 1;
|
||||
|
||||
if (obj is GameVersion value)
|
||||
{
|
||||
return this.CompareTo(value);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ArgumentException("Argument must be a GameVersion");
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public int CompareTo(GameVersion value)
|
||||
{
|
||||
if (value == null)
|
||||
return 1;
|
||||
|
||||
if (this == value)
|
||||
return 0;
|
||||
|
||||
if (this == AnyVersion)
|
||||
return 1;
|
||||
|
||||
if (value == AnyVersion)
|
||||
return -1;
|
||||
|
||||
if (this.Year != value.Year)
|
||||
return this.Year > value.Year ? 1 : -1;
|
||||
|
||||
if (this.Month != value.Month)
|
||||
return this.Month > value.Month ? 1 : -1;
|
||||
|
||||
if (this.Day != value.Day)
|
||||
return this.Day > value.Day ? 1 : -1;
|
||||
|
||||
if (this.Major != value.Major)
|
||||
return this.Major > value.Major ? 1 : -1;
|
||||
|
||||
if (this.Minor != value.Minor)
|
||||
return this.Minor > value.Minor ? 1 : -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (obj is not GameVersion value)
|
||||
return false;
|
||||
|
||||
return this.Equals(value);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool Equals(GameVersion value)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return
|
||||
(this.Year == value.Year) &&
|
||||
(this.Month == value.Month) &&
|
||||
(this.Day == value.Day) &&
|
||||
(this.Major == value.Major) &&
|
||||
(this.Minor == value.Minor);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override int GetHashCode()
|
||||
{
|
||||
var accumulator = 0;
|
||||
|
||||
// This might be horribly wrong, but it isn't used heavily.
|
||||
accumulator |= this.Year.GetHashCode();
|
||||
accumulator |= this.Month.GetHashCode();
|
||||
accumulator |= this.Day.GetHashCode();
|
||||
accumulator |= this.Major.GetHashCode();
|
||||
accumulator |= this.Minor.GetHashCode();
|
||||
|
||||
return accumulator;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string ToString()
|
||||
{
|
||||
if (this.Year == -1 &&
|
||||
this.Month == -1 &&
|
||||
this.Day == -1 &&
|
||||
this.Major == -1 &&
|
||||
this.Minor == -1)
|
||||
return "any";
|
||||
|
||||
return new StringBuilder()
|
||||
.Append(string.Format("{0:D4}.", this.Year == -1 ? 0 : this.Year))
|
||||
.Append(string.Format("{0:D2}.", this.Month == -1 ? 0 : this.Month))
|
||||
.Append(string.Format("{0:D2}.", this.Day == -1 ? 0 : this.Day))
|
||||
.Append(string.Format("{0:D4}.", this.Major == -1 ? 0 : this.Major))
|
||||
.Append(string.Format("{0:D4}", this.Minor == -1 ? 0 : this.Minor))
|
||||
.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
80
Dalamud/Game/GameVersionConverter.cs
Normal file
80
Dalamud/Game/GameVersionConverter.cs
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
using System;
|
||||
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Dalamud.Game
|
||||
{
|
||||
/// <summary>
|
||||
/// Converts a <see cref="GameVersion"/> to and from a string (e.g. <c>"2010.01.01.1234.5678"</c>).
|
||||
/// </summary>
|
||||
public sealed class GameVersionConverter : JsonConverter
|
||||
{
|
||||
/// <summary>
|
||||
/// Writes the JSON representation of the object.
|
||||
/// </summary>
|
||||
/// <param name="writer">The <see cref="JsonWriter"/> to write to.</param>
|
||||
/// <param name="value">The value.</param>
|
||||
/// <param name="serializer">The calling serializer.</param>
|
||||
public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
writer.WriteNull();
|
||||
}
|
||||
else if (value is GameVersion)
|
||||
{
|
||||
writer.WriteValue(value.ToString());
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new JsonSerializationException("Expected GameVersion object value");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads the JSON representation of the object.
|
||||
/// </summary>
|
||||
/// <param name="reader">The <see cref="JsonReader"/> to read from.</param>
|
||||
/// <param name="objectType">Type of the object.</param>
|
||||
/// <param name="existingValue">The existing property value of the JSON that is being converted.</param>
|
||||
/// <param name="serializer">The calling serializer.</param>
|
||||
/// <returns>The object value.</returns>
|
||||
public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer)
|
||||
{
|
||||
if (reader.TokenType == JsonToken.Null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (reader.TokenType == JsonToken.String)
|
||||
{
|
||||
try
|
||||
{
|
||||
return new GameVersion((string)reader.Value!);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new JsonSerializationException($"Error parsing GameVersion string: {reader.Value}", ex);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new JsonSerializationException($"Unexpected token or value when parsing GameVersion. Token: {reader.TokenType}, Value: {reader.Value}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether this instance can convert the specified object type.
|
||||
/// </summary>
|
||||
/// <param name="objectType">Type of the object.</param>
|
||||
/// <returns>
|
||||
/// <c>true</c> if this instance can convert the specified object type; otherwise, <c>false</c>.
|
||||
/// </returns>
|
||||
public override bool CanConvert(Type objectType)
|
||||
{
|
||||
return objectType == typeof(GameVersion);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -29,7 +29,7 @@ namespace Dalamud.Game.Internal
|
|||
this.debugCheckAddress = IntPtr.Zero;
|
||||
}
|
||||
|
||||
Log.Verbose("DebugCheck address {DebugCheckAddress}", this.debugCheckAddress);
|
||||
Log.Verbose($"Debug check address 0x{this.debugCheckAddress.ToInt64():X}");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -45,7 +45,7 @@ namespace Dalamud.Game.Internal
|
|||
this.original = new byte[this.nop.Length];
|
||||
if (this.debugCheckAddress != IntPtr.Zero && !this.IsEnabled)
|
||||
{
|
||||
Log.Information($"Overwriting debug check @ 0x{this.debugCheckAddress.ToInt64():X}");
|
||||
Log.Information($"Overwriting debug check at 0x{this.debugCheckAddress.ToInt64():X}");
|
||||
SafeMemory.ReadBytes(this.debugCheckAddress, this.nop.Length, out this.original);
|
||||
SafeMemory.WriteBytes(this.debugCheckAddress, this.nop);
|
||||
}
|
||||
|
|
@ -64,7 +64,7 @@ namespace Dalamud.Game.Internal
|
|||
{
|
||||
if (this.debugCheckAddress != IntPtr.Zero && this.original != null)
|
||||
{
|
||||
Log.Information($"Reverting debug check @ 0x{this.debugCheckAddress.ToInt64():X}");
|
||||
Log.Information($"Reverting debug check at 0x{this.debugCheckAddress.ToInt64():X}");
|
||||
SafeMemory.WriteBytes(this.debugCheckAddress, this.original);
|
||||
}
|
||||
else
|
||||
|
|
@ -110,9 +110,11 @@ namespace Dalamud.Game.Internal
|
|||
{
|
||||
// If anti-debug is enabled and is being disposed, odds are either the game is exiting, or Dalamud is being reloaded.
|
||||
// If it is the latter, there's half a chance a debugger is currently attached. There's no real need to disable the
|
||||
// check in either situation anyways.
|
||||
// this.Disable();
|
||||
// check in either situation anyways. However if Dalamud is being reloaded, the sig may fail so may as well undo it.
|
||||
this.Disable();
|
||||
}
|
||||
|
||||
this.disposed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
227
Dalamud/Game/Internal/DXGI/Definitions/ID3D11DeviceVtbl.cs
Normal file
227
Dalamud/Game/Internal/DXGI/Definitions/ID3D11DeviceVtbl.cs
Normal file
|
|
@ -0,0 +1,227 @@
|
|||
namespace Dalamud.Game.Internal.DXGI.Definitions
|
||||
{
|
||||
/// <summary>
|
||||
/// Contains a full list of ID3D11Device functions to be used as an indexer into the DirectX Virtual Function Table entries.
|
||||
/// </summary>
|
||||
internal enum ID3D11DeviceVtbl
|
||||
{
|
||||
// IUnknown
|
||||
|
||||
/// <summary>
|
||||
/// IUnknown::QueryInterface method (unknwn.h).
|
||||
/// </summary>
|
||||
QueryInterface = 0,
|
||||
|
||||
/// <summary>
|
||||
/// IUnknown::AddRef method (unknwn.h).
|
||||
/// </summary>
|
||||
AddRef = 1,
|
||||
|
||||
/// <summary>
|
||||
/// IUnknown::Release method (unknwn.h).
|
||||
/// </summary>
|
||||
Release = 2,
|
||||
|
||||
// ID3D11Device
|
||||
|
||||
/// <summary>
|
||||
/// ID3D11Device::CreateBuffer method (d3d11.h).
|
||||
/// </summary>
|
||||
CreateBuffer = 3,
|
||||
|
||||
/// <summary>
|
||||
/// ID3D11Device::CreateTexture1D method (d3d11.h).
|
||||
/// </summary>
|
||||
CreateTexture1D = 4,
|
||||
|
||||
/// <summary>
|
||||
/// ID3D11Device::CreateTexture2D method (d3d11.h).
|
||||
/// </summary>
|
||||
CreateTexture2D = 5,
|
||||
|
||||
/// <summary>
|
||||
/// ID3D11Device::CreateTexture3D method (d3d11.h).
|
||||
/// </summary>
|
||||
CreateTexture3D = 6,
|
||||
|
||||
/// <summary>
|
||||
/// ID3D11Device::CreateShaderResourceView method (d3d11.h).
|
||||
/// </summary>
|
||||
CreateShaderResourceView = 7,
|
||||
|
||||
/// <summary>
|
||||
/// ID3D11Device::CreateUnorderedAccessView method (d3d11.h).
|
||||
/// </summary>
|
||||
CreateUnorderedAccessView = 8,
|
||||
|
||||
/// <summary>
|
||||
/// ID3D11Device::CreateRenderTargetView method (d3d11.h).
|
||||
/// </summary>
|
||||
CreateRenderTargetView = 9,
|
||||
|
||||
/// <summary>
|
||||
/// ID3D11Device::CreateDepthStencilView method (d3d11.h).
|
||||
/// </summary>
|
||||
CreateDepthStencilView = 10,
|
||||
|
||||
/// <summary>
|
||||
/// ID3D11Device::CreateInputLayout method (d3d11.h).
|
||||
/// </summary>
|
||||
CreateInputLayout = 11,
|
||||
|
||||
/// <summary>
|
||||
/// ID3D11Device::CreateVertexShader method (d3d11.h).
|
||||
/// </summary>
|
||||
CreateVertexShader = 12,
|
||||
|
||||
/// <summary>
|
||||
/// ID3D11Device::CreateGeometryShader method (d3d11.h).
|
||||
/// </summary>
|
||||
CreateGeometryShader = 13,
|
||||
|
||||
/// <summary>
|
||||
/// ID3D11Device::CreateGeometryShaderWithStreamOutput method (d3d11.h).
|
||||
/// </summary>
|
||||
CreateGeometryShaderWithStreamOutput = 14,
|
||||
|
||||
/// <summary>
|
||||
/// ID3D11Device::CreatePixelShader method (d3d11.h).
|
||||
/// </summary>
|
||||
CreatePixelShader = 15,
|
||||
|
||||
/// <summary>
|
||||
/// ID3D11Device::CreateHullShader method (d3d11.h).
|
||||
/// </summary>
|
||||
CreateHullShader = 16,
|
||||
|
||||
/// <summary>
|
||||
/// ID3D11Device::CreateDomainShader method (d3d11.h).
|
||||
/// </summary>
|
||||
CreateDomainShader = 17,
|
||||
|
||||
/// <summary>
|
||||
/// ID3D11Device::CreateComputeShader method (d3d11.h).
|
||||
/// </summary>
|
||||
CreateComputeShader = 18,
|
||||
|
||||
/// <summary>
|
||||
/// ID3D11Device::CreateClassLinkage method (d3d11.h).
|
||||
/// </summary>
|
||||
CreateClassLinkage = 19,
|
||||
|
||||
/// <summary>
|
||||
/// ID3D11Device::CreateBlendState method (d3d11.h).
|
||||
/// </summary>
|
||||
CreateBlendState = 20,
|
||||
|
||||
/// <summary>
|
||||
/// ID3D11Device::CreateDepthStencilState method (d3d11.h).
|
||||
/// </summary>
|
||||
CreateDepthStencilState = 21,
|
||||
|
||||
/// <summary>
|
||||
/// ID3D11Device::CreateRasterizerState method (d3d11.h).
|
||||
/// </summary>
|
||||
CreateRasterizerState = 22,
|
||||
|
||||
/// <summary>
|
||||
/// ID3D11Device::CreateSamplerState method (d3d11.h).
|
||||
/// </summary>
|
||||
CreateSamplerState = 23,
|
||||
|
||||
/// <summary>
|
||||
/// ID3D11Device::CreateQuery method (d3d11.h).
|
||||
/// </summary>
|
||||
CreateQuery = 24,
|
||||
|
||||
/// <summary>
|
||||
/// ID3D11Device::CreatePredicate method (d3d11.h).
|
||||
/// </summary>
|
||||
CreatePredicate = 25,
|
||||
|
||||
/// <summary>
|
||||
/// ID3D11Device::CreateCounter method (d3d11.h).
|
||||
/// </summary>
|
||||
CreateCounter = 26,
|
||||
|
||||
/// <summary>
|
||||
/// ID3D11Device::CreateDeferredContext method (d3d11.h).
|
||||
/// </summary>
|
||||
CreateDeferredContext = 27,
|
||||
|
||||
/// <summary>
|
||||
/// ID3D11Device::OpenSharedResource method (d3d11.h).
|
||||
/// </summary>
|
||||
OpenSharedResource = 28,
|
||||
|
||||
/// <summary>
|
||||
/// ID3D11Device::CheckFormatSupport method (d3d11.h).
|
||||
/// </summary>
|
||||
CheckFormatSupport = 29,
|
||||
|
||||
/// <summary>
|
||||
/// ID3D11Device::CheckMultisampleQualityLevels method (d3d11.h).
|
||||
/// </summary>
|
||||
CheckMultisampleQualityLevels = 30,
|
||||
|
||||
/// <summary>
|
||||
/// ID3D11Device::CheckCounterInfo method (d3d11.h).
|
||||
/// </summary>
|
||||
CheckCounterInfo = 31,
|
||||
|
||||
/// <summary>
|
||||
/// ID3D11Device::CheckCounter method (d3d11.h).
|
||||
/// </summary>
|
||||
CheckCounter = 32,
|
||||
|
||||
/// <summary>
|
||||
/// ID3D11Device::CheckFeatureSupport method (d3d11.h).
|
||||
/// </summary>
|
||||
CheckFeatureSupport = 33,
|
||||
|
||||
/// <summary>
|
||||
/// ID3D11Device::GetPrivateData method (d3d11.h).
|
||||
/// </summary>
|
||||
GetPrivateData = 34,
|
||||
|
||||
/// <summary>
|
||||
/// ID3D11Device::SetPrivateData method (d3d11.h).
|
||||
/// </summary>
|
||||
SetPrivateData = 35,
|
||||
|
||||
/// <summary>
|
||||
/// ID3D11Device::SetPrivateDataInterface method (d3d11.h).
|
||||
/// </summary>
|
||||
SetPrivateDataInterface = 36,
|
||||
|
||||
/// <summary>
|
||||
/// ID3D11Device::GetFeatureLevel method (d3d11.h).
|
||||
/// </summary>
|
||||
GetFeatureLevel = 37,
|
||||
|
||||
/// <summary>
|
||||
/// ID3D11Device::GetCreationFlags method (d3d11.h).
|
||||
/// </summary>
|
||||
GetCreationFlags = 38,
|
||||
|
||||
/// <summary>
|
||||
/// ID3D11Device::GetDeviceRemovedReason method (d3d11.h).
|
||||
/// </summary>
|
||||
GetDeviceRemovedReason = 39,
|
||||
|
||||
/// <summary>
|
||||
/// ID3D11Device::GetImmediateContext method (d3d11.h).
|
||||
/// </summary>
|
||||
GetImmediateContext = 40,
|
||||
|
||||
/// <summary>
|
||||
/// ID3D11Device::SetExceptionMode method (d3d11.h).
|
||||
/// </summary>
|
||||
SetExceptionMode = 41,
|
||||
|
||||
/// <summary>
|
||||
/// ID3D11Device::GetExceptionMode method (d3d11.h).
|
||||
/// </summary>
|
||||
GetExceptionMode = 42,
|
||||
}
|
||||
}
|
||||
107
Dalamud/Game/Internal/DXGI/Definitions/IDXGISwapChainVtbl.cs
Normal file
107
Dalamud/Game/Internal/DXGI/Definitions/IDXGISwapChainVtbl.cs
Normal file
|
|
@ -0,0 +1,107 @@
|
|||
namespace Dalamud.Game.Internal.DXGI.Definitions
|
||||
{
|
||||
/// <summary>
|
||||
/// Contains a full list of IDXGISwapChain functions to be used as an indexer into the SwapChain Virtual Function Table
|
||||
/// entries.
|
||||
/// </summary>
|
||||
internal enum IDXGISwapChainVtbl
|
||||
{
|
||||
// IUnknown
|
||||
|
||||
/// <summary>
|
||||
/// IUnknown::QueryInterface method (unknwn.h).
|
||||
/// </summary>
|
||||
QueryInterface = 0,
|
||||
|
||||
/// <summary>
|
||||
/// IUnknown::AddRef method (unknwn.h).
|
||||
/// </summary>
|
||||
AddRef = 1,
|
||||
|
||||
/// <summary>
|
||||
/// IUnknown::Release method (unknwn.h).
|
||||
/// </summary>
|
||||
Release = 2,
|
||||
|
||||
// IDXGIObject
|
||||
|
||||
/// <summary>
|
||||
/// IDXGIObject::SetPrivateData method (dxgi.h).
|
||||
/// </summary>
|
||||
SetPrivateData = 3,
|
||||
|
||||
/// <summary>
|
||||
/// IDXGIObject::SetPrivateDataInterface method (dxgi.h).
|
||||
/// </summary>
|
||||
SetPrivateDataInterface = 4,
|
||||
|
||||
/// <summary>
|
||||
/// IDXGIObject::GetPrivateData method (dxgi.h).
|
||||
/// </summary>
|
||||
GetPrivateData = 5,
|
||||
|
||||
/// <summary>
|
||||
/// IDXGIObject::GetParent method (dxgi.h).
|
||||
/// </summary>
|
||||
GetParent = 6,
|
||||
|
||||
// IDXGIDeviceSubObject
|
||||
|
||||
/// <summary>
|
||||
/// IDXGIDeviceSubObject::GetDevice method (dxgi.h).
|
||||
/// </summary>
|
||||
GetDevice = 7,
|
||||
|
||||
// IDXGISwapChain
|
||||
|
||||
/// <summary>
|
||||
/// IDXGISwapChain::Present method (dxgi.h).
|
||||
/// </summary>
|
||||
Present = 8,
|
||||
|
||||
/// <summary>
|
||||
/// IUnknIDXGISwapChainown::GetBuffer method (dxgi.h).
|
||||
/// </summary>
|
||||
GetBuffer = 9,
|
||||
|
||||
/// <summary>
|
||||
/// IDXGISwapChain::SetFullscreenState method (dxgi.h).
|
||||
/// </summary>
|
||||
SetFullscreenState = 10,
|
||||
|
||||
/// <summary>
|
||||
/// IDXGISwapChain::GetFullscreenState method (dxgi.h).
|
||||
/// </summary>
|
||||
GetFullscreenState = 11,
|
||||
|
||||
/// <summary>
|
||||
/// IDXGISwapChain::GetDesc method (dxgi.h).
|
||||
/// </summary>
|
||||
GetDesc = 12,
|
||||
|
||||
/// <summary>
|
||||
/// IDXGISwapChain::ResizeBuffers method (dxgi.h).
|
||||
/// </summary>
|
||||
ResizeBuffers = 13,
|
||||
|
||||
/// <summary>
|
||||
/// IDXGISwapChain::ResizeTarget method (dxgi.h).
|
||||
/// </summary>
|
||||
ResizeTarget = 14,
|
||||
|
||||
/// <summary>
|
||||
/// IDXGISwapChain::GetContainingOutput method (dxgi.h).
|
||||
/// </summary>
|
||||
GetContainingOutput = 15,
|
||||
|
||||
/// <summary>
|
||||
/// IDXGISwapChain::GetFrameStatistics method (dxgi.h).
|
||||
/// </summary>
|
||||
GetFrameStatistics = 16,
|
||||
|
||||
/// <summary>
|
||||
/// IDXGISwapChain::GetLastPresentCount method (dxgi.h).
|
||||
/// </summary>
|
||||
GetLastPresentCount = 17,
|
||||
}
|
||||
}
|
||||
|
|
@ -22,7 +22,7 @@ namespace Dalamud.Game.Internal.DXGI
|
|||
{
|
||||
var module = Process.GetCurrentProcess().Modules.Cast<ProcessModule>().First(m => m.ModuleName == "dxgi.dll");
|
||||
|
||||
Log.Debug($"Found DXGI: {module.BaseAddress.ToInt64():X}");
|
||||
Log.Debug($"Found DXGI: 0x{module.BaseAddress.ToInt64():X}");
|
||||
|
||||
var scanner = new SigScanner(module);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Windows.Forms;
|
||||
|
||||
using Dalamud.Game.Internal.DXGI.Definitions;
|
||||
using SharpDX.Direct3D;
|
||||
using SharpDX.Direct3D11;
|
||||
using SharpDX.DXGI;
|
||||
|
|
@ -19,9 +19,6 @@ namespace Dalamud.Game.Internal.DXGI
|
|||
/// </remarks>
|
||||
public class SwapChainVtableResolver : BaseAddressResolver, ISwapChainAddressResolver
|
||||
{
|
||||
private const int DxgiSwapchainMethodCount = 18;
|
||||
private const int D3D11DeviceMethodCount = 43;
|
||||
|
||||
private List<IntPtr> d3d11VTblAddresses;
|
||||
private List<IntPtr> dxgiSwapChainVTblAddresses;
|
||||
|
||||
|
|
@ -34,30 +31,33 @@ namespace Dalamud.Game.Internal.DXGI
|
|||
/// <inheritdoc/>
|
||||
protected override void Setup64Bit(SigScanner sig)
|
||||
{
|
||||
// Create temporary device + swapchain and determine method addresses
|
||||
if (this.d3d11VTblAddresses == null)
|
||||
{
|
||||
// Create temporary device + swapchain and determine method addresses
|
||||
var renderForm = new Form();
|
||||
// A renderable object isnt required, just a handle
|
||||
var handle = Marshal.AllocHGlobal(Marshal.SizeOf<IntPtr>());
|
||||
|
||||
Device.CreateWithSwapChain(
|
||||
DriverType.Hardware,
|
||||
DeviceCreationFlags.BgraSupport,
|
||||
CreateSwapChainDescription(renderForm.Handle),
|
||||
CreateSwapChainDescription(handle),
|
||||
out var device,
|
||||
out var swapChain);
|
||||
|
||||
if (device != null && swapChain != null)
|
||||
{
|
||||
this.d3d11VTblAddresses = this.GetVTblAddresses(device.NativePointer, D3D11DeviceMethodCount);
|
||||
this.dxgiSwapChainVTblAddresses = this.GetVTblAddresses(swapChain.NativePointer, DxgiSwapchainMethodCount);
|
||||
this.d3d11VTblAddresses = GetVTblAddresses(device.NativePointer, Enum.GetValues(typeof(ID3D11DeviceVtbl)).Length);
|
||||
this.dxgiSwapChainVTblAddresses = GetVTblAddresses(swapChain.NativePointer, Enum.GetValues(typeof(IDXGISwapChainVtbl)).Length);
|
||||
}
|
||||
|
||||
device?.Dispose();
|
||||
swapChain?.Dispose();
|
||||
|
||||
Marshal.FreeHGlobal(handle);
|
||||
}
|
||||
|
||||
this.Present = this.dxgiSwapChainVTblAddresses[8];
|
||||
this.ResizeBuffers = this.dxgiSwapChainVTblAddresses[13];
|
||||
this.Present = this.dxgiSwapChainVTblAddresses[(int)IDXGISwapChainVtbl.Present];
|
||||
this.ResizeBuffers = this.dxgiSwapChainVTblAddresses[(int)IDXGISwapChainVtbl.ResizeBuffers];
|
||||
}
|
||||
|
||||
private static SwapChainDescription CreateSwapChainDescription(IntPtr renderForm)
|
||||
|
|
@ -75,12 +75,12 @@ namespace Dalamud.Game.Internal.DXGI
|
|||
};
|
||||
}
|
||||
|
||||
private List<IntPtr> GetVTblAddresses(IntPtr pointer, int numberOfMethods)
|
||||
private static List<IntPtr> GetVTblAddresses(IntPtr pointer, int numberOfMethods)
|
||||
{
|
||||
return this.GetVTblAddresses(pointer, 0, numberOfMethods);
|
||||
return GetVTblAddresses(pointer, 0, numberOfMethods);
|
||||
}
|
||||
|
||||
private List<IntPtr> GetVTblAddresses(IntPtr pointer, int startIndex, int numberOfMethods)
|
||||
private static List<IntPtr> GetVTblAddresses(IntPtr pointer, int startIndex, int numberOfMethods)
|
||||
{
|
||||
var vtblAddresses = new List<IntPtr>();
|
||||
var vTable = Marshal.ReadIntPtr(pointer);
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ using System.Collections.Generic;
|
|||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
|
||||
using Dalamud.Game.Internal.Gui;
|
||||
using Dalamud.Game.Internal.Libc;
|
||||
|
|
@ -29,13 +30,13 @@ namespace Dalamud.Game.Internal
|
|||
/// </summary>
|
||||
/// <param name="scanner">The SigScanner instance.</param>
|
||||
/// <param name="dalamud">The Dalamud instance.</param>
|
||||
public Framework(SigScanner scanner, Dalamud dalamud)
|
||||
internal Framework(SigScanner scanner, Dalamud dalamud)
|
||||
{
|
||||
this.dalamud = dalamud;
|
||||
this.Address = new FrameworkAddressResolver();
|
||||
this.Address.Setup(scanner);
|
||||
|
||||
Log.Verbose("Framework address {FrameworkAddress}", this.Address.BaseAddress);
|
||||
Log.Verbose($"Framework address 0x{this.Address.BaseAddress.ToInt64():X}");
|
||||
if (this.Address.BaseAddress == IntPtr.Zero)
|
||||
{
|
||||
throw new InvalidOperationException("Framework is not initalized yet.");
|
||||
|
|
@ -143,6 +144,11 @@ namespace Dalamud.Game.Internal
|
|||
this.Gui.Dispose();
|
||||
this.Network.Dispose();
|
||||
|
||||
this.updateHook.Disable();
|
||||
this.destroyHook.Disable();
|
||||
this.realDestroyHook.Disable();
|
||||
Thread.Sleep(500);
|
||||
|
||||
this.updateHook.Dispose();
|
||||
this.destroyHook.Dispose();
|
||||
this.realDestroyHook.Dispose();
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ namespace Dalamud.Game.Internal
|
|||
// 00007FF701AD666A | 48 8D ?? ?? ?? 00 00 | LEA RCX,QWORD PTR DS:[RBX + 2C38]
|
||||
// 00007FF701AD6671 | E8 ?? ?? ?? ?? | CALL ffxiv_dx11.7FF701E2A7D0
|
||||
// 00007FF701AD6676 | 48 8D ?? ?? ?? ?? ?? | LEA RAX,QWORD PTR DS:[7FF702C31F80
|
||||
var fwDtor = scanner.ScanText("48C705????????00000000 E8???????? 488D??????0000 E8???????? 488D");
|
||||
var fwDtor = scanner.ScanText("48 C7 05 ?? ?? ?? ?? 00 00 00 00 E8 ?? ?? ?? ?? 48 8D ?? ?? ?? 00 00 E8 ?? ?? ?? ?? 48 8D");
|
||||
var fwOffset = Marshal.ReadInt32(fwDtor + 3);
|
||||
var pFramework = scanner.ResolveRelativeAddress(fwDtor + 11, fwOffset);
|
||||
|
||||
|
|
|
|||
|
|
@ -36,14 +36,14 @@ namespace Dalamud.Game.Internal.Gui
|
|||
/// <param name="baseAddress">The base address of the ChatManager.</param>
|
||||
/// <param name="scanner">The SigScanner instance.</param>
|
||||
/// <param name="dalamud">The Dalamud instance.</param>
|
||||
public ChatGui(IntPtr baseAddress, SigScanner scanner, Dalamud dalamud)
|
||||
internal ChatGui(IntPtr baseAddress, SigScanner scanner, Dalamud dalamud)
|
||||
{
|
||||
this.dalamud = dalamud;
|
||||
|
||||
this.address = new ChatGuiAddressResolver(baseAddress);
|
||||
this.address.Setup(scanner);
|
||||
|
||||
Log.Verbose("Chat manager address {ChatManager}", this.address.BaseAddress);
|
||||
Log.Verbose($"Chat manager address 0x{this.address.BaseAddress.ToInt64():X}");
|
||||
|
||||
this.printMessageHook = new Hook<PrintMessageDelegate>(this.address.PrintMessage, this.HandlePrintMessageDetour);
|
||||
this.populateItemLinkHook = new Hook<PopulateItemLinkDelegate>(this.address.PopulateItemLinkObject, this.HandlePopulateItemLinkDetour);
|
||||
|
|
@ -252,7 +252,7 @@ namespace Dalamud.Game.Internal.Gui
|
|||
var senderRaw = Encoding.UTF8.GetBytes(chat.Name ?? string.Empty);
|
||||
using var senderOwned = framework.Libc.NewString(senderRaw);
|
||||
|
||||
var messageRaw = chat.MessageBytes ?? new byte[0];
|
||||
var messageRaw = chat.MessageBytes ?? Array.Empty<byte>();
|
||||
using var messageOwned = framework.Libc.NewString(messageRaw);
|
||||
|
||||
this.HandlePrintMessageDetour(this.baseAddress, chat.Type, senderOwned.Address, messageOwned.Address, chat.SenderId, chat.Parameters);
|
||||
|
|
|
|||
|
|
@ -10,10 +10,10 @@ namespace Dalamud.Game.Internal.Gui
|
|||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ChatGuiAddressResolver"/> class.
|
||||
/// </summary>
|
||||
/// <param name="baseAddres">The base address of the native ChatManager class.</param>
|
||||
public ChatGuiAddressResolver(IntPtr baseAddres)
|
||||
/// <param name="baseAddress">The base address of the native ChatManager class.</param>
|
||||
public ChatGuiAddressResolver(IntPtr baseAddress)
|
||||
{
|
||||
this.BaseAddress = baseAddres;
|
||||
this.BaseAddress = baseAddress;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ namespace Dalamud.Game.Internal.Gui
|
|||
/// <param name="baseAddress">The base address of the native GuiManager class.</param>
|
||||
/// <param name="scanner">The SigScanner instance.</param>
|
||||
/// <param name="dalamud">The Dalamud instance.</param>
|
||||
public GameGui(IntPtr baseAddress, SigScanner scanner, Dalamud dalamud)
|
||||
internal GameGui(IntPtr baseAddress, SigScanner scanner, Dalamud dalamud)
|
||||
{
|
||||
this.dalamud = dalamud;
|
||||
|
||||
|
|
@ -56,12 +56,12 @@ namespace Dalamud.Game.Internal.Gui
|
|||
|
||||
Log.Verbose("===== G A M E G U I =====");
|
||||
|
||||
Log.Verbose("GameGuiManager address {Address:X}", this.address.BaseAddress.ToInt64());
|
||||
Log.Verbose("SetGlobalBgm address {Address:X}", this.address.SetGlobalBgm.ToInt64());
|
||||
Log.Verbose("HandleItemHover address {Address:X}", this.address.HandleItemHover.ToInt64());
|
||||
Log.Verbose("HandleItemOut address {Address:X}", this.address.HandleItemOut.ToInt64());
|
||||
Log.Verbose("GetUIObject address {Address:X}", this.address.GetUIObject.ToInt64());
|
||||
Log.Verbose("GetAgentModule address {Address:X}", this.address.GetAgentModule.ToInt64());
|
||||
Log.Verbose($"GameGuiManager address 0x{this.address.BaseAddress.ToInt64():X}");
|
||||
Log.Verbose($"SetGlobalBgm address 0x{this.address.SetGlobalBgm.ToInt64():X}");
|
||||
Log.Verbose($"HandleItemHover address 0x{this.address.HandleItemHover.ToInt64():X}");
|
||||
Log.Verbose($"HandleItemOut address 0x{this.address.HandleItemOut.ToInt64():X}");
|
||||
Log.Verbose($"GetUIObject address 0x{this.address.GetUIObject.ToInt64():X}");
|
||||
Log.Verbose($"GetAgentModule address 0x{this.address.GetAgentModule.ToInt64():X}");
|
||||
|
||||
this.Chat = new ChatGui(this.address.ChatManager, scanner, dalamud);
|
||||
this.PartyFinder = new PartyFinderGui(scanner, dalamud);
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ namespace Dalamud.Game.Internal.Gui
|
|||
/// </summary>
|
||||
/// <param name="scanner">The SigScanner instance.</param>
|
||||
/// <param name="dalamud">The Dalamud instance.</param>
|
||||
public PartyFinderGui(SigScanner scanner, Dalamud dalamud)
|
||||
internal PartyFinderGui(SigScanner scanner, Dalamud dalamud)
|
||||
{
|
||||
this.dalamud = dalamud;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
using System.Runtime.InteropServices;
|
||||
|
||||
using FFXIVClientStructs.FFXIV.Component.GUI;
|
||||
|
||||
namespace Dalamud.Game.Internal.Gui.Structs
|
||||
{
|
||||
/// <summary>
|
||||
|
|
|
|||
|
|
@ -1,130 +0,0 @@
|
|||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Dalamud.Game.Internal.Gui.Structs
|
||||
{
|
||||
/// <summary>
|
||||
/// Native memory representation of a UI resource node.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This is copied from https://github.com/aers/FFXIVClientStructs/blob/main/Component/GUI/AtkResNode.cs.
|
||||
/// If you need newer features, include FFXIVClientStructs and ILMerge the assembly.
|
||||
/// </remarks>
|
||||
[StructLayout(LayoutKind.Explicit, Size = 0xA8)]
|
||||
public unsafe struct AtkResNode
|
||||
{
|
||||
[FieldOffset(0x0)]
|
||||
public IntPtr AtkEventTarget;
|
||||
|
||||
[FieldOffset(0x8)]
|
||||
public uint NodeID;
|
||||
|
||||
[FieldOffset(0x20)]
|
||||
public AtkResNode* ParentNode;
|
||||
|
||||
[FieldOffset(0x28)]
|
||||
public AtkResNode* PrevSiblingNode;
|
||||
|
||||
[FieldOffset(0x30)]
|
||||
public AtkResNode* NextSiblingNode;
|
||||
|
||||
[FieldOffset(0x38)]
|
||||
public AtkResNode* ChildNode;
|
||||
|
||||
[FieldOffset(0x40)]
|
||||
public ushort Type;
|
||||
|
||||
[FieldOffset(0x42)]
|
||||
public ushort ChildCount;
|
||||
|
||||
[FieldOffset(0x44)]
|
||||
public float X;
|
||||
|
||||
[FieldOffset(0x48)]
|
||||
public float Y;
|
||||
|
||||
[FieldOffset(0x4C)]
|
||||
public float ScaleX;
|
||||
|
||||
[FieldOffset(0x50)]
|
||||
public float ScaleY;
|
||||
|
||||
[FieldOffset(0x54)]
|
||||
public float Rotation;
|
||||
|
||||
[FieldOffset(0x58)]
|
||||
public fixed float UnkMatrix[3 * 2];
|
||||
|
||||
[FieldOffset(0x70)]
|
||||
public uint Color;
|
||||
|
||||
[FieldOffset(0x74)]
|
||||
public float Depth;
|
||||
|
||||
[FieldOffset(0x78)]
|
||||
public float Depth_2;
|
||||
|
||||
[FieldOffset(0x7C)]
|
||||
public ushort AddRed;
|
||||
|
||||
[FieldOffset(0x7E)]
|
||||
public ushort AddGreen;
|
||||
|
||||
[FieldOffset(0x80)]
|
||||
public ushort AddBlue;
|
||||
|
||||
[FieldOffset(0x82)]
|
||||
public ushort AddRed_2;
|
||||
|
||||
[FieldOffset(0x84)]
|
||||
public ushort AddGreen_2;
|
||||
|
||||
[FieldOffset(0x86)]
|
||||
public ushort AddBlue_2;
|
||||
|
||||
[FieldOffset(0x88)]
|
||||
public byte MultiplyRed;
|
||||
|
||||
[FieldOffset(0x89)]
|
||||
public byte MultiplyGreen;
|
||||
|
||||
[FieldOffset(0x8A)]
|
||||
public byte MultiplyBlue;
|
||||
|
||||
[FieldOffset(0x8B)]
|
||||
public byte MultiplyRed_2;
|
||||
|
||||
[FieldOffset(0x8C)]
|
||||
public byte MultiplyGreen_2;
|
||||
|
||||
[FieldOffset(0x8D)]
|
||||
public byte MultiplyBlue_2;
|
||||
|
||||
[FieldOffset(0x8E)]
|
||||
public byte Alpha_2;
|
||||
|
||||
[FieldOffset(0x8F)]
|
||||
public byte UnkByte_1;
|
||||
|
||||
[FieldOffset(0x90)]
|
||||
public ushort Width;
|
||||
|
||||
[FieldOffset(0x92)]
|
||||
public ushort Height;
|
||||
|
||||
[FieldOffset(0x94)]
|
||||
public float OriginX;
|
||||
|
||||
[FieldOffset(0x98)]
|
||||
public float OriginY;
|
||||
|
||||
[FieldOffset(0x9C)]
|
||||
public ushort Priority;
|
||||
|
||||
[FieldOffset(0x9E)]
|
||||
public short Flags;
|
||||
|
||||
[FieldOffset(0xA0)]
|
||||
public uint Flags_2;
|
||||
}
|
||||
}
|
||||
|
|
@ -31,7 +31,7 @@ namespace Dalamud.Game.Internal.Gui
|
|||
/// </summary>
|
||||
/// <param name="scanner">The SigScanner instance.</param>
|
||||
/// <param name="dalamud">The Dalamud instance.</param>
|
||||
public ToastGui(SigScanner scanner, Dalamud dalamud)
|
||||
internal ToastGui(SigScanner scanner, Dalamud dalamud)
|
||||
{
|
||||
this.dalamud = dalamud;
|
||||
|
||||
|
|
|
|||
|
|
@ -34,8 +34,8 @@ namespace Dalamud.Game.Internal.Network
|
|||
this.address.Setup(scanner);
|
||||
|
||||
Log.Verbose("===== G A M E N E T W O R K =====");
|
||||
Log.Verbose("ProcessZonePacketDown address {ProcessZonePacketDown}", this.address.ProcessZonePacketDown);
|
||||
Log.Verbose("ProcessZonePacketUp address {ProcessZonePacketUp}", this.address.ProcessZonePacketUp);
|
||||
Log.Verbose($"ProcessZonePacketDown address 0x{this.address.ProcessZonePacketDown.ToInt64():X}");
|
||||
Log.Verbose($"ProcessZonePacketUp address 0x{this.address.ProcessZonePacketUp.ToInt64():X}");
|
||||
|
||||
this.processZonePacketDownHook = new Hook<ProcessZonePacketDownDelegate>(this.address.ProcessZonePacketDown, this.ProcessZonePacketDownDetour);
|
||||
this.processZonePacketUpHook = new Hook<ProcessZonePacketUpDelegate>(this.address.ProcessZonePacketUp, this.ProcessZonePacketUpDetour);
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ namespace Dalamud.Game.Internal.File
|
|||
/// </summary>
|
||||
/// <param name="dalamud">The Dalamud instance.</param>
|
||||
/// <param name="scanner">The SigScanner instance.</param>
|
||||
public ResourceManager(Dalamud dalamud, SigScanner scanner)
|
||||
internal ResourceManager(Dalamud dalamud, SigScanner scanner)
|
||||
{
|
||||
this.dalamud = dalamud;
|
||||
this.address = new ResourceManagerAddressResolver();
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ namespace Dalamud.Game.Network
|
|||
/// </summary>
|
||||
/// <param name="dalamud">The Dalamud instance.</param>
|
||||
/// <param name="optOutMbUploads">Whether the client should opt out of marketboard uploads.</param>
|
||||
public NetworkHandlers(Dalamud dalamud, bool optOutMbUploads)
|
||||
internal NetworkHandlers(Dalamud dalamud, bool optOutMbUploads)
|
||||
{
|
||||
this.dalamud = dalamud;
|
||||
this.optOutMbUploads = optOutMbUploads;
|
||||
|
|
@ -84,11 +84,11 @@ namespace Dalamud.Game.Network
|
|||
{
|
||||
var flashInfo = new NativeFunctions.FlashWindowInfo
|
||||
{
|
||||
cbSize = (uint)Marshal.SizeOf<NativeFunctions.FlashWindowInfo>(),
|
||||
uCount = uint.MaxValue,
|
||||
dwTimeout = 0,
|
||||
dwFlags = NativeFunctions.FlashWindow.All | NativeFunctions.FlashWindow.TimerNoFG,
|
||||
hwnd = Process.GetCurrentProcess().MainWindowHandle,
|
||||
Size = (uint)Marshal.SizeOf<NativeFunctions.FlashWindowInfo>(),
|
||||
Count = uint.MaxValue,
|
||||
Timeout = 0,
|
||||
Flags = NativeFunctions.FlashWindow.All | NativeFunctions.FlashWindow.TimerNoFG,
|
||||
Hwnd = Process.GetCurrentProcess().MainWindowHandle,
|
||||
};
|
||||
NativeFunctions.FlashWindowEx(ref flashInfo);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,8 +34,8 @@ namespace Dalamud.Game
|
|||
if (this.IsCopy)
|
||||
this.SetupCopiedSegments();
|
||||
|
||||
Log.Verbose("Module base: {Address}", this.TextSectionBase);
|
||||
Log.Verbose("Module size: {Size}", this.TextSectionSize);
|
||||
Log.Verbose($"Module base: 0x{this.TextSectionBase.ToInt64():X}");
|
||||
Log.Verbose($"Module size: 0x{this.TextSectionSize:X}");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -206,7 +206,7 @@ namespace Dalamud.Game
|
|||
var insnByte = Marshal.ReadByte(scanRet);
|
||||
|
||||
if (insnByte == 0xE8 || insnByte == 0xE9)
|
||||
return ReadCallSig(scanRet);
|
||||
return ReadJmpCallSig(scanRet);
|
||||
|
||||
return scanRet;
|
||||
}
|
||||
|
|
@ -220,13 +220,13 @@ namespace Dalamud.Game
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper for ScanText to get the correct address for IDA sigs that mark the first CALL location.
|
||||
/// Helper for ScanText to get the correct address for IDA sigs that mark the first JMP or CALL location.
|
||||
/// </summary>
|
||||
/// <param name="sigLocation">The address the CALL sig resolved to.</param>
|
||||
/// <param name="sigLocation">The address the JMP or CALL sig resolved to.</param>
|
||||
/// <returns>The real offset of the signature.</returns>
|
||||
private static IntPtr ReadCallSig(IntPtr sigLocation)
|
||||
private static IntPtr ReadJmpCallSig(IntPtr sigLocation)
|
||||
{
|
||||
var jumpOffset = Marshal.ReadInt32(IntPtr.Add(sigLocation, 1));
|
||||
var jumpOffset = Marshal.ReadInt32(sigLocation, 1);
|
||||
return IntPtr.Add(sigLocation, 5 + jumpOffset);
|
||||
}
|
||||
|
||||
|
|
@ -235,6 +235,7 @@ namespace Dalamud.Game
|
|||
signature = signature.Replace(" ", string.Empty);
|
||||
if (signature.Length % 2 != 0)
|
||||
throw new ArgumentException("Signature without whitespaces must be divisible by two.", nameof(signature));
|
||||
|
||||
var needleLength = signature.Length / 2;
|
||||
var needle = new byte[needleLength];
|
||||
var mask = new bool[needleLength];
|
||||
|
|
|
|||
|
|
@ -88,7 +88,7 @@ namespace Dalamud.Game.Text.SeStringHandling
|
|||
/// <returns>An SeString containing all the payloads necessary to display an item link in the chat log.</returns>
|
||||
public SeString CreateItemLink(Item item, bool isHQ, string displayNameOverride = null)
|
||||
{
|
||||
return this.CreateItemLink((uint)item.RowId, isHQ, displayNameOverride ?? item.Name);
|
||||
return this.CreateItemLink(item.RowId, isHQ, displayNameOverride ?? item.Name);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
|||
|
|
@ -18,26 +18,15 @@ using System.Diagnostics.CodeAnalysis;
|
|||
// Extensions
|
||||
[assembly: SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1402:File may only contain a single type", Justification = "Group extensions with the relevant class", Scope = "type", Target = "~T:Dalamud.Interface.FontAwesomeExtensions")]
|
||||
[assembly: SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1649:File name should match first type name", Justification = "Enum followed by an extension", Scope = "type", Target = "~T:Dalamud.Interface.FontAwesomeExtensions")]
|
||||
[assembly: SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1402:File may only contain a single type", Justification = "Group extensions with the relevant class", Scope = "type", Target = "~T:Dalamud.Game.Internal.Gui.Structs.JobFlagsExtensions")]
|
||||
[assembly: SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1649:File name should match first type name", Justification = "Enum followed by an extension", Scope = "type", Target = "~T:Dalamud.Game.Internal.Gui.Structs.JobFlagsExtensions")]
|
||||
[assembly: SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1402:File may only contain a single type", Justification = "Group extensions with the relevant class", Scope = "type", Target = "~T:Dalamud.Game.Internal.Gui.Structs.JobFlagsExt")]
|
||||
[assembly: SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1649:File name should match first type name", Justification = "Enum followed by an extension", Scope = "type", Target = "~T:Dalamud.Game.Internal.Gui.Structs.JobFlagsExt")]
|
||||
[assembly: SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1402:File may only contain a single type", Justification = "Group extensions with the relevant class", Scope = "type", Target = "~T:Dalamud.Game.Text.XivChatTypeExtensions")]
|
||||
[assembly: SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1649:File name should match first type name", Justification = "Enum followed by an extension", Scope = "type", Target = "~T:Dalamud.Game.Text.XivChatTypeExtensions")]
|
||||
[assembly: SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1402:File may only contain a single type", Justification = "Group attributes with the relevant class", Scope = "type", Target = "~T:Dalamud.Game.Text.XivChatTypeInfoAttribute")]
|
||||
|
||||
// NativeFunctions.cs
|
||||
[assembly: SuppressMessage("StyleCop.CSharp.NamingRules", "SA1307:Accessible fields should begin with upper-case letter", Justification = "Default Microsoft naming", Scope = "type", Target = "~T:Dalamud.NativeFunctions.FlashWindowInfo")]
|
||||
|
||||
// EntryPoint.cs
|
||||
[assembly: SuppressMessage("Style", "IDE0060:Remove unused parameter", Justification = "Required by EasyHook", Scope = "member", Target = "~M:Dalamud.EntryPoint.#ctor(EasyHook.RemoteHooking.IContext,Dalamud.DalamudStartInfo)")]
|
||||
[assembly: SuppressMessage("Style", "IDE0060:Remove unused parameter", Justification = "Required by EasyHook", Scope = "member", Target = "~M:Dalamud.EntryPoint.Run(EasyHook.RemoteHooking.IContext,Dalamud.DalamudStartInfo)")]
|
||||
|
||||
// DalamudStartInfo.cs
|
||||
[assembly: SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1401:Fields should be private", Justification = "Interop", Scope = "type", Target = "~T:Dalamud.DalamudStartInfo")]
|
||||
|
||||
// AtkResNode.cs
|
||||
[assembly: SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1600:Elements should be documented", Justification = "Inherit documentation or lack thereof from FFXIVClientStructs", Scope = "type", Target = "~T:Dalamud.Game.Internal.Gui.Structs.AtkResNode")]
|
||||
[assembly: SuppressMessage("StyleCop.CSharp.NamingRules", "SA1310:Field names should not contain underscore", Justification = "Inherit naming from FFXIVClientStructs", Scope = "type", Target = "~T:Dalamud.Game.Internal.Gui.Structs.AtkResNode")]
|
||||
|
||||
// PartyFinder
|
||||
[assembly: SuppressMessage("StyleCop.CSharp.OrderingRules", "SA1202:Elements should be ordered by access", Justification = "Explicit struct layout", Scope = "type", Target = "~T:Dalamud.Game.Internal.Gui.Structs.PartyFinder.Packet")]
|
||||
[assembly: SuppressMessage("StyleCop.CSharp.OrderingRules", "SA1202:Elements should be ordered by access", Justification = "Explicit struct layout", Scope = "type", Target = "~T:Dalamud.Game.Internal.Gui.Structs.PartyFinder.Listing")]
|
||||
|
|
@ -86,9 +75,7 @@ using System.Diagnostics.CodeAnalysis;
|
|||
[assembly: SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1401:Fields should be private", Justification = "breaking api change", Scope = "member", Target = "~F:Dalamud.Game.ClientState.ClientState.GamepadState")]
|
||||
[assembly: SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1401:Fields should be private", Justification = "breaking api change", Scope = "member", Target = "~F:Dalamud.Game.ClientState.ClientState.Condition")]
|
||||
[assembly: SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1401:Fields should be private", Justification = "breaking api change", Scope = "member", Target = "~F:Dalamud.Game.ClientState.ClientState.Targets")]
|
||||
[assembly: SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1401:Fields should be private", Justification = "breaking api change", Scope = "member", Target = "~F:Dalamud.Interface.InterfaceManager.LastImGuiIoPtr")]
|
||||
[assembly: SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1401:Fields should be private", Justification = "breaking api change", Scope = "type", Target = "~T:Dalamud.Game.ClientState.Actors.Types.PartyMember")]
|
||||
[assembly: SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1401:Fields should be private", Justification = "breaking api change", Scope = "member", Target = "~F:Dalamud.Interface.InterfaceManager.OnBuildFonts")]
|
||||
[assembly: SuppressMessage("StyleCop.CSharp.OrderingRules", "SA1201:Elements should appear in the correct order", Justification = "breaking api change", Scope = "member", Target = "~F:Dalamud.Game.ClientState.Actors.Types.Actor.Address")]
|
||||
[assembly: SuppressMessage("StyleCop.CSharp.OrderingRules", "SA1202:Elements should be ordered by access", Justification = "breaking api change", Scope = "member", Target = "~F:Dalamud.Game.ClientState.Structs.JobGauge.BLMGauge.NumUmbralHearts")]
|
||||
[assembly: SuppressMessage("StyleCop.CSharp.OrderingRules", "SA1202:Elements should be ordered by access", Justification = "breaking api change", Scope = "member", Target = "~F:Dalamud.Game.ClientState.Structs.JobGauge.DNCGauge.NumCompleteSteps")]
|
||||
|
|
@ -97,10 +84,12 @@ using System.Diagnostics.CodeAnalysis;
|
|||
[assembly: SuppressMessage("StyleCop.CSharp.NamingRules", "SA1310:Field names should not contain underscore", Justification = "breaking api change", Scope = "member", Target = "~F:Dalamud.Game.Text.SeStringHandling.Payload.END_BYTE")]
|
||||
[assembly: SuppressMessage("CodeQuality", "IDE0052:Remove unread private members", Justification = "Unused, but eventually, maybe.", Scope = "member", Target = "~F:Dalamud.Game.ClientState.PartyList.address")]
|
||||
[assembly: SuppressMessage("Style", "IDE1006:Naming Styles", Justification = "breaking api change", Scope = "member", Target = "~E:Dalamud.Game.ClientState.ClientState.CfPop")]
|
||||
[assembly: SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1401:Fields should be private", Justification = "breaking api change", Scope = "member", Target = "~F:Dalamud.Game.Internal.Framework.StatsHistory")]
|
||||
[assembly: SuppressMessage("StyleCop.CSharp.OrderingRules", "SA1201:Elements should appear in the correct order", Justification = "breaking api change", Scope = "member", Target = "~F:Dalamud.Game.Internal.Framework.StatsHistory")]
|
||||
[assembly: SuppressMessage("StyleCop.CSharp.OrderingRules", "SA1204:Static elements should appear before instance elements", Justification = "breaking api change, move to util", Scope = "type", Target = "~T:Dalamud.Game.Text.EnumExtensions")]
|
||||
[assembly: SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1402:File may only contain a single type", Justification = "breaking api change, move to util", Scope = "type", Target = "~T:Dalamud.Game.Text.EnumExtensions")]
|
||||
[assembly: SuppressMessage("StyleCop.CSharp.OrderingRules", "SA1201:Elements should appear in the correct order", Justification = "breaking api change", Scope = "member", Target = "~F:Dalamud.Game.Internal.Framework.StatsHistory")]
|
||||
[assembly: SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1401:Fields should be private", Justification = "breaking api change", Scope = "member", Target = "~F:Dalamud.Game.Internal.Framework.StatsHistory")]
|
||||
[assembly: SuppressMessage("Usage", "CA2211:Non-constant fields should not be visible", Justification = "breaking api change", Scope = "member", Target = "~F:Dalamud.Game.Internal.Framework.StatsHistory")]
|
||||
[assembly: SuppressMessage("Usage", "CA2208:Instantiate argument exceptions correctly", Justification = "Appears to be a bug, it is being used correctly", Scope = "member", Target = "~M:Dalamud.Data.DataManager.Initialize(System.String)")]
|
||||
|
||||
// I mostly didnt care to do these.
|
||||
[assembly: SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1401:Fields should be private", Justification = "breaking api change", Scope = "member", Target = "~F:Dalamud.Game.Internal.Network.GameNetwork.OnNetworkMessage")]
|
||||
|
|
|
|||
|
|
@ -3,7 +3,8 @@ using System.Reflection;
|
|||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
using EasyHook;
|
||||
using CoreHook;
|
||||
using Dalamud.Hooking.Internal;
|
||||
|
||||
namespace Dalamud.Hooking
|
||||
{
|
||||
|
|
@ -30,8 +31,8 @@ namespace Dalamud.Hooking
|
|||
{
|
||||
this.hookInfo = LocalHook.Create(address, detour, null); // Installs a hook here
|
||||
this.address = address;
|
||||
this.original = Marshal.GetDelegateForFunctionPointer<T>(this.hookInfo.HookBypassAddress);
|
||||
HookInfo.TrackedHooks.Add(new HookInfo() { Delegate = detour, Hook = this, Assembly = Assembly.GetCallingAssembly() });
|
||||
this.original = Marshal.GetDelegateForFunctionPointer<T>(this.hookInfo.OriginalAddress);
|
||||
HookManager.TrackedHooks.Add(new HookInfo() { Delegate = detour, Hook = this, Assembly = Assembly.GetCallingAssembly() });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -130,9 +131,8 @@ namespace Dalamud.Hooking
|
|||
return;
|
||||
}
|
||||
|
||||
this.hookInfo.Dispose();
|
||||
|
||||
this.IsDisposed = true;
|
||||
this.hookInfo.Dispose();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
|||
|
|
@ -3,18 +3,13 @@ using System.Collections.Generic;
|
|||
using System.Diagnostics;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Dalamud.Hooking
|
||||
namespace Dalamud.Hooking.Internal
|
||||
{
|
||||
/// <summary>
|
||||
/// Class containing information about registered hooks.
|
||||
/// </summary>
|
||||
internal class HookInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// Static list of tracked and registered hooks.
|
||||
/// </summary>
|
||||
internal static readonly List<HookInfo> TrackedHooks = new();
|
||||
|
||||
private ulong? inProcessMemory = 0;
|
||||
|
||||
/// <summary>
|
||||
33
Dalamud/Hooking/Internal/HookManager.cs
Normal file
33
Dalamud/Hooking/Internal/HookManager.cs
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Dalamud.Hooking.Internal
|
||||
{
|
||||
/// <summary>
|
||||
/// This class manages the final disposition of hooks, cleaning up any that have not reverted their changes.
|
||||
/// </summary>
|
||||
internal class HookManager : IDisposable
|
||||
{
|
||||
// private readonly Dalamud dalamud;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="HookManager"/> class.
|
||||
/// </summary>
|
||||
/// <param name="dalamud">Dalamud instance.</param>
|
||||
public HookManager(Dalamud dalamud)
|
||||
{
|
||||
_ = dalamud;
|
||||
// this.dalamud = dalamud;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a static list of tracked and registered hooks.
|
||||
/// </summary>
|
||||
internal static List<HookInfo> TrackedHooks { get; } = new();
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Dispose()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
using System;
|
||||
|
||||
namespace Dalamud.Hooking
|
||||
namespace Dalamud.Hooking.Internal
|
||||
{
|
||||
/// <summary>
|
||||
/// Interface describing a generic hook.
|
||||
|
|
@ -1,61 +0,0 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
|
||||
using Dalamud.Interface.Windowing;
|
||||
using ImGuiNET;
|
||||
|
||||
namespace Dalamud.Interface.Colors
|
||||
{
|
||||
/// <summary>
|
||||
/// color Demo Window to view custom ImGui colors.
|
||||
/// </summary>
|
||||
internal class ColorDemoWindow : Window
|
||||
{
|
||||
private readonly List<KeyValuePair<string, Vector4>> colors;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ColorDemoWindow"/> class.
|
||||
/// </summary>
|
||||
public ColorDemoWindow()
|
||||
: base("Dalamud Colors Demo")
|
||||
{
|
||||
this.Size = new Vector2(600, 500);
|
||||
this.SizeCondition = ImGuiCond.FirstUseEver;
|
||||
this.colors = new List<KeyValuePair<string, Vector4>>
|
||||
{
|
||||
Demo("White", ImGuiColors.White),
|
||||
Demo("DalamudRed", ImGuiColors.DalamudRed),
|
||||
Demo("DalamudGrey", ImGuiColors.DalamudGrey),
|
||||
Demo("DalamudGrey2", ImGuiColors.DalamudGrey2),
|
||||
Demo("DalamudGrey3", ImGuiColors.DalamudGrey3),
|
||||
Demo("DalamudWhite", ImGuiColors.DalamudWhite),
|
||||
Demo("DalamudWhite2", ImGuiColors.DalamudWhite2),
|
||||
Demo("DalamudOrange", ImGuiColors.DalamudOrange),
|
||||
Demo("TankBlue", ImGuiColors.TankBlue),
|
||||
Demo("HealerGreen", ImGuiColors.HealerGreen),
|
||||
Demo("DPSRed", ImGuiColors.DPSRed),
|
||||
};
|
||||
this.colors = this.colors.OrderBy(colorDemo => colorDemo.Key).ToList();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void Draw()
|
||||
{
|
||||
ImGui.BeginChild("color_scrolling", new Vector2(0, 0), false, ImGuiWindowFlags.AlwaysVerticalScrollbar | ImGuiWindowFlags.HorizontalScrollbar);
|
||||
ImGui.Text("This is a collection of UI colors you can use in your plugin.");
|
||||
ImGui.Separator();
|
||||
foreach (var color in this.colors)
|
||||
{
|
||||
ImGui.TextColored(color.Value, color.Key);
|
||||
}
|
||||
|
||||
ImGui.EndChild();
|
||||
}
|
||||
|
||||
private static KeyValuePair<string, Vector4> Demo(string name, Vector4 color)
|
||||
{
|
||||
return new KeyValuePair<string, Vector4>(name, color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,76 @@
|
|||
using System.Numerics;
|
||||
|
||||
using ImGuiNET;
|
||||
|
||||
namespace Dalamud.Interface.Components
|
||||
{
|
||||
/// <summary>
|
||||
/// Class containing various methods providing ImGui components.
|
||||
/// </summary>
|
||||
public static partial class ImGuiComponents
|
||||
{
|
||||
/// <summary>
|
||||
/// Alpha modified IconButton component to use an icon as a button with alpha and color options.
|
||||
/// </summary>
|
||||
/// <param name="icon">The icon for the button.</param>
|
||||
/// <param name="id">The ID of the button.</param>
|
||||
/// <param name="defaultColor">The default color of the button.</param>
|
||||
/// <param name="activeColor">The color of the button when active.</param>
|
||||
/// <param name="hoveredColor">The color of the button when hovered.</param>
|
||||
/// <param name="alphaMult">A multiplier for the current alpha levels.</param>
|
||||
/// <returns>Indicator if button is clicked.</returns>
|
||||
public static bool DisabledButton(FontAwesomeIcon icon, int? id = null, Vector4? defaultColor = null, Vector4? activeColor = null, Vector4? hoveredColor = null, float alphaMult = .5f)
|
||||
{
|
||||
ImGui.PushFont(UiBuilder.IconFont);
|
||||
|
||||
var text = icon.ToIconString();
|
||||
if (id.HasValue)
|
||||
text = $"{text}{id}";
|
||||
|
||||
var button = DisabledButton(text, defaultColor, activeColor, hoveredColor, alphaMult);
|
||||
|
||||
ImGui.PopFont();
|
||||
|
||||
return button;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Alpha modified Button component to use as a disabled button with alpha and color options.
|
||||
/// </summary>
|
||||
/// <param name="labelWithId">The button label with ID.</param>
|
||||
/// <param name="defaultColor">The default color of the button.</param>
|
||||
/// <param name="activeColor">The color of the button when active.</param>
|
||||
/// <param name="hoveredColor">The color of the button when hovered.</param>
|
||||
/// <param name="alphaMult">A multiplier for the current alpha levels.</param>
|
||||
/// <returns>Indicator if button is clicked.</returns>
|
||||
public static bool DisabledButton(string labelWithId, Vector4? defaultColor = null, Vector4? activeColor = null, Vector4? hoveredColor = null, float alphaMult = .5f)
|
||||
{
|
||||
if (defaultColor.HasValue)
|
||||
ImGui.PushStyleColor(ImGuiCol.Button, defaultColor.Value);
|
||||
|
||||
if (activeColor.HasValue)
|
||||
ImGui.PushStyleColor(ImGuiCol.ButtonActive, activeColor.Value);
|
||||
|
||||
if (hoveredColor.HasValue)
|
||||
ImGui.PushStyleColor(ImGuiCol.ButtonHovered, hoveredColor.Value);
|
||||
|
||||
var style = ImGui.GetStyle();
|
||||
ImGui.PushStyleVar(ImGuiStyleVar.Alpha, style.Alpha * alphaMult);
|
||||
|
||||
var button = ImGui.Button(labelWithId);
|
||||
|
||||
ImGui.PopStyleVar();
|
||||
|
||||
if (defaultColor.HasValue)
|
||||
ImGui.PopStyleColor();
|
||||
|
||||
if (activeColor.HasValue)
|
||||
ImGui.PopStyleColor();
|
||||
|
||||
if (hoveredColor.HasValue)
|
||||
ImGui.PopStyleColor();
|
||||
|
||||
return button;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -9,6 +9,14 @@ namespace Dalamud.Interface.Components
|
|||
/// </summary>
|
||||
public static partial class ImGuiComponents
|
||||
{
|
||||
/// <summary>
|
||||
/// IconButton component to use an icon as a button.
|
||||
/// </summary>
|
||||
/// <param name="icon">The icon for the button.</param>
|
||||
/// <returns>Indicator if button is clicked.</returns>
|
||||
public static bool IconButton(FontAwesomeIcon icon)
|
||||
=> IconButton(icon, null, null, null);
|
||||
|
||||
/// <summary>
|
||||
/// IconButton component to use an icon as a button.
|
||||
/// </summary>
|
||||
|
|
@ -16,16 +24,26 @@ namespace Dalamud.Interface.Components
|
|||
/// <param name="icon">The icon for the button.</param>
|
||||
/// <returns>Indicator if button is clicked.</returns>
|
||||
public static bool IconButton(int id, FontAwesomeIcon icon)
|
||||
{
|
||||
ImGui.PushStyleColor(ImGuiCol.Button, Vector4.Zero);
|
||||
ImGui.PushStyleColor(ImGuiCol.ButtonActive, Vector4.Zero);
|
||||
ImGui.PushStyleColor(ImGuiCol.ButtonHovered, Vector4.Zero);
|
||||
ImGui.PushFont(UiBuilder.IconFont);
|
||||
var button = ImGui.Button($"{icon.ToIconString()}{id}");
|
||||
ImGui.PopFont();
|
||||
ImGui.PopStyleColor(3);
|
||||
return button;
|
||||
}
|
||||
=> IconButton(id, icon, null, null, null);
|
||||
|
||||
/// <summary>
|
||||
/// IconButton component to use an icon as a button.
|
||||
/// </summary>
|
||||
/// <param name="iconText">Text already containing the icon string.</param>
|
||||
/// <returns>Indicator if button is clicked.</returns>
|
||||
public static bool IconButton(string iconText)
|
||||
=> IconButton(iconText, null, null, null);
|
||||
|
||||
/// <summary>
|
||||
/// IconButton component to use an icon as a button.
|
||||
/// </summary>
|
||||
/// <param name="icon">The icon for the button.</param>
|
||||
/// <param name="defaultColor">The default color of the button.</param>
|
||||
/// <param name="activeColor">The color of the button when active.</param>
|
||||
/// <param name="hoveredColor">The color of the button when hovered.</param>
|
||||
/// <returns>Indicator if button is clicked.</returns>
|
||||
public static bool IconButton(FontAwesomeIcon icon, Vector4? defaultColor = null, Vector4? activeColor = null, Vector4? hoveredColor = null)
|
||||
=> IconButton($"{icon.ToIconString()}", defaultColor, activeColor, hoveredColor);
|
||||
|
||||
/// <summary>
|
||||
/// IconButton component to use an icon as a button with color options.
|
||||
|
|
@ -36,15 +54,48 @@ namespace Dalamud.Interface.Components
|
|||
/// <param name="activeColor">The color of the button when active.</param>
|
||||
/// <param name="hoveredColor">The color of the button when hovered.</param>
|
||||
/// <returns>Indicator if button is clicked.</returns>
|
||||
public static bool IconButton(int id, FontAwesomeIcon icon, Vector4 defaultColor, Vector4 activeColor, Vector4 hoveredColor)
|
||||
public static bool IconButton(int id, FontAwesomeIcon icon, Vector4? defaultColor = null, Vector4? activeColor = null, Vector4? hoveredColor = null)
|
||||
=> IconButton($"{icon.ToIconString()}{id}", defaultColor, activeColor, hoveredColor);
|
||||
|
||||
/// <summary>
|
||||
/// IconButton component to use an icon as a button with color options.
|
||||
/// </summary>
|
||||
/// <param name="iconText">Text already containing the icon string.</param>
|
||||
/// <param name="defaultColor">The default color of the button.</param>
|
||||
/// <param name="activeColor">The color of the button when active.</param>
|
||||
/// <param name="hoveredColor">The color of the button when hovered.</param>
|
||||
/// <returns>Indicator if button is clicked.</returns>
|
||||
public static bool IconButton(string iconText, Vector4? defaultColor = null, Vector4? activeColor = null, Vector4? hoveredColor = null)
|
||||
{
|
||||
ImGui.PushStyleColor(ImGuiCol.Button, defaultColor);
|
||||
ImGui.PushStyleColor(ImGuiCol.ButtonActive, activeColor);
|
||||
ImGui.PushStyleColor(ImGuiCol.ButtonHovered, hoveredColor);
|
||||
var numColors = 0;
|
||||
|
||||
if (defaultColor.HasValue)
|
||||
{
|
||||
ImGui.PushStyleColor(ImGuiCol.Button, defaultColor.Value);
|
||||
numColors++;
|
||||
}
|
||||
|
||||
if (activeColor.HasValue)
|
||||
{
|
||||
ImGui.PushStyleColor(ImGuiCol.ButtonActive, activeColor.Value);
|
||||
numColors++;
|
||||
}
|
||||
|
||||
if (hoveredColor.HasValue)
|
||||
{
|
||||
ImGui.PushStyleColor(ImGuiCol.ButtonHovered, hoveredColor.Value);
|
||||
numColors++;
|
||||
}
|
||||
|
||||
ImGui.PushFont(UiBuilder.IconFont);
|
||||
var button = ImGui.Button($"{icon.ToIconString()}{id}");
|
||||
|
||||
var button = ImGui.Button(iconText);
|
||||
|
||||
ImGui.PopFont();
|
||||
ImGui.PopStyleColor(3);
|
||||
|
||||
if (numColors > 0)
|
||||
ImGui.PopStyleColor(numColors);
|
||||
|
||||
return button;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,8 +13,7 @@ namespace Dalamud.Interface.Components
|
|||
/// <param name="label">The label for text.</param>
|
||||
/// <param name="value">The text value.</param>
|
||||
/// <param name="hint">The hint to show on hover.</param>
|
||||
public static void TextWithLabel(
|
||||
string label, string value, string hint = "")
|
||||
public static void TextWithLabel(string label, string value, string hint = "")
|
||||
{
|
||||
ImGui.Text(label + ": ");
|
||||
ImGui.SameLine();
|
||||
|
|
|
|||
|
|
@ -20,6 +20,24 @@ namespace Dalamud.Interface
|
|||
/// </summary>
|
||||
public static float GlobalScale { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a <see cref="Vector2"/> that is pre-scaled with the <see cref="GlobalScale"/> multiplier.
|
||||
/// </summary>
|
||||
/// <param name="x">Vector2 X parameter.</param>
|
||||
/// <param name="y">Vector2 Y parameter.</param>
|
||||
/// <returns>A scaled Vector2.</returns>
|
||||
public static Vector2 ScaledVector2(float x, float y) => new Vector2(x, y) * GlobalScale;
|
||||
|
||||
/// <summary>
|
||||
/// Gets a <see cref="Vector4"/> that is pre-scaled with the <see cref="GlobalScale"/> multiplier.
|
||||
/// </summary>
|
||||
/// <param name="x">Vector4 X parameter.</param>
|
||||
/// <param name="y">Vector4 Y parameter.</param>
|
||||
/// <param name="z">Vector4 Z parameter.</param>
|
||||
/// <param name="w">Vector4 W parameter.</param>
|
||||
/// <returns>A scaled Vector2.</returns>
|
||||
public static Vector4 ScaledVector4(float x, float y, float z, float w) => new Vector4(x, y, z, w) * GlobalScale;
|
||||
|
||||
/// <summary>
|
||||
/// Force the next ImGui window to stay inside the main game window.
|
||||
/// </summary>
|
||||
|
|
@ -29,7 +47,14 @@ namespace Dalamud.Interface
|
|||
/// Create a dummy scaled by the global Dalamud scale.
|
||||
/// </summary>
|
||||
/// <param name="size">The size of the dummy.</param>
|
||||
public static void ScaledDummy(float size) => ImGui.Dummy(new Vector2(size * GlobalScale, size * GlobalScale));
|
||||
public static void ScaledDummy(float size) => ScaledDummy(size, size);
|
||||
|
||||
/// <summary>
|
||||
/// Create a dummy scaled by the global Dalamud scale.
|
||||
/// </summary>
|
||||
/// <param name="x">Vector2 X parameter.</param>
|
||||
/// <param name="y">Vector2 Y parameter.</param>
|
||||
public static void ScaledDummy(float x, float y) => ScaledDummy(new Vector2(x, y));
|
||||
|
||||
/// <summary>
|
||||
/// Create a dummy scaled by the global Dalamud scale.
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ using CheapLoc;
|
|||
using Dalamud.Game.Command;
|
||||
using Serilog;
|
||||
|
||||
namespace Dalamud
|
||||
namespace Dalamud.Interface.Internal
|
||||
{
|
||||
/// <summary>
|
||||
/// Class handling Dalamud core commands.
|
||||
|
|
@ -149,7 +149,7 @@ namespace Dalamud
|
|||
|
||||
try
|
||||
{
|
||||
this.dalamud.PluginManager.ReloadPlugins();
|
||||
this.dalamud.PluginManager.ReloadAllPlugins();
|
||||
|
||||
this.dalamud.Framework.Gui.Chat.Print("OK");
|
||||
}
|
||||
|
|
@ -226,20 +226,20 @@ namespace Dalamud
|
|||
|
||||
private void OnDebugDrawDevMenu(string command, string arguments)
|
||||
{
|
||||
this.dalamud.DalamudUi.IsDevMenu = !this.dalamud.DalamudUi.IsDevMenu;
|
||||
this.dalamud.DalamudUi.ToggleDevMenu();
|
||||
}
|
||||
|
||||
private void OnDebugDrawDataMenu(string command, string arguments)
|
||||
{
|
||||
if (string.IsNullOrEmpty(arguments))
|
||||
this.dalamud.DalamudUi.ToggleData();
|
||||
this.dalamud.DalamudUi.ToggleDataWindow();
|
||||
else
|
||||
this.dalamud.DalamudUi.ToggleData(arguments);
|
||||
this.dalamud.DalamudUi.ToggleDataWindow(arguments);
|
||||
}
|
||||
|
||||
private void OnOpenLog(string command, string arguments)
|
||||
{
|
||||
this.dalamud.DalamudUi.ToggleLog();
|
||||
this.dalamud.DalamudUi.ToggleLogWindow();
|
||||
}
|
||||
|
||||
private void OnDebugImInfoCommand(string command, string arguments)
|
||||
|
|
@ -267,12 +267,12 @@ namespace Dalamud
|
|||
|
||||
private void OnOpenInstallerCommand(string command, string arguments)
|
||||
{
|
||||
this.dalamud.DalamudUi.TogglePluginInstaller();
|
||||
this.dalamud.DalamudUi.TogglePluginInstallerWindow();
|
||||
}
|
||||
|
||||
private void OnOpenCreditsCommand(string command, string arguments)
|
||||
{
|
||||
this.dalamud.DalamudUi.ToggleCredits();
|
||||
this.dalamud.DalamudUi.ToggleCreditsWindow();
|
||||
}
|
||||
|
||||
private void OnSetLanguageCommand(string command, string arguments)
|
||||
|
|
@ -299,7 +299,7 @@ namespace Dalamud
|
|||
|
||||
private void OnOpenSettingsCommand(string command, string arguments)
|
||||
{
|
||||
this.dalamud.DalamudUi.ToggleSettings();
|
||||
this.dalamud.DalamudUi.ToggleSettingsWindow();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,152 +1,288 @@
|
|||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
using CheapLoc;
|
||||
using Dalamud.Interface.Colors;
|
||||
using Dalamud.Interface.Components;
|
||||
using Dalamud.Interface.Scratchpad;
|
||||
using Dalamud.Interface.Internal.Windows;
|
||||
using Dalamud.Interface.Windowing;
|
||||
using Dalamud.Plugin;
|
||||
using Dalamud.Plugin.Internal;
|
||||
using ImGuiNET;
|
||||
using Serilog;
|
||||
using Serilog.Events;
|
||||
|
||||
namespace Dalamud.Interface
|
||||
namespace Dalamud.Interface.Internal
|
||||
{
|
||||
/// <summary>
|
||||
/// Class handling Dalamud core interface.
|
||||
/// This plugin implements all of the Dalamud interface separately, to allow for reloading of the interface and rapid prototyping.
|
||||
/// </summary>
|
||||
internal class DalamudInterface : IDisposable
|
||||
{
|
||||
private static readonly ModuleLog Log = new("DUI");
|
||||
|
||||
private readonly Dalamud dalamud;
|
||||
private readonly WindowSystem windowSystem;
|
||||
|
||||
private readonly DalamudLogWindow logWindow;
|
||||
private readonly DalamudDataWindow dataWindow;
|
||||
private readonly DalamudCreditsWindow creditsWindow;
|
||||
private readonly DalamudSettingsWindow settingsWindow;
|
||||
private readonly PluginInstallerWindow pluginWindow;
|
||||
private readonly DalamudPluginStatWindow pluginStatWindow;
|
||||
private readonly DalamudChangelogWindow changelogWindow;
|
||||
private readonly ComponentDemoWindow componentDemoWindow;
|
||||
private readonly ChangelogWindow changelogWindow;
|
||||
private readonly ColorDemoWindow colorDemoWindow;
|
||||
private readonly ScratchpadWindow scratchpadWindow;
|
||||
private readonly ComponentDemoWindow componentDemoWindow;
|
||||
private readonly CreditsWindow creditsWindow;
|
||||
private readonly DataWindow dataWindow;
|
||||
private readonly GamepadModeNotifierWindow gamepadModeNotifierWindow;
|
||||
|
||||
private readonly WindowSystem windowSystem = new("DalamudCore");
|
||||
private readonly LogWindow logWindow;
|
||||
private readonly PluginStatWindow pluginStatWindow;
|
||||
private readonly PluginInstallerWindow pluginWindow;
|
||||
private readonly ScratchpadWindow scratchpadWindow;
|
||||
private readonly SettingsWindow settingsWindow;
|
||||
|
||||
private ulong frameCount = 0;
|
||||
|
||||
private bool isImguiDrawDemoWindow = false;
|
||||
|
||||
#if DEBUG
|
||||
private bool isImguiDrawDevMenu = true;
|
||||
private bool isImGuiDrawDevMenu = true;
|
||||
#else
|
||||
private bool isImguiDrawDevMenu = false;
|
||||
private bool isImGuiDrawDevMenu = false;
|
||||
#endif
|
||||
|
||||
private bool isImGuiDrawDemoWindow = false;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="DalamudInterface"/> class.
|
||||
/// </summary>
|
||||
/// <param name="dalamud">The Dalamud instance to register to.</param>
|
||||
/// <param name="dalamud">The Dalamud instance.</param>
|
||||
public DalamudInterface(Dalamud dalamud)
|
||||
{
|
||||
this.dalamud = dalamud;
|
||||
this.windowSystem = new WindowSystem("DalamudCore");
|
||||
|
||||
this.logWindow = new DalamudLogWindow(this.dalamud.CommandManager, this.dalamud.Configuration)
|
||||
{
|
||||
IsOpen = false,
|
||||
};
|
||||
this.windowSystem.AddWindow(this.logWindow);
|
||||
this.changelogWindow = new ChangelogWindow(dalamud) { IsOpen = false };
|
||||
this.colorDemoWindow = new ColorDemoWindow() { IsOpen = false };
|
||||
this.componentDemoWindow = new ComponentDemoWindow() { IsOpen = false };
|
||||
this.creditsWindow = new CreditsWindow(dalamud) { IsOpen = false };
|
||||
this.dataWindow = new DataWindow(dalamud) { IsOpen = false };
|
||||
this.gamepadModeNotifierWindow = new GamepadModeNotifierWindow();
|
||||
this.logWindow = new LogWindow(dalamud) { IsOpen = this.dalamud.Configuration.LogOpenAtStartup };
|
||||
this.pluginStatWindow = new PluginStatWindow(dalamud) { IsOpen = false };
|
||||
this.pluginWindow = new PluginInstallerWindow(dalamud) { IsOpen = false };
|
||||
this.scratchpadWindow = new ScratchpadWindow(dalamud) { IsOpen = false };
|
||||
this.settingsWindow = new SettingsWindow(dalamud) { IsOpen = false };
|
||||
|
||||
this.dataWindow = new DalamudDataWindow(this.dalamud)
|
||||
{
|
||||
IsOpen = false,
|
||||
};
|
||||
this.windowSystem.AddWindow(this.dataWindow);
|
||||
|
||||
this.creditsWindow = new DalamudCreditsWindow(this.dalamud)
|
||||
{
|
||||
IsOpen = false,
|
||||
};
|
||||
this.windowSystem.AddWindow(this.changelogWindow);
|
||||
this.windowSystem.AddWindow(this.colorDemoWindow);
|
||||
this.windowSystem.AddWindow(this.componentDemoWindow);
|
||||
this.windowSystem.AddWindow(this.creditsWindow);
|
||||
|
||||
this.settingsWindow = new DalamudSettingsWindow(this.dalamud)
|
||||
{
|
||||
IsOpen = false,
|
||||
};
|
||||
this.windowSystem.AddWindow(this.dataWindow);
|
||||
this.windowSystem.AddWindow(this.gamepadModeNotifierWindow);
|
||||
this.windowSystem.AddWindow(this.logWindow);
|
||||
this.windowSystem.AddWindow(this.pluginStatWindow);
|
||||
this.windowSystem.AddWindow(this.pluginWindow);
|
||||
this.windowSystem.AddWindow(this.scratchpadWindow);
|
||||
this.windowSystem.AddWindow(this.settingsWindow);
|
||||
|
||||
this.pluginWindow = new PluginInstallerWindow(this.dalamud, this.dalamud.StartInfo.GameVersion)
|
||||
{
|
||||
IsOpen = false,
|
||||
};
|
||||
this.windowSystem.AddWindow(this.pluginWindow);
|
||||
this.dalamud.InterfaceManager.OnDraw += this.OnDraw;
|
||||
|
||||
this.pluginStatWindow = new DalamudPluginStatWindow(this.dalamud.PluginManager)
|
||||
{
|
||||
IsOpen = false,
|
||||
};
|
||||
this.windowSystem.AddWindow(this.pluginStatWindow);
|
||||
|
||||
this.changelogWindow = new DalamudChangelogWindow(this.dalamud)
|
||||
{
|
||||
IsOpen = false,
|
||||
};
|
||||
this.windowSystem.AddWindow(this.changelogWindow);
|
||||
|
||||
this.componentDemoWindow = new ComponentDemoWindow()
|
||||
{
|
||||
IsOpen = false,
|
||||
};
|
||||
this.windowSystem.AddWindow(this.componentDemoWindow);
|
||||
|
||||
this.colorDemoWindow = new ColorDemoWindow()
|
||||
{
|
||||
IsOpen = false,
|
||||
};
|
||||
this.windowSystem.AddWindow(this.colorDemoWindow);
|
||||
|
||||
this.scratchpadWindow = new ScratchpadWindow(this.dalamud)
|
||||
{
|
||||
IsOpen = false,
|
||||
};
|
||||
this.windowSystem.AddWindow(this.scratchpadWindow);
|
||||
|
||||
this.gamepadModeNotifierWindow = new GamepadModeNotifierWindow();
|
||||
this.windowSystem.AddWindow(this.gamepadModeNotifierWindow);
|
||||
|
||||
Log.Information("[DUI] Windows added");
|
||||
|
||||
if (dalamud.Configuration.LogOpenAtStartup)
|
||||
this.OpenLog();
|
||||
Log.Information("Windows added");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether the Dalamud dev menu is drawing.
|
||||
/// Gets or sets a value indicating whether the /xldev menu is open.
|
||||
/// </summary>
|
||||
public bool IsDevMenu
|
||||
public bool IsDevMenuOpen
|
||||
{
|
||||
get => this.isImguiDrawDevMenu;
|
||||
set => this.isImguiDrawDevMenu = value;
|
||||
get => this.isImGuiDrawDevMenu;
|
||||
set => this.isImGuiDrawDevMenu = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Draw the Dalamud core interface via ImGui.
|
||||
/// Gets a value indicating whether the current Dalamud version warrants displaying the changelog.
|
||||
/// </summary>
|
||||
public void Draw()
|
||||
public bool WarrantsChangelog => ChangelogWindow.WarrantsChangelog;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Dispose()
|
||||
{
|
||||
this.dalamud.InterfaceManager.OnDraw -= this.OnDraw;
|
||||
|
||||
this.windowSystem.RemoveAllWindows();
|
||||
|
||||
this.creditsWindow.Dispose();
|
||||
this.logWindow.Dispose();
|
||||
this.scratchpadWindow.Dispose();
|
||||
}
|
||||
|
||||
#region Open
|
||||
|
||||
/// <summary>
|
||||
/// Opens the <see cref="ChangelogWindow"/>.
|
||||
/// </summary>
|
||||
public void OpenChangelogWindow() => this.changelogWindow.IsOpen = true;
|
||||
|
||||
/// <summary>
|
||||
/// Opens the <see cref="ColorDemoWindow"/>.
|
||||
/// </summary>
|
||||
public void OpenColorsDemoWindow() => this.colorDemoWindow.IsOpen = true;
|
||||
|
||||
/// <summary>
|
||||
/// Opens the <see cref="ComponentDemoWindow"/>.
|
||||
/// </summary>
|
||||
public void OpenComponentDemoWindow() => this.componentDemoWindow.IsOpen = true;
|
||||
|
||||
/// <summary>
|
||||
/// Opens the <see cref="CreditsWindow"/>.
|
||||
/// </summary>
|
||||
public void OpenCreditsWindow() => this.creditsWindow.IsOpen = true;
|
||||
|
||||
/// <summary>
|
||||
/// Opens the <see cref="DataWindow"/>.
|
||||
/// </summary>
|
||||
/// <param name="dataKind">The data kind to switch to after opening.</param>
|
||||
public void OpenDataWindow(string dataKind = null)
|
||||
{
|
||||
this.dataWindow.IsOpen = true;
|
||||
if (dataKind != null && this.dataWindow.IsOpen)
|
||||
{
|
||||
this.dataWindow.SetDataKind(dataKind);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Opens the dev menu bar.
|
||||
/// </summary>
|
||||
public void OpenDevMenu() => this.isImGuiDrawDevMenu = true;
|
||||
|
||||
/// <summary>
|
||||
/// Opens the <see cref="GamepadModeNotifierWindow"/>.
|
||||
/// </summary>
|
||||
public void OpenGamepadModeNotifierWindow() => this.gamepadModeNotifierWindow.IsOpen = true;
|
||||
|
||||
/// <summary>
|
||||
/// Opens the <see cref="LogWindow"/>.
|
||||
/// </summary>
|
||||
public void OpenLogWindow() => this.logWindow.IsOpen = true;
|
||||
|
||||
/// <summary>
|
||||
/// Opens the <see cref="PluginStatWindow"/>.
|
||||
/// </summary>
|
||||
public void OpenPluginStats() => this.pluginStatWindow.IsOpen = true;
|
||||
|
||||
/// <summary>
|
||||
/// Opens the <see cref="PluginInstallerWindow"/>.
|
||||
/// </summary>
|
||||
public void OpenPluginInstaller() => this.pluginWindow.IsOpen = true;
|
||||
|
||||
/// <summary>
|
||||
/// Opens the <see cref="ScratchpadWindow"/>.
|
||||
/// </summary>
|
||||
public void OpenScratchpadWindow() => this.scratchpadWindow.IsOpen = true;
|
||||
|
||||
/// <summary>
|
||||
/// Opens the <see cref="SettingsWindow"/>.
|
||||
/// </summary>
|
||||
public void OpenSettings() => this.settingsWindow.IsOpen = true;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Toggle
|
||||
|
||||
/// <summary>
|
||||
/// Toggles the <see cref="ChangelogWindow"/>.
|
||||
/// </summary>
|
||||
public void ToggleChangelogWindow() => this.changelogWindow.Toggle();
|
||||
|
||||
/// <summary>
|
||||
/// Toggles the <see cref="ColorDemoWindow"/>.
|
||||
/// </summary>
|
||||
public void ToggleColorsDemoWindow() => this.colorDemoWindow.Toggle();
|
||||
|
||||
/// <summary>
|
||||
/// Toggles the <see cref="ComponentDemoWindow"/>.
|
||||
/// </summary>
|
||||
public void ToggleComponentDemoWindow() => this.componentDemoWindow.Toggle();
|
||||
|
||||
/// <summary>
|
||||
/// Toggles the <see cref="CreditsWindow"/>.
|
||||
/// </summary>
|
||||
public void ToggleCreditsWindow() => this.creditsWindow.Toggle();
|
||||
|
||||
/// <summary>
|
||||
/// Toggles the <see cref="DataWindow"/>.
|
||||
/// </summary>
|
||||
/// <param name="dataKind">The data kind to switch to after opening.</param>
|
||||
public void ToggleDataWindow(string dataKind = null)
|
||||
{
|
||||
this.dataWindow.Toggle();
|
||||
if (dataKind != null && this.dataWindow.IsOpen)
|
||||
{
|
||||
this.dataWindow.SetDataKind(dataKind);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Toggles the dev menu bar.
|
||||
/// </summary>
|
||||
public void ToggleDevMenu() => this.isImGuiDrawDevMenu ^= true;
|
||||
|
||||
/// <summary>
|
||||
/// Toggles the <see cref="GamepadModeNotifierWindow"/>.
|
||||
/// </summary>
|
||||
public void ToggleGamepadModeNotifierWindow() => this.gamepadModeNotifierWindow.Toggle();
|
||||
|
||||
/// <summary>
|
||||
/// Toggles the <see cref="LogWindow"/>.
|
||||
/// </summary>
|
||||
public void ToggleLogWindow() => this.logWindow.Toggle();
|
||||
|
||||
/// <summary>
|
||||
/// Toggles the <see cref="PluginStatWindow"/>.
|
||||
/// </summary>
|
||||
public void TogglePluginStatsWindow() => this.pluginStatWindow.Toggle();
|
||||
|
||||
/// <summary>
|
||||
/// Toggles the <see cref="PluginInstallerWindow"/>.
|
||||
/// </summary>
|
||||
public void TogglePluginInstallerWindow() => this.pluginWindow.Toggle();
|
||||
|
||||
/// <summary>
|
||||
/// Toggles the <see cref="ScratchpadWindow"/>.
|
||||
/// </summary>
|
||||
public void ToggleScratchpadWindow() => this.scratchpadWindow.Toggle();
|
||||
|
||||
/// <summary>
|
||||
/// Toggles the <see cref="SettingsWindow"/>.
|
||||
/// </summary>
|
||||
public void ToggleSettingsWindow() => this.settingsWindow.Toggle();
|
||||
|
||||
#endregion
|
||||
|
||||
private void OnDraw()
|
||||
{
|
||||
this.frameCount++;
|
||||
|
||||
if (!this.IsDevMenu && !this.dalamud.ClientState.Condition.Any())
|
||||
try
|
||||
{
|
||||
ImGui.PushStyleColor(ImGuiCol.Button, new Vector4(0, 0, 0, 0));
|
||||
ImGui.PushStyleColor(ImGuiCol.ButtonActive, new Vector4(0, 0, 0, 0));
|
||||
ImGui.PushStyleColor(ImGuiCol.ButtonHovered, new Vector4(0, 0, 0, 0));
|
||||
this.DrawHiddenDevMenuOpener();
|
||||
this.DrawDevMenu();
|
||||
|
||||
if (this.dalamud.Framework.Gui.GameUiHidden)
|
||||
return;
|
||||
|
||||
this.windowSystem.Draw();
|
||||
|
||||
if (this.isImGuiDrawDemoWindow)
|
||||
ImGui.ShowDemoWindow();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
PluginLog.Error(ex, "Error during OnDraw");
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawHiddenDevMenuOpener()
|
||||
{
|
||||
if (!this.isImGuiDrawDevMenu && !this.dalamud.ClientState.Condition.Any())
|
||||
{
|
||||
ImGui.PushStyleColor(ImGuiCol.Button, Vector4.Zero);
|
||||
ImGui.PushStyleColor(ImGuiCol.ButtonActive, Vector4.Zero);
|
||||
ImGui.PushStyleColor(ImGuiCol.ButtonHovered, Vector4.Zero);
|
||||
ImGui.PushStyleColor(ImGuiCol.Text, new Vector4(0, 0, 0, 1));
|
||||
ImGui.PushStyleColor(ImGuiCol.TextSelectedBg, new Vector4(0, 0, 0, 1));
|
||||
ImGui.PushStyleColor(ImGuiCol.Border, new Vector4(0, 0, 0, 1));
|
||||
|
|
@ -160,27 +296,30 @@ namespace Dalamud.Interface
|
|||
if (ImGui.Begin("DevMenu Opener", ImGuiWindowFlags.AlwaysAutoResize | ImGuiWindowFlags.NoBackground | ImGuiWindowFlags.NoDecoration | ImGuiWindowFlags.NoMove | ImGuiWindowFlags.NoScrollbar | ImGuiWindowFlags.NoResize | ImGuiWindowFlags.NoSavedSettings))
|
||||
{
|
||||
if (ImGui.Button("###devMenuOpener", new Vector2(40, 25)))
|
||||
this.IsDevMenu = true;
|
||||
this.isImGuiDrawDevMenu = true;
|
||||
|
||||
ImGui.End();
|
||||
}
|
||||
|
||||
ImGui.PopStyleColor(8);
|
||||
}
|
||||
}
|
||||
|
||||
if (this.IsDevMenu)
|
||||
private void DrawDevMenu()
|
||||
{
|
||||
if (this.isImGuiDrawDevMenu)
|
||||
{
|
||||
if (ImGui.BeginMainMenuBar())
|
||||
{
|
||||
if (ImGui.BeginMenu("Dalamud"))
|
||||
{
|
||||
ImGui.MenuItem("Draw Dalamud dev menu", string.Empty, ref this.isImguiDrawDevMenu);
|
||||
ImGui.MenuItem("Draw Dalamud dev menu", string.Empty, ref this.isImGuiDrawDevMenu);
|
||||
|
||||
ImGui.Separator();
|
||||
|
||||
if (ImGui.MenuItem("Open Log window"))
|
||||
{
|
||||
this.OpenLog();
|
||||
this.OpenLogWindow();
|
||||
}
|
||||
|
||||
if (ImGui.BeginMenu("Set log level..."))
|
||||
|
|
@ -214,12 +353,12 @@ namespace Dalamud.Interface
|
|||
|
||||
if (ImGui.MenuItem("Open Data window"))
|
||||
{
|
||||
this.OpenData();
|
||||
this.OpenDataWindow();
|
||||
}
|
||||
|
||||
if (ImGui.MenuItem("Open Credits window"))
|
||||
{
|
||||
this.OpenCredits();
|
||||
this.OpenCreditsWindow();
|
||||
}
|
||||
|
||||
if (ImGui.MenuItem("Open Settings window"))
|
||||
|
|
@ -229,20 +368,20 @@ namespace Dalamud.Interface
|
|||
|
||||
if (ImGui.MenuItem("Open Changelog window"))
|
||||
{
|
||||
this.OpenChangelog();
|
||||
this.OpenChangelogWindow();
|
||||
}
|
||||
|
||||
if (ImGui.MenuItem("Open Components Demo"))
|
||||
{
|
||||
this.OpenComponentDemo();
|
||||
this.OpenComponentDemoWindow();
|
||||
}
|
||||
|
||||
if (ImGui.MenuItem("Open Colors Demo"))
|
||||
{
|
||||
this.OpenColorsDemo();
|
||||
this.OpenColorsDemoWindow();
|
||||
}
|
||||
|
||||
ImGui.MenuItem("Draw ImGui demo", string.Empty, ref this.isImguiDrawDemoWindow);
|
||||
ImGui.MenuItem("Draw ImGui demo", string.Empty, ref this.isImGuiDrawDemoWindow);
|
||||
|
||||
ImGui.Separator();
|
||||
|
||||
|
|
@ -264,12 +403,12 @@ namespace Dalamud.Interface
|
|||
ImGui.Separator();
|
||||
if (ImGui.MenuItem("Enable Dalamud testing", string.Empty, this.dalamud.Configuration.DoDalamudTest))
|
||||
{
|
||||
this.dalamud.Configuration.DoDalamudTest = !this.dalamud.Configuration.DoDalamudTest;
|
||||
this.dalamud.Configuration.DoDalamudTest ^= true;
|
||||
this.dalamud.Configuration.Save();
|
||||
}
|
||||
|
||||
ImGui.MenuItem(Util.AssemblyVersion, false);
|
||||
ImGui.MenuItem(this.dalamud.StartInfo.GameVersion, false);
|
||||
ImGui.MenuItem(this.dalamud.StartInfo.GameVersion.ToString(), false);
|
||||
|
||||
ImGui.EndMenu();
|
||||
}
|
||||
|
|
@ -300,10 +439,10 @@ namespace Dalamud.Interface
|
|||
|
||||
if (ImGui.MenuItem("Print plugin info"))
|
||||
{
|
||||
foreach (var plugin in this.dalamud.PluginManager.Plugins)
|
||||
foreach (var plugin in this.dalamud.PluginManager.InstalledPlugins)
|
||||
{
|
||||
// TODO: some more here, state maybe?
|
||||
Log.Information($"{plugin.Plugin.Name}");
|
||||
PluginLog.Information($"{plugin.Name}");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -311,18 +450,23 @@ namespace Dalamud.Interface
|
|||
{
|
||||
try
|
||||
{
|
||||
this.dalamud.PluginManager.ReloadPlugins();
|
||||
this.dalamud.PluginManager.ReloadAllPlugins();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
this.dalamud.Framework.Gui.Chat.PrintError("Reload failed.");
|
||||
Log.Error(ex, "Plugin reload failed.");
|
||||
PluginLog.Error(ex, "Plugin reload failed.");
|
||||
}
|
||||
}
|
||||
|
||||
if (ImGui.MenuItem("Scan dev plugins"))
|
||||
{
|
||||
this.dalamud.PluginManager.ScanDevPlugins();
|
||||
}
|
||||
|
||||
ImGui.Separator();
|
||||
ImGui.MenuItem("API Level:" + PluginManager.DalamudApiLevel, false);
|
||||
ImGui.MenuItem("Loaded plugins:" + this.dalamud.PluginManager?.Plugins.Count, false);
|
||||
ImGui.MenuItem("Loaded plugins:" + this.dalamud.PluginManager?.InstalledPlugins.Count, false);
|
||||
ImGui.EndMenu();
|
||||
}
|
||||
|
||||
|
|
@ -384,197 +528,6 @@ namespace Dalamud.Interface
|
|||
ImGui.EndMainMenuBar();
|
||||
}
|
||||
}
|
||||
|
||||
if (this.dalamud.Framework.Gui.GameUiHidden)
|
||||
return;
|
||||
|
||||
this.windowSystem.Draw();
|
||||
|
||||
if (this.isImguiDrawDemoWindow)
|
||||
ImGui.ShowDemoWindow();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Dispose the window system and all windows that require it.
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
this.scratchpadWindow.Dispose();
|
||||
this.windowSystem.RemoveAllWindows();
|
||||
|
||||
this.logWindow?.Dispose();
|
||||
this.creditsWindow?.Dispose();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Open the Plugin Installer window.
|
||||
/// </summary>
|
||||
internal void OpenPluginInstaller()
|
||||
{
|
||||
this.pluginWindow.IsOpen = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Open the changelog window.
|
||||
/// </summary>
|
||||
internal void OpenChangelog()
|
||||
{
|
||||
this.changelogWindow.IsOpen = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Open the settings window.
|
||||
/// </summary>
|
||||
internal void OpenSettings()
|
||||
{
|
||||
this.settingsWindow.IsOpen = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Open the log window.
|
||||
/// </summary>
|
||||
internal void OpenLog()
|
||||
{
|
||||
this.logWindow.IsOpen = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Open the data window.
|
||||
/// </summary>
|
||||
internal void OpenData()
|
||||
{
|
||||
this.dataWindow.IsOpen = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Open the credits window.
|
||||
/// </summary>
|
||||
internal void OpenCredits()
|
||||
{
|
||||
this.creditsWindow.IsOpen = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Open the stats window.
|
||||
/// </summary>
|
||||
internal void OpenPluginStats()
|
||||
{
|
||||
this.pluginStatWindow.IsOpen = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Open the component test window.
|
||||
/// </summary>
|
||||
internal void OpenComponentDemo()
|
||||
{
|
||||
this.componentDemoWindow.IsOpen = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Open the colors test window.
|
||||
/// </summary>
|
||||
internal void OpenColorsDemo()
|
||||
{
|
||||
this.colorDemoWindow.IsOpen = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Open the colors test window.
|
||||
/// </summary>
|
||||
internal void OpenScratchpadWindow()
|
||||
{
|
||||
this.scratchpadWindow.IsOpen = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Toggle the Plugin Installer window.
|
||||
/// </summary>
|
||||
internal void TogglePluginInstaller()
|
||||
{
|
||||
this.pluginWindow.IsOpen ^= true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Toggle the changelog window.
|
||||
/// </summary>
|
||||
internal void ToggleChangelog()
|
||||
{
|
||||
this.changelogWindow.IsOpen ^= true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Toggle the settings window.
|
||||
/// </summary>
|
||||
internal void ToggleSettings()
|
||||
{
|
||||
this.settingsWindow.IsOpen ^= true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Toggle the log window.
|
||||
/// </summary>
|
||||
internal void ToggleLog()
|
||||
{
|
||||
this.logWindow.IsOpen ^= true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Toggle the data window.
|
||||
/// </summary>
|
||||
internal void ToggleData()
|
||||
{
|
||||
this.dataWindow.IsOpen ^= true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Toggle the data window and preset the dropdown.
|
||||
/// </summary>
|
||||
/// <param name="dataKind">The data kind to toggle.</param>
|
||||
internal void ToggleData(string dataKind)
|
||||
{
|
||||
this.dataWindow.IsOpen ^= true;
|
||||
if (this.dataWindow.IsOpen)
|
||||
this.dataWindow.SetDataKind(dataKind);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Toggle the credits window.
|
||||
/// </summary>
|
||||
internal void ToggleCredits()
|
||||
{
|
||||
this.creditsWindow.IsOpen ^= true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Toggle the stats window.
|
||||
/// </summary>
|
||||
internal void TogglePluginStats()
|
||||
{
|
||||
this.pluginStatWindow.IsOpen ^= true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Toggle the component test window.
|
||||
/// </summary>
|
||||
internal void ToggleComponentDemo()
|
||||
{
|
||||
this.componentDemoWindow.IsOpen ^= true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Toggle the scratchpad window.
|
||||
/// </summary>
|
||||
internal void ToggleScratchpadWindow()
|
||||
{
|
||||
this.scratchpadWindow.IsOpen ^= true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Toggle the gamepad notifier window window.
|
||||
/// </summary>
|
||||
internal void ToggleGamePadNotifierWindow()
|
||||
{
|
||||
this.gamepadModeNotifierWindow.IsOpen ^= true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -10,7 +10,6 @@ using Dalamud.Game;
|
|||
using Dalamud.Game.ClientState;
|
||||
using Dalamud.Game.Internal.DXGI;
|
||||
using Dalamud.Hooking;
|
||||
using EasyHook;
|
||||
using ImGuiNET;
|
||||
using ImGuiScene;
|
||||
using Serilog;
|
||||
|
|
@ -27,35 +26,24 @@ using SharpDX.Direct3D11;
|
|||
* - Might eventually want to render to a separate target and composite, especially with reshade etc in the mix.
|
||||
*/
|
||||
|
||||
namespace Dalamud.Interface
|
||||
namespace Dalamud.Interface.Internal
|
||||
{
|
||||
/// <summary>
|
||||
/// This class manages interaction with the ImGui interface.
|
||||
/// </summary>
|
||||
internal class InterfaceManager : IDisposable
|
||||
{
|
||||
/// <summary>
|
||||
/// Code that is exexuted when fonts are rebuilt.
|
||||
/// </summary>
|
||||
public Action OnBuildFonts;
|
||||
|
||||
/// <summary>
|
||||
/// The pointer to ImGui.IO(), when it last used..
|
||||
/// </summary>
|
||||
public ImGuiIOPtr LastImGuiIoPtr;
|
||||
|
||||
private readonly Dalamud dalamud;
|
||||
private readonly string rtssPath;
|
||||
|
||||
private readonly Hook<PresentDelegate> presentHook;
|
||||
private readonly Hook<ResizeBuffersDelegate> resizeBuffersHook;
|
||||
private readonly Hook<SetCursorDelegate> setCursorHook;
|
||||
|
||||
private ManualResetEvent fontBuildSignal;
|
||||
private ISwapChainAddressResolver address;
|
||||
private readonly ManualResetEvent fontBuildSignal;
|
||||
private readonly ISwapChainAddressResolver address;
|
||||
private RawDX11Scene scene;
|
||||
|
||||
private string rtssPath;
|
||||
|
||||
// can't access imgui IO before first present call
|
||||
private bool lastWantCapture = false;
|
||||
private bool isRebuildingFonts = false;
|
||||
|
|
@ -95,12 +83,12 @@ namespace Dalamud.Interface
|
|||
|
||||
try
|
||||
{
|
||||
var rtss = NativeFunctions.GetModuleHandle("RTSSHooks64.dll");
|
||||
var rtss = NativeFunctions.GetModuleHandleW("RTSSHooks64.dll");
|
||||
|
||||
if (rtss != IntPtr.Zero)
|
||||
{
|
||||
var fileName = new StringBuilder(255);
|
||||
NativeFunctions.GetModuleFileName(rtss, fileName, fileName.Capacity);
|
||||
_ = NativeFunctions.GetModuleFileNameW(rtss, fileName, fileName.Capacity);
|
||||
this.rtssPath = fileName.ToString();
|
||||
Log.Verbose("RTSS at {0}", this.rtssPath);
|
||||
|
||||
|
|
@ -113,17 +101,16 @@ namespace Dalamud.Interface
|
|||
Log.Error(e, "RTSS Free failed");
|
||||
}
|
||||
|
||||
var setCursorAddr = LocalHook.GetProcAddress("user32.dll", "SetCursor");
|
||||
var user32 = NativeFunctions.GetModuleHandleW("user32.dll");
|
||||
var setCursorAddr = NativeFunctions.GetProcAddress(user32, "SetCursor");
|
||||
|
||||
Log.Verbose("===== S W A P C H A I N =====");
|
||||
Log.Verbose("SetCursor address {SetCursor}", setCursorAddr);
|
||||
Log.Verbose("Present address {Present}", this.address.Present);
|
||||
Log.Verbose("ResizeBuffers address {ResizeBuffers}", this.address.ResizeBuffers);
|
||||
Log.Verbose($"SetCursor address 0x{setCursorAddr.ToInt64():X}");
|
||||
Log.Verbose($"Present address 0x{this.address.Present.ToInt64():X}");
|
||||
Log.Verbose($"ResizeBuffers address 0x{this.address.ResizeBuffers.ToInt64():X}");
|
||||
|
||||
this.setCursorHook = new Hook<SetCursorDelegate>(setCursorAddr, this.SetCursorDetour);
|
||||
|
||||
this.presentHook = new Hook<PresentDelegate>(this.address.Present, this.PresentDetour);
|
||||
|
||||
this.resizeBuffersHook = new Hook<ResizeBuffersDelegate>(this.address.ResizeBuffers, this.ResizeBuffersDetour);
|
||||
}
|
||||
|
||||
|
|
@ -153,6 +140,16 @@ namespace Dalamud.Interface
|
|||
/// </summary>
|
||||
public static ImFontPtr IconFont { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets an action that is exexuted when fonts are rebuilt.
|
||||
/// </summary>
|
||||
public Action OnBuildFonts { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the pointer to ImGui.IO(), when it was last used.
|
||||
/// </summary>
|
||||
public ImGuiIOPtr LastImGuiIoPtr { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the D3D11 device instance.
|
||||
/// </summary>
|
||||
|
|
@ -195,11 +192,11 @@ namespace Dalamud.Interface
|
|||
{
|
||||
if (!string.IsNullOrEmpty(this.rtssPath))
|
||||
{
|
||||
NativeFunctions.LoadLibrary(this.rtssPath);
|
||||
NativeFunctions.LoadLibraryW(this.rtssPath);
|
||||
var rtssModule = NativeFunctions.GetModuleHandleW("RTSSHooks64.dll");
|
||||
var installAddr = NativeFunctions.GetProcAddress(rtssModule, "InstallRTSSHook");
|
||||
|
||||
var installAddr = LocalHook.GetProcAddress("RTSSHooks64.dll", "InstallRTSSHook");
|
||||
var installDele = Marshal.GetDelegateForFunctionPointer<InstallRTSSHook>(installAddr);
|
||||
installDele.Invoke();
|
||||
Marshal.GetDelegateForFunctionPointer<InstallRTSSHook>(installAddr).Invoke();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
|
@ -567,7 +564,7 @@ namespace Dalamud.Interface
|
|||
{
|
||||
ImGui.GetIO().ConfigFlags ^= ImGuiConfigFlags.NavEnableGamepad;
|
||||
this.dalamud.ClientState.GamepadState.NavEnableGamepad ^= true;
|
||||
this.dalamud.DalamudUi.ToggleGamePadNotifierWindow();
|
||||
this.dalamud.DalamudUi.ToggleGamepadModeNotifierWindow();
|
||||
}
|
||||
|
||||
if (gamepadEnabled
|
||||
|
|
@ -592,7 +589,7 @@ namespace Dalamud.Interface
|
|||
|
||||
if (this.dalamud.ClientState.GamepadState.Pressed(GamepadButtons.R3) > 0)
|
||||
{
|
||||
this.dalamud.DalamudUi.TogglePluginInstaller();
|
||||
this.dalamud.DalamudUi.TogglePluginInstallerWindow();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -9,7 +9,7 @@ using Microsoft.CodeAnalysis.CSharp.Scripting;
|
|||
using Microsoft.CodeAnalysis.Scripting;
|
||||
using Serilog;
|
||||
|
||||
namespace Dalamud.Interface.Scratchpad
|
||||
namespace Dalamud.Interface.Internal.Scratchpad
|
||||
{
|
||||
/// <summary>
|
||||
/// This class manages the execution of <see cref="ScratchpadDocument"/> classes.
|
||||
|
|
@ -83,9 +83,9 @@ namespace Dalamud.Interface.Scratchpad
|
|||
{
|
||||
var script = CSharpScript.Create(code, options);
|
||||
|
||||
var pi = new DalamudPluginInterface(this.dalamud, "Scratch-" + doc.Id, null, PluginLoadReason.Installer);
|
||||
var plugin = script.ContinueWith<IDalamudPlugin>("return new ScratchPlugin() as IDalamudPlugin;").RunAsync().GetAwaiter().GetResult()
|
||||
.ReturnValue;
|
||||
var pi = new DalamudPluginInterface(this.dalamud, "Scratch-" + doc.Id, null);
|
||||
var plugin = script.ContinueWith<IDalamudPlugin>("return new ScratchPlugin() as IDalamudPlugin;")
|
||||
.RunAsync().GetAwaiter().GetResult().ReturnValue;
|
||||
|
||||
plugin.Initialize(pi);
|
||||
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace Dalamud.Interface.Scratchpad
|
||||
namespace Dalamud.Interface.Internal.Scratchpad
|
||||
{
|
||||
/// <summary>
|
||||
/// A file watcher for <see cref="ScratchpadDocument"/> classes.
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
namespace Dalamud.Interface.Scratchpad
|
||||
namespace Dalamud.Interface.Internal.Scratchpad
|
||||
{
|
||||
/// <summary>
|
||||
/// The load status of a <see cref="ScratchpadDocument"/> class.
|
||||
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