Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
LennardF1989 committed Nov 14, 2017
0 parents commit a301faa
Show file tree
Hide file tree
Showing 10 changed files with 380 additions and 0 deletions.
4 changes: 4 additions & 0 deletions .gitignore
@@ -0,0 +1,4 @@
bin
obj
*.suo
*.user
3 changes: 3 additions & 0 deletions .gitmodules
@@ -0,0 +1,3 @@
[submodule "Lib/Steamless"]
path = Lib/Steamless
url = https://github.com/atom0s/Steamless.git
1 change: 1 addition & 0 deletions Lib/Steamless
Submodule Steamless added at 18d34e
55 changes: 55 additions & 0 deletions NiohResolution.sln
@@ -0,0 +1,55 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14
VisualStudioVersion = 14.0.25420.1
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NiohResolution", "Src\NiohResolution\NiohResolution.csproj", "{369EAAEB-080A-4C1C-AC0F-37581CD98BFD}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Libraries", "Libraries", "{1FA8987A-75B3-46FE-9AE2-093FB6E1257C}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Steamless.API", "Lib\Steamless\Steamless.API\Steamless.API.csproj", "{56C95629-3B34-47FE-B988-04274409294F}"
EndProject
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}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Documentation", "Documentation", "{2E9E0824-3394-48A4-A078-8D59CB77DA15}"
ProjectSection(SolutionItems) = preProject
README.md = README.md
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Debug|x86 = Debug|x86
Release|Any CPU = Release|Any CPU
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{369EAAEB-080A-4C1C-AC0F-37581CD98BFD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{369EAAEB-080A-4C1C-AC0F-37581CD98BFD}.Debug|Any CPU.Build.0 = Debug|Any CPU
{369EAAEB-080A-4C1C-AC0F-37581CD98BFD}.Debug|x86.ActiveCfg = Debug|Any CPU
{369EAAEB-080A-4C1C-AC0F-37581CD98BFD}.Debug|x86.Build.0 = Debug|Any CPU
{369EAAEB-080A-4C1C-AC0F-37581CD98BFD}.Release|Any CPU.ActiveCfg = Release|Any CPU
{369EAAEB-080A-4C1C-AC0F-37581CD98BFD}.Release|Any CPU.Build.0 = Release|Any CPU
{369EAAEB-080A-4C1C-AC0F-37581CD98BFD}.Release|x86.ActiveCfg = Release|Any CPU
{369EAAEB-080A-4C1C-AC0F-37581CD98BFD}.Release|x86.Build.0 = Release|Any CPU
{56C95629-3B34-47FE-B988-04274409294F}.Debug|Any CPU.ActiveCfg = Debug|x86
{56C95629-3B34-47FE-B988-04274409294F}.Debug|x86.ActiveCfg = Debug|x86
{56C95629-3B34-47FE-B988-04274409294F}.Debug|x86.Build.0 = Debug|x86
{56C95629-3B34-47FE-B988-04274409294F}.Release|Any CPU.ActiveCfg = Release|x86
{56C95629-3B34-47FE-B988-04274409294F}.Release|x86.ActiveCfg = Release|x86
{56C95629-3B34-47FE-B988-04274409294F}.Release|x86.Build.0 = Release|x86
{05F540FB-D14B-4966-8DE2-591B76361CF0}.Debug|Any CPU.ActiveCfg = Debug|x86
{05F540FB-D14B-4966-8DE2-591B76361CF0}.Debug|x86.ActiveCfg = Debug|x86
{05F540FB-D14B-4966-8DE2-591B76361CF0}.Debug|x86.Build.0 = Debug|x86
{05F540FB-D14B-4966-8DE2-591B76361CF0}.Release|Any CPU.ActiveCfg = Release|x86
{05F540FB-D14B-4966-8DE2-591B76361CF0}.Release|x86.ActiveCfg = Release|x86
{05F540FB-D14B-4966-8DE2-591B76361CF0}.Release|x86.Build.0 = Release|x86
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{56C95629-3B34-47FE-B988-04274409294F} = {1FA8987A-75B3-46FE-9AE2-093FB6E1257C}
{05F540FB-D14B-4966-8DE2-591B76361CF0} = {1FA8987A-75B3-46FE-9AE2-093FB6E1257C}
EndGlobalSection
EndGlobal
19 changes: 19 additions & 0 deletions README.md
@@ -0,0 +1,19 @@
# NiohResolution

NiohResolution adds support for any resolution to *Nioh: Complete Edition* on PC.

## How to use?

1) Download the latest release of NiohResolution.
2) Extract the ZIP to the root of the *Nioh: Complete Edition* game-directory. By default this would be `C:\Program Files\Steam\steamapps\common\Nioh`.
3) Run `NiohResolution.exe` and follow the instructions.
4) Start the launcher and set your resolution to 1920x1080.
5) Start the game and enjoy!

## How does it work?

