├── .gitignore ├── .vs ├── ProjectSettings.json ├── slnx.sqlite └── VSWorkspaceState.json ├── README.md ├── .gitmodules ├── packages ├── Fody.6.3.0 │ ├── .signature.p7s │ ├── Fody.6.3.0.nupkg │ ├── netclassictask │ │ ├── Fody.dll │ │ ├── FodyCommon.dll │ │ ├── Mono.Cecil.dll │ │ ├── Mono.Cecil.pdb │ │ ├── FodyHelpers.dll │ │ ├── FodyIsolated.dll │ │ ├── Mono.Cecil.Pdb.dll │ │ ├── Mono.Cecil.Pdb.pdb │ │ ├── Mono.Cecil.Rocks.dll │ │ └── Mono.Cecil.Rocks.pdb │ ├── netstandardtask │ │ ├── Fody.dll │ │ ├── FodyCommon.dll │ │ ├── FodyHelpers.dll │ │ ├── FodyIsolated.dll │ │ ├── Mono.Cecil.dll │ │ ├── Mono.Cecil.pdb │ │ ├── Mono.Cecil.Pdb.dll │ │ ├── Mono.Cecil.Pdb.pdb │ │ ├── Mono.Cecil.Rocks.dll │ │ └── Mono.Cecil.Rocks.pdb │ ├── License.txt │ └── build │ │ └── Fody.targets └── Costura.Fody.4.1.0 │ ├── .signature.p7s │ ├── lib │ └── net40 │ │ ├── Costura.dll │ │ └── Costura.xml │ ├── Costura.Fody.4.1.0.nupkg │ ├── weaver │ ├── Costura.Fody.dll │ └── Costura.Fody.xcf │ └── build │ └── Costura.Fody.props ├── Src └── Nioh2Resolution │ ├── FodyWeavers.xml │ ├── App.config │ ├── packages.config │ ├── Properties │ └── AssemblyInfo.cs │ ├── Nioh2Resolution.csproj │ ├── FodyWeavers.xsd │ └── Program.cs └── Nioh2Resolution.sln /.gitignore: -------------------------------------------------------------------------------- 1 | bin 2 | obj 3 | *.suo 4 | *.user -------------------------------------------------------------------------------- /.vs/ProjectSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "CurrentProjectSetting": null 3 | } -------------------------------------------------------------------------------- /.vs/slnx.sqlite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Filoppi/Nioh2Resolution/HEAD/.vs/slnx.sqlite -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | See here: 2 | https://community.pcgamingwiki.com/files/file/2146-nioh2resolution/ 3 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "Lib/Steamless"] 2 | path = Lib/Steamless 3 | url = https://github.com/atom0s/Steamless.git 4 | -------------------------------------------------------------------------------- /packages/Fody.6.3.0/.signature.p7s: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Filoppi/Nioh2Resolution/HEAD/packages/Fody.6.3.0/.signature.p7s -------------------------------------------------------------------------------- /packages/Fody.6.3.0/Fody.6.3.0.nupkg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Filoppi/Nioh2Resolution/HEAD/packages/Fody.6.3.0/Fody.6.3.0.nupkg -------------------------------------------------------------------------------- /packages/Costura.Fody.4.1.0/.signature.p7s: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Filoppi/Nioh2Resolution/HEAD/packages/Costura.Fody.4.1.0/.signature.p7s -------------------------------------------------------------------------------- /packages/Fody.6.3.0/netclassictask/Fody.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Filoppi/Nioh2Resolution/HEAD/packages/Fody.6.3.0/netclassictask/Fody.dll -------------------------------------------------------------------------------- /packages/Fody.6.3.0/netstandardtask/Fody.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Filoppi/Nioh2Resolution/HEAD/packages/Fody.6.3.0/netstandardtask/Fody.dll -------------------------------------------------------------------------------- /packages/Costura.Fody.4.1.0/lib/net40/Costura.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Filoppi/Nioh2Resolution/HEAD/packages/Costura.Fody.4.1.0/lib/net40/Costura.dll -------------------------------------------------------------------------------- /packages/Fody.6.3.0/netclassictask/FodyCommon.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Filoppi/Nioh2Resolution/HEAD/packages/Fody.6.3.0/netclassictask/FodyCommon.dll -------------------------------------------------------------------------------- /packages/Fody.6.3.0/netclassictask/Mono.Cecil.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Filoppi/Nioh2Resolution/HEAD/packages/Fody.6.3.0/netclassictask/Mono.Cecil.dll -------------------------------------------------------------------------------- /packages/Fody.6.3.0/netclassictask/Mono.Cecil.pdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Filoppi/Nioh2Resolution/HEAD/packages/Fody.6.3.0/netclassictask/Mono.Cecil.pdb -------------------------------------------------------------------------------- /.vs/VSWorkspaceState.json: -------------------------------------------------------------------------------- 1 | { 2 | "ExpandedNodes": [ 3 | "" 4 | ], 5 | "SelectedNode": "\\Steamless.sln", 6 | "PreviewInSolutionExplorer": false 7 | } -------------------------------------------------------------------------------- /packages/Costura.Fody.4.1.0/Costura.Fody.4.1.0.nupkg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Filoppi/Nioh2Resolution/HEAD/packages/Costura.Fody.4.1.0/Costura.Fody.4.1.0.nupkg -------------------------------------------------------------------------------- /packages/Costura.Fody.4.1.0/weaver/Costura.Fody.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Filoppi/Nioh2Resolution/HEAD/packages/Costura.Fody.4.1.0/weaver/Costura.Fody.dll -------------------------------------------------------------------------------- /packages/Fody.6.3.0/netclassictask/FodyHelpers.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Filoppi/Nioh2Resolution/HEAD/packages/Fody.6.3.0/netclassictask/FodyHelpers.dll -------------------------------------------------------------------------------- /packages/Fody.6.3.0/netclassictask/FodyIsolated.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Filoppi/Nioh2Resolution/HEAD/packages/Fody.6.3.0/netclassictask/FodyIsolated.dll -------------------------------------------------------------------------------- /packages/Fody.6.3.0/netstandardtask/FodyCommon.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Filoppi/Nioh2Resolution/HEAD/packages/Fody.6.3.0/netstandardtask/FodyCommon.dll -------------------------------------------------------------------------------- /packages/Fody.6.3.0/netstandardtask/FodyHelpers.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Filoppi/Nioh2Resolution/HEAD/packages/Fody.6.3.0/netstandardtask/FodyHelpers.dll -------------------------------------------------------------------------------- /packages/Fody.6.3.0/netstandardtask/FodyIsolated.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Filoppi/Nioh2Resolution/HEAD/packages/Fody.6.3.0/netstandardtask/FodyIsolated.dll -------------------------------------------------------------------------------- /packages/Fody.6.3.0/netstandardtask/Mono.Cecil.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Filoppi/Nioh2Resolution/HEAD/packages/Fody.6.3.0/netstandardtask/Mono.Cecil.dll -------------------------------------------------------------------------------- /packages/Fody.6.3.0/netstandardtask/Mono.Cecil.pdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Filoppi/Nioh2Resolution/HEAD/packages/Fody.6.3.0/netstandardtask/Mono.Cecil.pdb -------------------------------------------------------------------------------- /packages/Fody.6.3.0/netclassictask/Mono.Cecil.Pdb.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Filoppi/Nioh2Resolution/HEAD/packages/Fody.6.3.0/netclassictask/Mono.Cecil.Pdb.dll -------------------------------------------------------------------------------- /packages/Fody.6.3.0/netclassictask/Mono.Cecil.Pdb.pdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Filoppi/Nioh2Resolution/HEAD/packages/Fody.6.3.0/netclassictask/Mono.Cecil.Pdb.pdb -------------------------------------------------------------------------------- /packages/Fody.6.3.0/netstandardtask/Mono.Cecil.Pdb.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Filoppi/Nioh2Resolution/HEAD/packages/Fody.6.3.0/netstandardtask/Mono.Cecil.Pdb.dll -------------------------------------------------------------------------------- /packages/Fody.6.3.0/netstandardtask/Mono.Cecil.Pdb.pdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Filoppi/Nioh2Resolution/HEAD/packages/Fody.6.3.0/netstandardtask/Mono.Cecil.Pdb.pdb -------------------------------------------------------------------------------- /packages/Fody.6.3.0/netclassictask/Mono.Cecil.Rocks.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Filoppi/Nioh2Resolution/HEAD/packages/Fody.6.3.0/netclassictask/Mono.Cecil.Rocks.dll -------------------------------------------------------------------------------- /packages/Fody.6.3.0/netclassictask/Mono.Cecil.Rocks.pdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Filoppi/Nioh2Resolution/HEAD/packages/Fody.6.3.0/netclassictask/Mono.Cecil.Rocks.pdb -------------------------------------------------------------------------------- /packages/Fody.6.3.0/netstandardtask/Mono.Cecil.Rocks.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Filoppi/Nioh2Resolution/HEAD/packages/Fody.6.3.0/netstandardtask/Mono.Cecil.Rocks.dll -------------------------------------------------------------------------------- /packages/Fody.6.3.0/netstandardtask/Mono.Cecil.Rocks.pdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Filoppi/Nioh2Resolution/HEAD/packages/Fody.6.3.0/netstandardtask/Mono.Cecil.Rocks.pdb -------------------------------------------------------------------------------- /Src/Nioh2Resolution/FodyWeavers.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /Src/Nioh2Resolution/App.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /packages/Costura.Fody.4.1.0/build/Costura.Fody.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /Src/Nioh2Resolution/packages.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /packages/Costura.Fody.4.1.0/lib/net40/Costura.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Costura 5 | 6 | 7 | 8 | 9 | Contains methods for interacting with the Costura system. 10 | 11 | 12 | 13 | 14 | Call this to Initialize the Costura system. 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /packages/Fody.6.3.0/License.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) Simon Cropp 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. -------------------------------------------------------------------------------- /Src/Nioh2Resolution/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.InteropServices; 3 | 4 | // General Information about an assembly is controlled through the following 5 | // set of attributes. Change these attribute values to modify the information 6 | // associated with an assembly. 7 | [assembly: AssemblyTitle("Nioh2Resolution")] 8 | [assembly: AssemblyDescription("")] 9 | [assembly: AssemblyConfiguration("")] 10 | [assembly: AssemblyCompany("")] 11 | [assembly: AssemblyProduct("Nioh2Resolution")] 12 | [assembly: AssemblyCopyright("Copyright © Filippo Tarpini 2021")] 13 | [assembly: AssemblyTrademark("")] 14 | [assembly: AssemblyCulture("")] 15 | 16 | // Setting ComVisible to false makes the types in this assembly not visible 17 | // to COM components. If you need to access a type in this assembly from 18 | // COM, set the ComVisible attribute to true on that type. 19 | [assembly: ComVisible(false)] 20 | 21 | // The following GUID is for the ID of the typelib if this project is exposed to COM 22 | [assembly: Guid("369eaaeb-080a-4c1c-ac0f-37581cd98bfc")] 23 | 24 | // Version information for an assembly consists of the following four values: 25 | // 26 | // Major Version 27 | // Minor Version 28 | // Build Number 29 | // Revision 30 | // 31 | // You can specify all the values or you can default the Build and Revision Numbers 32 | // by using the '*' as shown below: 33 | // [assembly: AssemblyVersion("1.0.*")] 34 | [assembly: AssemblyVersion("1.0.0.0")] 35 | [assembly: AssemblyFileVersion("1.0.0.0")] 36 | -------------------------------------------------------------------------------- /Nioh2Resolution.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.29519.87 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nioh2Resolution", "Src\Nioh2Resolution\Nioh2Resolution.csproj", "{369EAAEB-080A-4C1C-AC0F-37581CD98BFD}" 7 | EndProject 8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Libraries", "Libraries", "{1FA8987A-75B3-46FE-9AE2-093FB6E1257C}" 9 | EndProject 10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Steamless.API", "Lib\Steamless\Steamless.API\Steamless.API.csproj", "{56C95629-3B34-47FE-B988-04274409294F}" 11 | EndProject 12 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Steamless.Unpacker.Variant31.x64", "Lib\Steamless\Steamless.Unpacker.Variant31.x64\Steamless.Unpacker.Variant31.x64.csproj", "{05F540FB-D14B-4966-8DE2-591B76361CF0}" 13 | EndProject 14 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Documentation", "Documentation", "{2E9E0824-3394-48A4-A078-8D59CB77DA15}" 15 | ProjectSection(SolutionItems) = preProject 16 | README.md = README.md 17 | EndProjectSection 18 | EndProject 19 | Global 20 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 21 | Debug|Any CPU = Debug|Any CPU 22 | Debug|x86 = Debug|x86 23 | Release|Any CPU = Release|Any CPU 24 | Release|x86 = Release|x86 25 | EndGlobalSection 26 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 27 | {369EAAEB-080A-4C1C-AC0F-37581CD98BFD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 28 | {369EAAEB-080A-4C1C-AC0F-37581CD98BFD}.Debug|Any CPU.Build.0 = Debug|Any CPU 29 | {369EAAEB-080A-4C1C-AC0F-37581CD98BFD}.Debug|x86.ActiveCfg = Debug|Any CPU 30 | {369EAAEB-080A-4C1C-AC0F-37581CD98BFD}.Debug|x86.Build.0 = Debug|Any CPU 31 | {369EAAEB-080A-4C1C-AC0F-37581CD98BFD}.Release|Any CPU.ActiveCfg = Release|Any CPU 32 | {369EAAEB-080A-4C1C-AC0F-37581CD98BFD}.Release|Any CPU.Build.0 = Release|Any CPU 33 | {369EAAEB-080A-4C1C-AC0F-37581CD98BFD}.Release|x86.ActiveCfg = Release|Any CPU 34 | {369EAAEB-080A-4C1C-AC0F-37581CD98BFD}.Release|x86.Build.0 = Release|Any CPU 35 | {56C95629-3B34-47FE-B988-04274409294F}.Debug|Any CPU.ActiveCfg = Debug|x86 36 | {56C95629-3B34-47FE-B988-04274409294F}.Debug|Any CPU.Build.0 = Debug|x86 37 | {56C95629-3B34-47FE-B988-04274409294F}.Debug|x86.ActiveCfg = Debug|x86 38 | {56C95629-3B34-47FE-B988-04274409294F}.Debug|x86.Build.0 = Debug|x86 39 | {56C95629-3B34-47FE-B988-04274409294F}.Release|Any CPU.ActiveCfg = Release|x86 40 | {56C95629-3B34-47FE-B988-04274409294F}.Release|Any CPU.Build.0 = Release|x86 41 | {56C95629-3B34-47FE-B988-04274409294F}.Release|x86.ActiveCfg = Release|x86 42 | {56C95629-3B34-47FE-B988-04274409294F}.Release|x86.Build.0 = Release|x86 43 | {05F540FB-D14B-4966-8DE2-591B76361CF0}.Debug|Any CPU.ActiveCfg = Debug|x86 44 | {05F540FB-D14B-4966-8DE2-591B76361CF0}.Debug|Any CPU.Build.0 = Debug|x86 45 | {05F540FB-D14B-4966-8DE2-591B76361CF0}.Debug|x86.ActiveCfg = Debug|x86 46 | {05F540FB-D14B-4966-8DE2-591B76361CF0}.Debug|x86.Build.0 = Debug|x86 47 | {05F540FB-D14B-4966-8DE2-591B76361CF0}.Release|Any CPU.ActiveCfg = Release|x86 48 | {05F540FB-D14B-4966-8DE2-591B76361CF0}.Release|Any CPU.Build.0 = Release|x86 49 | {05F540FB-D14B-4966-8DE2-591B76361CF0}.Release|x86.ActiveCfg = Release|x86 50 | {05F540FB-D14B-4966-8DE2-591B76361CF0}.Release|x86.Build.0 = Release|x86 51 | EndGlobalSection 52 | GlobalSection(SolutionProperties) = preSolution 53 | HideSolutionNode = FALSE 54 | EndGlobalSection 55 | GlobalSection(NestedProjects) = preSolution 56 | {56C95629-3B34-47FE-B988-04274409294F} = {1FA8987A-75B3-46FE-9AE2-093FB6E1257C} 57 | {05F540FB-D14B-4966-8DE2-591B76361CF0} = {1FA8987A-75B3-46FE-9AE2-093FB6E1257C} 58 | EndGlobalSection 59 | GlobalSection(ExtensibilityGlobals) = postSolution 60 | SolutionGuid = {30709AFF-6DE0-4B90-8271-4BC13F071011} 61 | EndGlobalSection 62 | EndGlobal 63 | -------------------------------------------------------------------------------- /packages/Costura.Fody.4.1.0/weaver/Costura.Fody.xcf: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | A list of assembly names to exclude from the default action of "embed all Copy Local references", delimited with line breaks 7 | 8 | 9 | 10 | 11 | A list of assembly names to include from the default action of "embed all Copy Local references", delimited with line breaks. 12 | 13 | 14 | 15 | 16 | A list of unmanaged 32 bit assembly names to include, delimited with line breaks. 17 | 18 | 19 | 20 | 21 | A list of unmanaged 64 bit assembly names to include, delimited with line breaks. 22 | 23 | 24 | 25 | 26 | The order of preloaded assemblies, delimited with line breaks. 27 | 28 | 29 | 30 | 31 | 32 | This will copy embedded files to disk before loading them into memory. This is helpful for some scenarios that expected an assembly to be loaded from a physical file. 33 | 34 | 35 | 36 | 37 | Controls if .pdbs for reference assemblies are also embedded. 38 | 39 | 40 | 41 | 42 | Embedded assemblies are compressed by default, and uncompressed when they are loaded. You can turn compression off with this option. 43 | 44 | 45 | 46 | 47 | As part of Costura, embedded assemblies are no longer included as part of the build. This cleanup can be turned off. 48 | 49 | 50 | 51 | 52 | Costura by default will load as part of the module initialization. This flag disables that behavior. Make sure you call CosturaUtility.Initialize() somewhere in your code. 53 | 54 | 55 | 56 | 57 | Costura will by default use assemblies with a name like 'resources.dll' as a satellite resource and prepend the output path. This flag disables that behavior. 58 | 59 | 60 | 61 | 62 | A list of assembly names to exclude from the default action of "embed all Copy Local references", delimited with | 63 | 64 | 65 | 66 | 67 | A list of assembly names to include from the default action of "embed all Copy Local references", delimited with |. 68 | 69 | 70 | 71 | 72 | A list of unmanaged 32 bit assembly names to include, delimited with |. 73 | 74 | 75 | 76 | 77 | A list of unmanaged 64 bit assembly names to include, delimited with |. 78 | 79 | 80 | 81 | 82 | The order of preloaded assemblies, delimited with |. 83 | 84 | 85 | -------------------------------------------------------------------------------- /packages/Fody.6.3.0/build/Fody.targets: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | $(ProjectDir)FodyWeavers.xml 5 | $(MSBuildThisFileDirectory)..\ 6 | $(FodyPath)netstandardtask 7 | $(FodyPath)netclassictask 8 | $(FodyAssemblyDirectory)\Fody.dll 9 | $(DefaultItemExcludes);FodyWeavers.xsd 10 | true 11 | 15 12 | $([System.Version]::Parse($(MSBuildVersion)).Major) 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 37 | 38 | 40 | 60 | 61 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 77 | 78 | 82 | 83 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 101 | 102 | 110 | 111 | 112 | -------------------------------------------------------------------------------- /Src/Nioh2Resolution/Nioh2Resolution.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Debug 7 | AnyCPU 8 | {369EAAEB-080A-4C1C-AC0F-37581CD98BFD} 9 | Exe 10 | Properties 11 | Nioh2Resolution 12 | Nioh2Resolution 13 | v4.8 14 | 512 15 | true 16 | 17 | false 18 | publish\ 19 | true 20 | Disk 21 | false 22 | Foreground 23 | 7 24 | Days 25 | false 26 | false 27 | true 28 | 0 29 | 1.0.0.%2a 30 | false 31 | true 32 | 33 | 34 | 35 | 36 | x86 37 | true 38 | full 39 | false 40 | ..\..\Bin\Debug\ 41 | DEBUG;TRACE 42 | prompt 43 | 4 44 | 45 | 46 | x86 47 | pdbonly 48 | true 49 | ..\..\Bin\Release\ 50 | TRACE 51 | prompt 52 | 4 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | ..\..\packages\Costura.Fody.4.1.0\lib\net40\Costura.dll 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | {56c95629-3b34-47fe-b988-04274409294f} 76 | Steamless.API 77 | True 78 | 79 | 80 | {05f540fb-d14b-4966-8de2-591b76361cf0} 81 | Steamless.Unpacker.Variant31.x64 82 | True 83 | 84 | 85 | 86 | 87 | False 88 | Microsoft .NET Framework 4.6.1 %28x86 and x64%29 89 | true 90 | 91 | 92 | False 93 | .NET Framework 3.5 SP1 94 | false 95 | 96 | 97 | 98 | 99 | 100 | This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. 101 | 102 | 103 | 104 | 105 | 106 | 113 | -------------------------------------------------------------------------------- /Src/Nioh2Resolution/FodyWeavers.xsd: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | A list of assembly names to exclude from the default action of "embed all Copy Local references", delimited with line breaks 13 | 14 | 15 | 16 | 17 | A list of assembly names to include from the default action of "embed all Copy Local references", delimited with line breaks. 18 | 19 | 20 | 21 | 22 | A list of unmanaged 32 bit assembly names to include, delimited with line breaks. 23 | 24 | 25 | 26 | 27 | A list of unmanaged 64 bit assembly names to include, delimited with line breaks. 28 | 29 | 30 | 31 | 32 | The order of preloaded assemblies, delimited with line breaks. 33 | 34 | 35 | 36 | 37 | 38 | This will copy embedded files to disk before loading them into memory. This is helpful for some scenarios that expected an assembly to be loaded from a physical file. 39 | 40 | 41 | 42 | 43 | Controls if .pdbs for reference assemblies are also embedded. 44 | 45 | 46 | 47 | 48 | Embedded assemblies are compressed by default, and uncompressed when they are loaded. You can turn compression off with this option. 49 | 50 | 51 | 52 | 53 | As part of Costura, embedded assemblies are no longer included as part of the build. This cleanup can be turned off. 54 | 55 | 56 | 57 | 58 | Costura by default will load as part of the module initialization. This flag disables that behavior. Make sure you call CosturaUtility.Initialize() somewhere in your code. 59 | 60 | 61 | 62 | 63 | Costura will by default use assemblies with a name like 'resources.dll' as a satellite resource and prepend the output path. This flag disables that behavior. 64 | 65 | 66 | 67 | 68 | A list of assembly names to exclude from the default action of "embed all Copy Local references", delimited with | 69 | 70 | 71 | 72 | 73 | A list of assembly names to include from the default action of "embed all Copy Local references", delimited with |. 74 | 75 | 76 | 77 | 78 | A list of unmanaged 32 bit assembly names to include, delimited with |. 79 | 80 | 81 | 82 | 83 | A list of unmanaged 64 bit assembly names to include, delimited with |. 84 | 85 | 86 | 87 | 88 | The order of preloaded assemblies, delimited with |. 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed. 97 | 98 | 99 | 100 | 101 | A comma-separated list of error codes that can be safely ignored in assembly verification. 102 | 103 | 104 | 105 | 106 | 'false' to turn off automatic generation of the XML Schema file. 107 | 108 | 109 | 110 | 111 | -------------------------------------------------------------------------------- /Src/Nioh2Resolution/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Globalization; 4 | using System.IO; 5 | using System.Linq; 6 | using System.Threading; 7 | using Steamless.API.Model; 8 | using Steamless.API.Services; 9 | using Steamless.Unpacker.Variant31.x64; 10 | 11 | namespace Nioh2Resolution 12 | { 13 | public class Program 14 | { 15 | private const string EXE_FILE = "nioh2.exe"; 16 | private const string EXE_FILE_BACKUP = "nioh2.exe.backup.exe"; 17 | private const string EXE_FILE_UNPACKED = "nioh2.exe.unpacked.exe"; 18 | 19 | // 16:9 20 | private const int DEFAULT_AR_RES_W = 1920; 21 | private const int DEFAULT_AR_RES_H = 1080; 22 | private const float DEFAULT_AR = DEFAULT_AR_RES_W / (float)DEFAULT_AR_RES_H; 23 | private const double DEFAULT_AR_DOUBLE = DEFAULT_AR_RES_W / (double)DEFAULT_AR_RES_H; 24 | // Based on recent research, any aspect ratio above this number is treated as widescreen and uses 25 | // the widescreen set of UI textures and code. 26 | // It's likely that any AR above 2.0 that isn't exactly 64:27 will cause UI drift. 27 | private const float MAX_NON_WIDESCREEN_AR = 2.0f; 28 | 29 | // "Lower" max supported AR is 64:27 (2.370370...). 30 | // This is the AR they have hardcoded for Widescreen as far as patch 1.26. 31 | // UI will slowly drift for any other AR that isn't this or 16:9. 32 | private const int MAX_AR_RES_1_W = 2560; 33 | private const int MAX_AR_RES_1_H = 1080; 34 | private const float MAX_AR_1 = MAX_AR_RES_1_W / (float)MAX_AR_RES_1_H; 35 | private const double MAX_AR_1_DOUBLE = MAX_AR_RES_1_W / (double)MAX_AR_RES_1_H; 36 | // Max supported AR is 43:18 (2.3888...) 37 | private const int MAX_AR_RES_2_W = 3440; 38 | private const int MAX_AR_RES_2_H = 1440; 39 | private const float MAX_AR_2 = MAX_AR_RES_2_W / (float)MAX_AR_RES_2_H; 40 | private const double MAX_AR_2_DOUBLE = MAX_AR_RES_2_W / (double)MAX_AR_RES_2_H; 41 | // Guessed generic 21:9 AR 42 | private const int MAX_AR_GUESS_W = 21; 43 | private const int MAX_AR_GUESS_H = 9; 44 | private const float MAX_AR_GUESS = MAX_AR_GUESS_W / (float)MAX_AR_GUESS_H; 45 | private const double MAX_AR_GUESS_DOUBLE = MAX_AR_GUESS_W / (double)MAX_AR_GUESS_H; 46 | 47 | private const float AR_TOLERANCE = 0.0001f; 48 | 49 | private static int RES_TO_REPLACE_W = 1280; 50 | private static int RES_TO_REPLACE_H = 720; 51 | 52 | public static void Main(string[] args) 53 | { 54 | Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US"); 55 | 56 | Console.WriteLine("Welcome to the Nioh 2 Resolution patcher!\n"); 57 | 58 | int res_to_replace = ReadInt("Select the resolution you want to replace.\n1 for 1280x720, 2 for 1920x1080, 3 for 3440x1440.", 1); 59 | if (res_to_replace <= 1 || res_to_replace > 3) 60 | { 61 | RES_TO_REPLACE_W = 1280; 62 | RES_TO_REPLACE_H = 720; 63 | } 64 | else if (res_to_replace == 2) 65 | { 66 | RES_TO_REPLACE_W = 1920; 67 | RES_TO_REPLACE_H = 1080; 68 | } 69 | else if (res_to_replace == 3) 70 | { 71 | RES_TO_REPLACE_W = 3440; 72 | RES_TO_REPLACE_H = 1440; 73 | } 74 | 75 | Console.WriteLine("\nPlease enter your desired resolution (it might not work if it's higher than your screen)."); 76 | 77 | int width = ReadInt("Width", RES_TO_REPLACE_W); 78 | int height = ReadInt("Height", RES_TO_REPLACE_H); 79 | 80 | bool patch_UI = false; 81 | bool ask_for_UI_patch = false; 82 | bool ask_for_black_bars = false; 83 | float ratio = width / (float)height; 84 | if (ratio + AR_TOLERANCE < DEFAULT_AR) 85 | { 86 | Console.WriteLine("\nYour aspect ratio is below the minimum official supported."); 87 | ask_for_UI_patch = true; 88 | ask_for_black_bars = true; 89 | } 90 | // TODO: we should probably replace DEFAULT_AR here with MAX_NON_WIDESCREEN_AR, but it's untested 91 | else if (ratio - AR_TOLERANCE > DEFAULT_AR && ratio + AR_TOLERANCE < MAX_AR_1) 92 | { 93 | Console.WriteLine("\nYour aspect ratio is in between supported ones (16:9 and 21:9)."); 94 | ask_for_UI_patch = true; 95 | } 96 | else if (ratio - AR_TOLERANCE > MAX_AR_1) 97 | { 98 | Console.WriteLine("\nYour aspect ratio is above 64:27 (~21:9), the officially supported max."); 99 | ask_for_UI_patch = true; 100 | } 101 | 102 | if (ask_for_UI_patch || ask_for_black_bars) 103 | { 104 | if (ask_for_UI_patch && 105 | ReadBool("The UI might not scale or anchor correctly, it might be partially hidden and also drift as you play.\n" + 106 | "There is an EXPERIMANTAL fix available, it might shrink the UI in some places but it will fix the drifting and\nimprove the in game UI.\nNOTE THAT DEPENDING ON YOUR ASPECT RATIO THIS WILL BREAK THE MAP SELECTION SCREEN" + 107 | "\n(SOMETIMES YOU CAN STILL MAKE YOUR WAY WITH DIRECTIONAL KEYS),\nbut at the same time it can make other parts of the UI selectable.\n" + 108 | "For now, a possible solution is to patch the exe twice, one with the UI fix and one without, and switch when having to select a mission.\nWould you like to apply it?", false)) 109 | { 110 | patch_UI = true; 111 | } 112 | else if (ask_for_black_bars) 113 | { 114 | Console.WriteLine(""); 115 | if (ReadBool("Would you like me to find the maximum 16:9 resolution contained by your screen?\nThat way you could play borderless with black bars by putting a black background behind the game", false)) 116 | { 117 | height = (int)Math.Round(width / DEFAULT_AR); 118 | } 119 | } 120 | } 121 | 122 | if (File.Exists(EXE_FILE_BACKUP)) 123 | { 124 | Console.WriteLine($"\nA backup of {EXE_FILE} has been found, it was created the last time this patcher ran succesfully."); 125 | 126 | if (ReadBool("Do you want to restore this backup before patching?", false)) 127 | { 128 | File.Copy(EXE_FILE_BACKUP, EXE_FILE, true); 129 | } 130 | } 131 | 132 | if (!File.Exists(EXE_FILE)) 133 | { 134 | Console.WriteLine($"\nCould not find {EXE_FILE}!"); 135 | 136 | Exit(); 137 | 138 | return; 139 | } 140 | 141 | Console.WriteLine($"\nUnpacking {EXE_FILE}..."); 142 | 143 | var result = UnpackExe(); 144 | if (!result) 145 | { 146 | Console.WriteLine($"\nUnpacking of {EXE_FILE} failed (will continue)."); 147 | 148 | File.Copy(EXE_FILE, EXE_FILE_UNPACKED, true); 149 | } 150 | 151 | Console.WriteLine($"\nPatching resolution to {width}x{height}..."); 152 | 153 | var buffer = File.ReadAllBytes(EXE_FILE_UNPACKED); 154 | 155 | bool UI_patch_failed = false; 156 | result = PatchExe(ref buffer, width, height, patch_UI, ref UI_patch_failed); 157 | 158 | if (!result) 159 | { 160 | Console.WriteLine("\nPatching failed, consider restoring a backup and try again."); 161 | 162 | File.Delete(EXE_FILE_UNPACKED); 163 | 164 | Exit(); 165 | 166 | return; 167 | } 168 | else if (UI_patch_failed) 169 | { 170 | Console.WriteLine("\nUI failed to patch, resolution was patched nonetheless."); 171 | } 172 | 173 | Console.WriteLine($"\nBacking up {EXE_FILE}..."); 174 | 175 | File.Copy(EXE_FILE, EXE_FILE_BACKUP, true); 176 | 177 | Console.WriteLine($"\nReplacing {EXE_FILE}..."); 178 | 179 | File.WriteAllBytes(EXE_FILE, buffer); 180 | File.Delete(EXE_FILE_UNPACKED); 181 | 182 | Console.WriteLine($"\nDone! Don't forget to set the game resolution to {RES_TO_REPLACE_W}x{RES_TO_REPLACE_H} and restart the game.\nYou can also do it from the config file."); 183 | 184 | Exit(); 185 | } 186 | 187 | private static bool UnpackExe() 188 | { 189 | LoggingService loggingService = new LoggingService(); 190 | loggingService.AddLogMessage += (sender, eventArgs) => 191 | { 192 | Console.WriteLine(eventArgs.Message); 193 | }; 194 | 195 | SteamlessPlugin plugin = new Main(); 196 | plugin.Initialize(loggingService); 197 | 198 | var result = plugin.CanProcessFile(EXE_FILE); 199 | 200 | if (!result) 201 | { 202 | return false; 203 | } 204 | 205 | result = plugin.ProcessFile(EXE_FILE, new SteamlessOptions 206 | { 207 | VerboseOutput = false, 208 | KeepBindSection = true 209 | }); 210 | 211 | if (!result) 212 | { 213 | Console.WriteLine($"-> Processing {EXE_FILE} failed (file might not be encrypted)!"); 214 | 215 | return false; 216 | } 217 | 218 | return true; 219 | } 220 | 221 | private static bool PatchExe(ref byte[] buffer, int width, int height, bool patch_UI, ref bool UI_patch_failed) 222 | { 223 | UI_patch_failed = !PatchAspectRatio(ref buffer, width, height, patch_UI); 224 | bool success = PatchResolution(ref buffer, width, height); 225 | return success; 226 | } 227 | 228 | private static bool PatchAspectRatio(ref byte[] buffer, int width, int height, bool patch_UI) 229 | { 230 | if (!patch_UI) // Here in case we wanted to still patch parts of the UI nonetheless 231 | { 232 | return true; // Success 233 | } 234 | 235 | float ratio = width / (float)height; 236 | float patch_ratio = DEFAULT_AR; 237 | 238 | float ratioWidth = DEFAULT_AR_RES_W; 239 | float ratioHeight = DEFAULT_AR_RES_H; 240 | // Scaling MAX_AR_2 will make the UI slightly drift with mission restarts/cutscenes and so on... 241 | float target_max_AR = MAX_AR_1; 242 | 243 | if (ratio < DEFAULT_AR) 244 | { 245 | // Changing both patch_ratio and ratioWidth didn't seem to work in this case 246 | ratioHeight = ratioWidth / ratio; 247 | patch_ratio = ratio; 248 | } 249 | else 250 | { 251 | // Nioh 2 compares MAX_AR_1 to DEFAULT_AR to compute how much to shift the UI of. 252 | // This calculation breaks at any other aspect ratio (including the supported MAX_AR_2) 253 | // and makes the UI shift/drift with time. If we patch some hardcoded values, 254 | // we can fix the UI drifting at the cost of "more broken" menus and stretched AR 255 | // in some cutscenes. 256 | ratioWidth *= target_max_AR / DEFAULT_AR; 257 | patch_ratio = target_max_AR; 258 | } 259 | 260 | /* Some random patches that didn't seem to make any difference 261 | var positions = FindSequence(ref buffer, ConvertToBytes(MAX_AR_1_DOUBLE)); // 0 262 | positions = FindSequence(ref buffer, ConvertToBytes(MAX_AR_2_DOUBLE)); // 0 263 | positions = FindSequence(ref buffer, ConvertToBytes(MAX_AR_GUESS_DOUBLE)); // 0 264 | positions = FindSequence(ref buffer, ConvertToBytes(MAX_AR_1)); // 0 265 | positions = FindSequence(ref buffer, ConvertToBytes(MAX_AR_2)); // 0 266 | positions = FindSequence(ref buffer, ConvertToBytes(MAX_AR_GUESS)); // 0 267 | 268 | positions = FindSequence(ref buffer, ConvertToBytes(DEFAULT_AR_DOUBLE / MAX_AR_1_DOUBLE)); // 2 269 | Patch(ref buffer, positions, ConvertToBytes(DEFAULT_AR_DOUBLE / ratio_double)); 270 | positions = FindSequence(ref buffer, ConvertToBytes(DEFAULT_AR_DOUBLE / MAX_AR_2_DOUBLE)); // 0 271 | Patch(ref buffer, positions, ConvertToBytes(DEFAULT_AR_DOUBLE / ratio_double)); 272 | positions = FindSequence(ref buffer, ConvertToBytes(DEFAULT_AR_DOUBLE / MAX_AR_GUESS_DOUBLE)); // 0 273 | Patch(ref buffer, positions, ConvertToBytes(DEFAULT_AR_DOUBLE / ratio_double)); 274 | positions = FindSequence(ref buffer, ConvertToBytes(MAX_AR_1_DOUBLE / DEFAULT_AR_DOUBLE)); // 1 275 | Patch(ref buffer, positions, ConvertToBytes(ratio_double / DEFAULT_AR_DOUBLE)); 276 | positions = FindSequence(ref buffer, ConvertToBytes(MAX_AR_2_DOUBLE / DEFAULT_AR_DOUBLE)); // 2 277 | Patch(ref buffer, positions, ConvertToBytes(ratio_double / DEFAULT_AR_DOUBLE)); 278 | positions = FindSequence(ref buffer, ConvertToBytes(MAX_AR_GUESS_DOUBLE / DEFAULT_AR_DOUBLE)); // 0 279 | Patch(ref buffer, positions, ConvertToBytes(ratio_double / DEFAULT_AR_DOUBLE)); 280 | positions = FindSequence(ref buffer, ConvertToBytes(DEFAULT_AR / MAX_AR_1)); // 59 281 | // Some index between 49 and 52 AND also between 55 and 58 makes the game crash or infinite load 282 | Patch(ref buffer, positions, 0, 48, ConvertToBytes(DEFAULT_AR / ratio)); 283 | Patch(ref buffer, positions, 53, 54, ConvertToBytes(DEFAULT_AR / ratio)); 284 | positions = FindSequence(ref buffer, ConvertToBytes(DEFAULT_AR / MAX_AR_2)); // 0 285 | Patch(ref buffer, positions, ConvertToBytes(DEFAULT_AR / ratio)); 286 | positions = FindSequence(ref buffer, ConvertToBytes(DEFAULT_AR / MAX_AR_GUESS)); // 0 287 | Patch(ref buffer, positions, ConvertToBytes(DEFAULT_AR / ratio)); 288 | positions = FindSequence(ref buffer, ConvertToBytes(MAX_AR_1 / DEFAULT_AR)); // 2 289 | Patch(ref buffer, positions, ConvertToBytes(ratio / DEFAULT_AR)); 290 | positions = FindSequence(ref buffer, ConvertToBytes(MAX_AR_2 / DEFAULT_AR)); // 5 291 | Patch(ref buffer, positions, ConvertToBytes(ratio / DEFAULT_AR)); 292 | positions = FindSequence(ref buffer, ConvertToBytes(MAX_AR_GUESS / DEFAULT_AR)); // 13 293 | Patch(ref buffer, positions, ConvertToBytes(ratio / DEFAULT_AR)); 294 | //TODO unhardcode 32:9 (my AR) 295 | positions = FindSequence(ref buffer, ConvertToBytes(MAX_AR_GUESS_H / (double)MAX_AR_GUESS_W)); // 0 296 | Patch(ref buffer, positions, ConvertToBytes(16.0 / 32.0)); 297 | positions = FindSequence(ref buffer, ConvertToBytes(MAX_AR_GUESS_W / (double)MAX_AR_GUESS_H)); // 2 298 | Patch(ref buffer, positions, ConvertToBytes(32.0 / 16.0)); 299 | positions = FindSequence(ref buffer, ConvertToBytes(MAX_AR_GUESS_H / (float)MAX_AR_GUESS_W)); // 0 300 | Patch(ref buffer, positions, ConvertToBytes(16.0f / 32.0f)); 301 | positions = FindSequence(ref buffer, ConvertToBytes(MAX_AR_GUESS_W / (float)MAX_AR_GUESS_H)); // 13 302 | Patch(ref buffer, positions, ConvertToBytes(32.0f / 16.0f));*/ 303 | 304 | // Aspect Ratio Fix #1 (double 16/9): Disabled as it seems to have no effect on UI 305 | /*var positions = FindSequence(ref buffer, ConvertToBytes(DEFAULT_AR_DOUBLE)); 306 | 307 | if (!AssertEquals("Aspect Ratio Pattern 1", 1, positions.Count)) 308 | { 309 | return false; 310 | } 311 | 312 | var ratio1Patch = ConvertToBytes((double)patch_ratio); 313 | Patch(ref buffer, positions, ratio1Patch);*/ 314 | 315 | // First, make sure all the positions are as expected... 316 | 317 | var positions2 = FindSequence(ref buffer, ConvertToBytes(DEFAULT_AR)); 318 | if (!AssertEquals("Aspect Ratio Pattern 2", 26, positions2.Count)) 319 | { 320 | return false; 321 | } 322 | 323 | var ratio3Pattern = ConvertToBytes((float)DEFAULT_AR_RES_H).Concat(ConvertToBytes((float)DEFAULT_AR_RES_W)).ToArray(); 324 | var positions3 = FindSequence(ref buffer, ratio3Pattern); 325 | 326 | if (!AssertEquals("Aspect Ratio Pattern 3", 1, positions3.Count)) 327 | { 328 | return false; 329 | } 330 | 331 | // Then, apply the patches... 332 | 333 | // Aspect Ratio Fix #2 (float 16/9): Changes the UI aspect ratio/scale 334 | var ratio2Patch = ConvertToBytes(patch_ratio); 335 | // TODO: instead of doing this, we should find a magic pattern around these numbers, or this patch would likely break when new versions of the game are released 336 | // Indexs 0 to 20 and 22 to 25 have no effects on UI. 337 | // Only index 21 has an effect, at least until ver 1.25 (this patch might not be safe for later updates). 338 | Patch(ref buffer, positions2, 21, 21, ratio2Patch); 339 | 340 | // Aspect Ratio Fix #3: Scales the UI in some ways, needs to have the same AR as the Fix #2 or it causes UI drifting and stretched UI. 341 | // Changing the height seems to have a different effect than changhing the width (they are used differently). 342 | // The smaller the numbers are, the bigger the UI gets. 343 | var ratio3Patch = ConvertToBytes(ratioHeight).Concat(ConvertToBytes(ratioWidth)).ToArray(); 344 | Patch(ref buffer, positions3, ratio3Patch); 345 | 346 | return true; 347 | } 348 | 349 | // Had no success with this 350 | private static bool PatchFPS(ref byte[] buffer, int targetFPS = 240) 351 | { 352 | string FPSText = "120"; 353 | string customFPSText = "240"; // Needs to be of the same length of course 354 | var patternFPSText = ConvertToBytes(FPSText); 355 | var patchFPSText = ConvertToBytes(customFPSText); 356 | var positions_text = FindSequence(ref buffer, patternFPSText); 357 | Patch(ref buffer, positions_text, patchFPSText); 358 | 359 | char targetFPSi = (char)targetFPS; 360 | float targetFPSf = (float)targetFPS; 361 | float targetDTf = 1.0f / targetFPSf; 362 | double targetFPSd = (double)targetFPS; 363 | double targetDTd = 1.0 / targetFPSd; 364 | 365 | //To review: try char and short. Try little endians? 366 | char FPSi = (char)120; 367 | float FPSf = 120.0f; 368 | float DTf = 1.0f / FPSf; 369 | double FPSd = 120.0; 370 | double DTd = 1.0 / FPSd; 371 | var positions120FPSi = FindSequence(ref buffer, ConvertToBytes(FPSi)); 372 | //Patch(ref buffer, positions120FPSi, ConvertToBytes(targetFPSi)); 373 | var positions120FPSf = FindSequence(ref buffer, ConvertToBytes(FPSf)); 374 | //Patch(ref buffer, positions120FPSf, ConvertToBytes(targetFPSf)); 375 | var positions120DTf = FindSequence(ref buffer, ConvertToBytes(DTf)); 376 | //Patch(ref buffer, positions120DTf, ConvertToBytes(targetDTf)); 377 | var positions120FPSd = FindSequence(ref buffer, ConvertToBytes(FPSd)); 378 | //Patch(ref buffer, positions120FPSd, ConvertToBytes(targetFPSd)); 379 | var positions120DTd = FindSequence(ref buffer, ConvertToBytes(DTd)); 380 | //Patch(ref buffer, positions120DTd, ConvertToBytes(targetDTd)); 381 | FPSi = (char)60; 382 | FPSf = 60.0f; 383 | DTf = 1.0f / FPSf; 384 | FPSd = 60.0; 385 | DTd = 1.0 / FPSd; 386 | var positions60FPSi = FindSequence(ref buffer, ConvertToBytes(FPSi)); 387 | var positions60FPSf = FindSequence(ref buffer, ConvertToBytes(FPSf)); 388 | var positions60DTf = FindSequence(ref buffer, ConvertToBytes(DTf)); 389 | var positions60FPSd = FindSequence(ref buffer, ConvertToBytes(FPSd)); 390 | var positions60DTd = FindSequence(ref buffer, ConvertToBytes(DTd)); 391 | FPSi = (char)30; 392 | FPSf = 30.0f; 393 | DTf = 1.0f / FPSf; 394 | FPSd = 30.0; 395 | DTd = 1.0 / FPSd; 396 | var positions30FPSi = FindSequence(ref buffer, ConvertToBytes(FPSi)); 397 | var positions30FPSf = FindSequence(ref buffer, ConvertToBytes(FPSf)); 398 | var positions30DTf = FindSequence(ref buffer, ConvertToBytes(DTf)); 399 | var positions30FPSd = FindSequence(ref buffer, ConvertToBytes(FPSd)); 400 | var positions30DTd = FindSequence(ref buffer, ConvertToBytes(DTd)); 401 | 402 | List> FPSi_list = new List>(); 403 | FPSi_list.Add(positions120FPSi); 404 | FPSi_list.Add(positions60FPSi); 405 | FPSi_list.Add(positions30FPSi); 406 | List> FPSf_list = new List>(); 407 | FPSf_list.Add(positions120FPSf); 408 | FPSf_list.Add(positions60FPSf); 409 | FPSf_list.Add(positions30FPSf); 410 | List> DTf_list = new List>(); 411 | DTf_list.Add(positions120DTf); 412 | DTf_list.Add(positions60DTf); 413 | DTf_list.Add(positions30DTf); 414 | List> FPSd_list = new List>(); 415 | FPSd_list.Add(positions120FPSd); 416 | FPSd_list.Add(positions60FPSd); 417 | FPSd_list.Add(positions30FPSd); 418 | List> DTd_list = new List>(); 419 | DTd_list.Add(positions120DTd); 420 | DTd_list.Add(positions60DTd); 421 | DTd_list.Add(positions30DTd); 422 | var FPSi_results = FindClosePositions(ref FPSi_list, 64); 423 | var FPSf_results = FindClosePositions(ref FPSf_list, 1024); 424 | var DTf_results = FindClosePositions(ref DTf_list, 1024); 425 | var FPSd_results = FindClosePositions(ref FPSd_list, 1024); 426 | var DTd_results = FindClosePositions(ref DTd_list, 1024); 427 | 428 | Patch(ref buffer, FPSi_results[0], ConvertToBytes(targetFPSi)); 429 | Patch(ref buffer, FPSf_results[0], ConvertToBytes(targetFPSf)); 430 | Patch(ref buffer, DTf_results[0], ConvertToBytes(targetDTf)); 431 | Patch(ref buffer, FPSd_results[0], ConvertToBytes(targetFPSd)); 432 | Patch(ref buffer, DTd_results[0], ConvertToBytes(targetDTd)); 433 | 434 | return true; 435 | } 436 | 437 | private static bool PatchResolution(ref byte[] buffer, int width, int height) 438 | { 439 | // Experimenting with resolutions to replace. 440 | // Some of them are hardcoded in the exe more than once, as maybe they represent the resolution of 441 | // other textures or effects, so better leave them alone. 442 | // The values we are looking to change are next to each other, and the first one 443 | // is the window resolution, the second is the internal resolution. 444 | var patternResolution720p = ConvertToBytes(1280).Concat(ConvertToBytes(720)).ToArray(); // Found 3 (index 0 and 1 are the good ones) 445 | var patternResolution1080p = ConvertToBytes(1920).Concat(ConvertToBytes(1080)).ToArray(); // Found 4 (index 1 and 2 are the good ones) 446 | var patternResolution1080pUltrawide = ConvertToBytes(2560).Concat(ConvertToBytes(1080)).ToArray(); // Found 2 447 | var patternResolution1440p = ConvertToBytes(2560).Concat(ConvertToBytes(1440)).ToArray(); // Found 2 448 | var patternResolution1440pUltrawide = ConvertToBytes(3440).Concat(ConvertToBytes(1440)).ToArray(); // Found 2 449 | var patternResolution2160p = ConvertToBytes(3840).Concat(ConvertToBytes(2160)).ToArray(); // Found 2 450 | 451 | var patternResolution = ConvertToBytes(RES_TO_REPLACE_W).Concat(ConvertToBytes(RES_TO_REPLACE_H)).ToArray(); 452 | var positions = FindSequence(ref buffer, patternResolution); 453 | patternResolution = ConvertToBytes(RES_TO_REPLACE_W).Concat(ConvertToBytes(RES_TO_REPLACE_H)).ToArray(); 454 | positions = FindSequence(ref buffer, patternResolution); 455 | 456 | bool replacing_1280x720 = RES_TO_REPLACE_W == 1280 && RES_TO_REPLACE_H == 720; 457 | bool replacing_1920x1080 = RES_TO_REPLACE_W == 1920 && RES_TO_REPLACE_H == 1080; 458 | 459 | var resolution = ConvertToBytes(width).Concat(ConvertToBytes(height)).ToArray(); 460 | 461 | int i1 = 0; 462 | int i2 = 1; 463 | int expected_results = 2; 464 | 465 | if (replacing_1280x720) 466 | { 467 | i1 = 0; 468 | i2 = 1; 469 | expected_results = 3; 470 | } 471 | else if (replacing_1920x1080) 472 | { 473 | i1 = 1; 474 | i2 = 2; 475 | expected_results = 4; 476 | } 477 | 478 | if (!AssertEquals("patternResolution", expected_results, positions.Count)) 479 | { 480 | return false; 481 | } 482 | 483 | var windowResolution = resolution; 484 | var internalResolution = windowResolution; 485 | 486 | // Window resolution 487 | Patch(ref buffer, positions[i1], windowResolution); 488 | // Internal resolution (don't scale it by any value as it can already been scaled from the game settings, and it seems to work even after overwriting resolutions) 489 | Patch(ref buffer, positions[i2], internalResolution); 490 | 491 | /* Patch resolution text (doesn't work, text is likely is an asset, at least english) 492 | string resolutionText = $"{RES_TO_REPLACE_W} x {RES_TO_REPLACE_H}"; 493 | string customResolutionText = $"{width} x {height}"; 494 | bool ultrawide = (RES_TO_REPLACE_W / (float)RES_TO_REPLACE_H) > 1.78; // 16/9 with tolerance 495 | if (ultrawide) 496 | { 497 | resolutionText += " (Ultrawide)"; 498 | customResolutionText += " (Patch res)"; // Needs to be of the same length of course 499 | } 500 | var patternResolutionText = ConvertToBytes(resolutionText); 501 | var patchResolutionText = ConvertToBytes(customResolutionText); 502 | var positions_text = FindSequence(ref buffer, patternResolutionText); 503 | Patch(ref buffer, positions_text, patchResolutionText); 504 | 505 | patternResolutionText = ConvertToBytes("1440"); 506 | patchResolutionText = ConvertToBytes($"{height}"); 507 | positions_text = FindSequence(ref buffer, patternResolutionText); 508 | Patch(ref buffer, positions_text, patchResolutionText);*/ 509 | 510 | return true; 511 | } 512 | 513 | private static void Exit() 514 | { 515 | Console.WriteLine("\nPress any key to exit..."); 516 | 517 | Console.ReadKey(); 518 | } 519 | 520 | private static int ReadInt(string name, int defaultValue) 521 | { 522 | int input; 523 | 524 | do 525 | { 526 | Console.Write($"-> {name} [default = {defaultValue}]: "); 527 | 528 | string inputString = Console.ReadLine(); 529 | 530 | if (string.IsNullOrWhiteSpace(inputString)) 531 | { 532 | return defaultValue; 533 | } 534 | 535 | int.TryParse(inputString, out input); 536 | 537 | if (input <= 0) 538 | { 539 | Console.WriteLine("--> Invalid value, try again!"); 540 | } 541 | } while (input <= 0); 542 | 543 | return input; 544 | } 545 | 546 | private static float ReadFloat(string name, float defaultValue) 547 | { 548 | float input; 549 | 550 | do 551 | { 552 | Console.Write($"-> {name} [default = {defaultValue:F1}]: "); 553 | 554 | string inputString = Console.ReadLine(); 555 | 556 | if (string.IsNullOrWhiteSpace(inputString)) 557 | { 558 | return defaultValue; 559 | } 560 | 561 | float.TryParse(inputString, out input); 562 | 563 | if (input <= 0) 564 | { 565 | Console.WriteLine("--> Invalid value, try again!"); 566 | } 567 | } while (input <= 0); 568 | 569 | return input; 570 | } 571 | 572 | private static bool ReadBool(string name, bool defaultValue) 573 | { 574 | while (true) 575 | { 576 | Console.Write($"-> {name} [default = {(defaultValue ? "Yes" : "No")}]: "); 577 | 578 | string inputString = Console.ReadLine(); 579 | 580 | if (string.IsNullOrWhiteSpace(inputString)) 581 | { 582 | return defaultValue; 583 | } 584 | 585 | if (inputString.StartsWith("Y", true, CultureInfo.CurrentCulture)) 586 | { 587 | return true; 588 | } 589 | 590 | if (inputString.StartsWith("N", true, CultureInfo.CurrentCulture)) 591 | { 592 | return false; 593 | } 594 | 595 | Console.WriteLine("--> Invalid value, try again!"); 596 | } 597 | } 598 | 599 | private static byte[] ConvertToBytes(char value) 600 | { 601 | byte[] bytes = BitConverter.GetBytes(value); 602 | 603 | if (!BitConverter.IsLittleEndian) 604 | { 605 | Array.Reverse(bytes); 606 | } 607 | 608 | return bytes; 609 | } 610 | 611 | private static byte[] ConvertToBytes(short value) 612 | { 613 | byte[] bytes = BitConverter.GetBytes(value); 614 | 615 | if (!BitConverter.IsLittleEndian) 616 | { 617 | Array.Reverse(bytes); 618 | } 619 | 620 | return bytes; 621 | } 622 | 623 | private static byte[] ConvertToBytes(Int32 value) 624 | { 625 | byte[] bytes = BitConverter.GetBytes(value); 626 | 627 | if (!BitConverter.IsLittleEndian) 628 | { 629 | Array.Reverse(bytes); 630 | } 631 | 632 | return bytes; 633 | } 634 | 635 | private static byte[] ConvertToBytes(float value) 636 | { 637 | byte[] bytes = BitConverter.GetBytes(value); 638 | 639 | if (!BitConverter.IsLittleEndian) 640 | { 641 | Array.Reverse(bytes); 642 | } 643 | 644 | return bytes; 645 | } 646 | 647 | private static byte[] ConvertToBytes(double value) 648 | { 649 | byte[] bytes = BitConverter.GetBytes(value); 650 | 651 | if (!BitConverter.IsLittleEndian) 652 | { 653 | Array.Reverse(bytes); 654 | } 655 | 656 | return bytes; 657 | } 658 | 659 | private static byte[] ConvertToBytes(string value) 660 | { 661 | // Unicode specifically for Nioh 2 (not UTF8 nor ASCII) 662 | byte[] bytes = System.Text.Encoding.Unicode.GetBytes(value); 663 | return bytes; 664 | } 665 | 666 | private static byte[] StringToPattern(string pattern) 667 | { 668 | return pattern 669 | .Split(' ') 670 | .Select(x => Convert.ToByte(x, 16)) 671 | .ToArray(); 672 | } 673 | 674 | private static List> FindClosePositions(ref List> positions_lists, uint tolerance) 675 | { 676 | List> out_list = new List>(); 677 | foreach (List positions in positions_lists) 678 | { 679 | out_list.Add(new List()); 680 | } 681 | 682 | // Limited to 3 lists... 683 | int i1 = 0; 684 | foreach (List positions1 in positions_lists) 685 | { 686 | foreach (int position1 in positions1) 687 | { 688 | int i2 = 0; 689 | foreach (List positions2 in positions_lists) 690 | { 691 | if (i1 != i2) 692 | { 693 | foreach (int position2 in positions2) 694 | { 695 | if (Math.Abs(position1 - position2) > 0 696 | && Math.Abs(position1 - position2) <= tolerance) 697 | { 698 | int i3 = 0; 699 | foreach (List positions3 in positions_lists) 700 | { 701 | if (i1 != i3 && i2 != i3) 702 | { 703 | foreach (int position3 in positions3) 704 | { 705 | if ((Math.Abs(position1 - position3) > 0 706 | && Math.Abs(position1 - position3) <= tolerance) 707 | || (Math.Abs(position2 - position3) > 0 708 | && Math.Abs(position2 - position3) <= tolerance)) 709 | { 710 | if (!out_list[i1].Contains(position1)) 711 | out_list[i1].Add(position1); 712 | if (!out_list[i2].Contains(position2)) 713 | out_list[i2].Add(position2); 714 | if (!out_list[i3].Contains(position3)) 715 | out_list[i3].Add(position3); 716 | } 717 | } 718 | } 719 | ++i3; 720 | } 721 | } 722 | } 723 | } 724 | ++i2; 725 | } 726 | } 727 | ++i1; 728 | } 729 | // Actually, keep all the lists in so we know the original order/index 730 | //while (out_list.Count > 0 && out_list.First().Count == 0) 731 | // out_list.RemoveAt(0); 732 | //while (out_list.Count > 0 && out_list.Last().Count == 0) 733 | // out_list.RemoveAt(out_list.Count - 1); 734 | return out_list; 735 | } 736 | 737 | //Source: https://stackoverflow.com/questions/283456/byte-array-pattern-search 738 | private static List FindSequence(ref byte[] buffer, byte[] pattern, int startIndex = 0) 739 | { 740 | List positions = new List(); 741 | 742 | int i = Array.IndexOf(buffer, pattern[0], startIndex); 743 | 744 | while (i >= 0 && i <= buffer.Length - pattern.Length) 745 | { 746 | byte[] segment = new byte[pattern.Length]; 747 | 748 | Buffer.BlockCopy(buffer, i, segment, 0, pattern.Length); 749 | 750 | if (segment.SequenceEqual(pattern)) 751 | { 752 | positions.Add(i); 753 | 754 | i = Array.IndexOf(buffer, pattern[0], i + pattern.Length); 755 | } 756 | else 757 | { 758 | i = Array.IndexOf(buffer, pattern[0], i + 1); 759 | } 760 | } 761 | 762 | return positions; 763 | } 764 | 765 | private static bool CompareSequence(ref byte[] buffer, byte[] pattern, int startIndex) 766 | { 767 | if (startIndex > buffer.Length - pattern.Length) 768 | { 769 | return false; 770 | } 771 | 772 | byte[] segment = new byte[pattern.Length]; 773 | Buffer.BlockCopy(buffer, startIndex, segment, 0, pattern.Length); 774 | 775 | return segment.SequenceEqual(pattern); 776 | } 777 | 778 | private static bool AssertEquals(string name, T expected, T value) 779 | { 780 | if (!value.Equals(expected)) 781 | { 782 | Console.WriteLine($"-> {name} expected {expected}, but got {value}!"); 783 | 784 | return false; 785 | } 786 | 787 | return true; 788 | } 789 | 790 | private static void Patch(ref byte[] buffer, List positions, byte[] patchBytes) 791 | { 792 | foreach (int position in positions) 793 | { 794 | Patch(ref buffer, position, patchBytes); 795 | } 796 | } 797 | 798 | private static void Patch(ref byte[] buffer, List positions, int i_min, int i_max, byte[] patchBytes) 799 | { 800 | int i = 0; 801 | foreach (int position in positions) 802 | { 803 | if (i >= i_min && i <= i_max) 804 | Patch(ref buffer, position, patchBytes); 805 | ++i; 806 | } 807 | } 808 | 809 | private static void Patch(ref byte[] buffer, int position, byte[] patchBytes) 810 | { 811 | Console.WriteLine($"-> Patching offset {position}"); 812 | 813 | for (int i = 0; i < patchBytes.Length; i++) 814 | { 815 | buffer[position + i] = patchBytes[i]; 816 | } 817 | } 818 | } 819 | } 820 | --------------------------------------------------------------------------------