├── .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 |
--------------------------------------------------------------------------------