Before doing anything, the game will be unpacked using [Steamless](https://github.com/atom0s/Steamless). This is required because the Steam DRM will otherwise not allow a modified executable.

Once unpacked, the patcher will look for the byte representation of the 1920x1080 resolution, and change all occurances to your desired resolution.

In theory, this patcher should work for any version of the game.
6 changes: 6 additions & 0 deletions Src/NiohResolution/App.config
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2"/>
</startup>
</configuration>
71 changes: 71 additions & 0 deletions Src/NiohResolution/NiohResolution.csproj
@@ -0,0 +1,71 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{369EAAEB-080A-4C1C-AC0F-37581CD98BFD}</ProjectGuid>
<OutputType>Exe</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>NiohResolution</RootNamespace>
<AssemblyName>NiohResolution</AssemblyName>
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>..\..\Bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>x86</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>..\..\Bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup>
<ApplicationIcon>icon.ico</ApplicationIcon>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
</ItemGroup>
<ItemGroup>
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\Lib\Steamless\Steamless.API\Steamless.API.csproj">
<Project>{56c95629-3b34-47fe-b988-04274409294f}</Project>
<Name>Steamless.API</Name>
</ProjectReference>
<ProjectReference Include="..\..\Lib\Steamless\Steamless.Unpacker.Variant31.x64\Steamless.Unpacker.Variant31.x64.csproj">
<Project>{05f540fb-d14b-4966-8de2-591b76361cf0}</Project>
<Name>Steamless.Unpacker.Variant31.x64</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<Content Include="icon.ico" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>
186 changes: 186 additions & 0 deletions Src/NiohResolution/Program.cs
@@ -0,0 +1,186 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Steamless.API.Model;
using Steamless.API.Services;
using Steamless.Unpacker.Variant31.x64;

namespace NiohResolution
{
public class Program
{
private const string EXE_FILE = "nioh.exe";
private const string EXE_FILE_BACKUP = "nioh.exe.bak";
private const string EXE_FILE_UNPACKED = "nioh.exe.unpacked.exe";

private static readonly byte[] _exePattern = { 0x80, 0x07, 0x00, 0x00, 0x38, 0x04, 0x00, 0x00 };

public static void Main(string[] args)
{
Console.WriteLine("Welcome to the Nioh Resolution patcher!");

Console.WriteLine("\nPlease specify your resolution.");

int width = ReadInt("Width");
int height = ReadInt("Height");

if (!File.Exists(EXE_FILE))
{
Console.WriteLine($"\nCould not find {EXE_FILE}!");

Exit();

return;
}

Console.WriteLine($"\nBacking up {EXE_FILE}...");

File.Copy(EXE_FILE, EXE_FILE_BACKUP, true);

Console.WriteLine($"Unpacking {EXE_FILE}...");

var result = UnpackExe();
if (!result)
{
return;
}

Console.WriteLine($"Patching resolution of {width}x{height}...");

var buffer = File.ReadAllBytes(EXE_FILE_UNPACKED);
var positions = FindSequence(buffer, _exePattern, 0);
var resolution = ConvertToBytes(width, height);

if (!positions.Any())
{
Console.WriteLine($"Could not find any offsets in {EXE_FILE_UNPACKED}!");

Exit();

return;
}

foreach (int position in positions)
{
Console.WriteLine($"Patching offset {position}...");

for (int i = 0; i < resolution.Length; i++)
{
buffer[position + i] = resolution[i];
}
}

Console.WriteLine("Cleaning up...");

File.WriteAllBytes(EXE_FILE, buffer);
File.Delete(EXE_FILE_UNPACKED);

Console.WriteLine("\nDone! Don't forget to set the resolution of the game to 1920x1080!");

Exit();
}

private static bool UnpackExe()
{
LoggingService loggingService = new LoggingService();
loggingService.AddLogMessage += (sender, eventArgs) =>
{
Console.WriteLine(eventArgs.Message);
};

SteamlessPlugin plugin = new Main();
plugin.Initialize(loggingService);

var result = plugin.CanProcessFile(EXE_FILE);

if (!result)
{
Console.WriteLine($"Cannot process {EXE_FILE}!");

Exit();

return false;
}

result = plugin.ProcessFile(EXE_FILE, new SteamlessOptions
{
VerboseOutput = false,
KeepBindSection = true
});

if (!result)
{
Console.WriteLine($"Could not process {EXE_FILE}!");

Exit();

return false;
}

return true;
}

private static int ReadInt(string name)
{
int input;

do
{
Console.Write($"{name}: ");

int.TryParse(Console.ReadLine(), out input);

if (input <= 0)
{
Console.WriteLine($"That's not a valid {name.ToLower()}, try again!");
}
} while (input <= 0);

return input;
}

private static byte[] ConvertToBytes(int width, int height)
{
byte[] widthBytes = BitConverter.GetBytes(width);
byte[] heightBytes = BitConverter.GetBytes(height);

if (!BitConverter.IsLittleEndian)
{
Array.Reverse(widthBytes);
Array.Reverse(heightBytes);
}

return widthBytes.Concat(heightBytes).ToArray();
}

//Source: https://stackoverflow.com/questions/283456/byte-array-pattern-search
private static List<int> FindSequence(byte[] buffer, byte[] pattern, int startIndex)
{
List<int> positions = new List<int>();

int i = Array.IndexOf(buffer, pattern[0], startIndex);

while (i >= 0 && i <= buffer.Length - pattern.Length)
{
byte[] segment = new byte[pattern.Length];

Buffer.BlockCopy(buffer, i, segment, 0, pattern.Length);

if (segment.SequenceEqual(pattern))
{
positions.Add(i);
}

i = Array.IndexOf(buffer, pattern[0], i + pattern.Length);
}

return positions;
}

private static void Exit()
{
Console.ReadKey();
}
}
}
35 changes: 35 additions & 0 deletions Src/NiohResolution/Properties/AssemblyInfo.cs
@@ -0,0 +1,35 @@
using System.Reflection;
using System.Runtime.InteropServices;

// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("NiohResolution")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("NiohResolution")]
[assembly: AssemblyCopyright("Copyright © Lennard Fonteijn 2017")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]

// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]

// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("369eaaeb-080a-4c1c-ac0f-37581cd98bfd")]

// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
Binary file added Src/NiohResolution/icon.ico
Binary file not shown.

0 comments on commit a301faa

Please sign in to comment.