diff --git a/dark-skin.sln b/dark-skin.sln
index df76373..8c703d7 100644
--- a/dark-skin.sln
+++ b/dark-skin.sln
@@ -1,25 +1,37 @@
Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio 15
-VisualStudioVersion = 15.0.28010.2003
-MinimumVisualStudioVersion = 10.0.40219.1
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.29201.188
+MinimumVisualStudioVersion = 15.0.26124.0
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "dark-skin", "dark-skin\dark-skin.csproj", "{7C0252E3-4D08-445B-9D3C-1DD49620BBF4}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
+ Debug|x64 = Debug|x64
+ Debug|x86 = Debug|x86
Release|Any CPU = Release|Any CPU
+ Release|x64 = Release|x64
+ Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{7C0252E3-4D08-445B-9D3C-1DD49620BBF4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7C0252E3-4D08-445B-9D3C-1DD49620BBF4}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {7C0252E3-4D08-445B-9D3C-1DD49620BBF4}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {7C0252E3-4D08-445B-9D3C-1DD49620BBF4}.Debug|x64.Build.0 = Debug|Any CPU
+ {7C0252E3-4D08-445B-9D3C-1DD49620BBF4}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {7C0252E3-4D08-445B-9D3C-1DD49620BBF4}.Debug|x86.Build.0 = Debug|Any CPU
{7C0252E3-4D08-445B-9D3C-1DD49620BBF4}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7C0252E3-4D08-445B-9D3C-1DD49620BBF4}.Release|Any CPU.Build.0 = Release|Any CPU
+ {7C0252E3-4D08-445B-9D3C-1DD49620BBF4}.Release|x64.ActiveCfg = Release|Any CPU
+ {7C0252E3-4D08-445B-9D3C-1DD49620BBF4}.Release|x64.Build.0 = Release|Any CPU
+ {7C0252E3-4D08-445B-9D3C-1DD49620BBF4}.Release|x86.ActiveCfg = Release|Any CPU
+ {7C0252E3-4D08-445B-9D3C-1DD49620BBF4}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
- SolutionGuid = {A491635B-D3B4-4E23-890A-91DAFB42D199}
+ SolutionGuid = {EF525544-E552-4928-9F1B-9848C7A4DCE5}
EndGlobalSection
EndGlobal
diff --git a/dark-skin/CVDump.cs b/dark-skin/CVDump.cs
index 75a127a..fe60455 100644
--- a/dark-skin/CVDump.cs
+++ b/dark-skin/CVDump.cs
@@ -16,12 +16,12 @@ public class CVDump : IDisposable {
public void Execute(string exePath, DataReceivedEventHandler outputCallback, DataReceivedEventHandler errorCallback, string arguments = "-headers -p") {
var startOptions = new ProcessStartInfo {
- FileName = cvDumpExe,
- Arguments = string.Format("{0} {1}", arguments, exePath),
- UseShellExecute = false,
- CreateNoWindow = true,
- RedirectStandardOutput = true,
- RedirectStandardError = true
+ FileName = cvDumpExe,
+ Arguments = string.Format("{0} {1}", arguments, exePath),
+ UseShellExecute = false,
+ CreateNoWindow = true,
+ RedirectStandardOutput = true,
+ RedirectStandardError = true
};
var process = Process.Start(startOptions);
diff --git a/dark-skin/FodyWeavers.xml b/dark-skin/FodyWeavers.xml
new file mode 100644
index 0000000..49b26bf
--- /dev/null
+++ b/dark-skin/FodyWeavers.xml
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/dark-skin/FodyWeavers.xsd b/dark-skin/FodyWeavers.xsd
new file mode 100644
index 0000000..44a5374
--- /dev/null
+++ b/dark-skin/FodyWeavers.xsd
@@ -0,0 +1,111 @@
+
+
+
+
+
+
+
+
+
+
+
+ A list of assembly names to exclude from the default action of "embed all Copy Local references", delimited with line breaks
+
+
+
+
+ A list of assembly names to include from the default action of "embed all Copy Local references", delimited with line breaks.
+
+
+
+
+ A list of unmanaged 32 bit assembly names to include, delimited with line breaks.
+
+
+
+
+ A list of unmanaged 64 bit assembly names to include, delimited with line breaks.
+
+
+
+
+ The order of preloaded assemblies, delimited with line breaks.
+
+
+
+
+
+ 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.
+
+
+
+
+ Controls if .pdbs for reference assemblies are also embedded.
+
+
+
+
+ Embedded assemblies are compressed by default, and uncompressed when they are loaded. You can turn compression off with this option.
+
+
+
+
+ As part of Costura, embedded assemblies are no longer included as part of the build. This cleanup can be turned off.
+
+
+
+
+ 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.
+
+
+
+
+ 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.
+
+
+
+
+ A list of assembly names to exclude from the default action of "embed all Copy Local references", delimited with |
+
+
+
+
+ A list of assembly names to include from the default action of "embed all Copy Local references", delimited with |.
+
+
+
+
+ A list of unmanaged 32 bit assembly names to include, delimited with |.
+
+
+
+
+ A list of unmanaged 64 bit assembly names to include, delimited with |.
+
+
+
+
+ The order of preloaded assemblies, delimited with |.
+
+
+
+
+
+
+
+ 'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.
+
+
+
+
+ A comma-separated list of error codes that can be safely ignored in assembly verification.
+
+
+
+
+ 'false' to turn off automatic generation of the XML Schema file.
+
+
+
+
+
\ No newline at end of file
diff --git a/dark-skin/Options.cs b/dark-skin/Options.cs
new file mode 100644
index 0000000..a5f895a
--- /dev/null
+++ b/dark-skin/Options.cs
@@ -0,0 +1,22 @@
+using CommandLine;
+
+namespace DarkSkin {
+
+ [Verb("enable", HelpText = "Unlock the dark skin.")]
+ class EnableOptions : BaseOption { }
+
+ [Verb("disable", HelpText = "Revert the skin to the original.")]
+ class DisableOptions : BaseOption { }
+
+ [Verb("findhex", HelpText = "Find and list the addresses and hexes of the GetSkinIdx methods")]
+ class FindHexOptions : BaseOption { }
+
+ class BaseOption {
+ [Value(0, MetaName = "unityExe", Default = ".")]
+ public string InputFile { get; set; }
+
+ [Option('f', "fast-enumerator", Default = false, HelpText = "Use fast file enumeration to search for executables, otherwise use recursive enumeration.")]
+ public bool FastEnumerator { get; set; }
+ }
+
+}
\ No newline at end of file
diff --git a/dark-skin/Program.cs b/dark-skin/Program.cs
index 7f4c630..62b462a 100644
--- a/dark-skin/Program.cs
+++ b/dark-skin/Program.cs
@@ -1,17 +1,14 @@
using System;
using System.Collections.Generic;
-using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using CodeProject;
+using CommandLine;
namespace DarkSkin {
public static class Program {
- private static bool m_toEnable = true;
- private static bool m_useFastFileEnumerator = false;
-
public static ParallelQuery Tap(this ParallelQuery source, Action action) {
return source.Select(item => {
action(item);
@@ -26,120 +23,130 @@ public static class Program {
});
}
- private static void FindHex(string unity) {
-
- using(var cvDump = new CVDump()) {
- var regex = new Regex(@"^.+:\s*\[(?[0-9a-fA-F]{4}):(?[0-9a-fA-F]{8})\].*GetSkinIdx.*$");
-
- cvDump.Execute(unity,
- (args, e) => { // Stdout
- if (string.IsNullOrWhiteSpace(e.Data))
- return;
-
- var match = regex.Match(e.Data);
-
- if (match.Success) {
- var section = match.Groups["section"];
- var addr = long.Parse(match.Groups["addr"].ToString(), System.Globalization.NumberStyles.HexNumber);
-
- addr += 0x400; // Section offset
-
- Console.WriteLine(e.Data);
+ private static void FindHex(string unityPath, bool useFastFileEnumerator) {
- using(new TempConsoleColor(ConsoleColor.DarkGreen))
- Console.WriteLine("Found GetSkinIdx at section {0} and address {1:X8}", section, addr);
+ if (useFastFileEnumerator)
+ using(new TempConsoleColor(ConsoleColor.DarkYellow))
+ Console.WriteLine("Using fast file enumeration");
- try {
- using(var file = File.OpenRead(unity)) {
- var buffer = new byte[0x80]; // 45 is a random number that might be enought
-
- file.Seek(addr, SeekOrigin.Begin);
- file.Read(buffer, 0, buffer.Length);
+ using(var cvDump = new CVDump()) {
+ var obj = new object();
- var formattedBytes = UnitySkin.FormatBytes(buffer);
- Console.WriteLine("x64 Routine:");
- Console.WriteLine(formattedBytes);
- }
- } catch (Exception ex) {
- Console.Error.WriteLine("Failed to open Unity executable");
- Console.Error.WriteLine(ex);
- }
- }
- }, (args, e) => { // Stderr
- Console.Error.WriteLine(e.Data);
+ GetUnityInstallations(Path.GetFullPath(unityPath), useFastFileEnumerator)
+ .AsParallel()
+ .Where(exe => File.Exists(exe))
+ .ForAll(unity => {
+ cvDump.Execute(unity,
+ (args, e) => { // Stdout
+ if (string.IsNullOrWhiteSpace(e.Data))
+ return;
+
+ var regex = new Regex(@"^.+:\s*\[(?[0-9a-fA-F]{4}):(?[0-9a-fA-F]{8})\].*GetSkinIdx.*$");
+ var match = regex.Match(e.Data);
+
+ if (match.Success)
+ lock(obj) {
+ var section = match.Groups["section"];
+ var addr = long.Parse(match.Groups["addr"].ToString(), System.Globalization.NumberStyles.HexNumber);
+
+ addr += 0x400; // Section offset
+
+ Console.WriteLine(e.Data);
+
+ using(new TempConsoleColor(ConsoleColor.DarkGreen))
+ Console.WriteLine("Found GetSkinIdx at section {0} and address {1:X8}", section, addr);
+
+ try {
+ using(var file = File.OpenRead(unity)) {
+ var buffer = new byte[0x80]; // This should be enough to reach the "ret" op
+
+ file.Seek(addr, SeekOrigin.Begin);
+ file.Read(buffer, 0, buffer.Length);
+
+ var formattedBytes = UnitySkin.FormatBytes(buffer);
+ Console.WriteLine("x64 Routine:");
+ Console.WriteLine(formattedBytes);
+ }
+ } catch (Exception ex) {
+ Console.Error.WriteLine("Failed to open Unity executable");
+ Console.Error.WriteLine(ex);
+ }
+ }
+ }, (args, e) => { // Stderr
+ using(new TempConsoleColor(ConsoleColor.DarkRed))
+ Console.Error.WriteLine(e.Data);
+ });
});
-
}
}
- private static void Main(params string[] args) {
-
- var findHex = args.Contains("findHex");
- var unityArg = findHex ? args[Array.IndexOf(args, "findHex") + 1] : "";
-
- if (findHex) {
- FindHex(unityArg);
- return;
- }
+ private static void Run(bool toEnable, string unityPath, bool useFastFileEnumerator) {
+ Console.WriteLine("Fetching unity installations...");
+
+ if (useFastFileEnumerator)
+ using(new TempConsoleColor(ConsoleColor.DarkYellow))
+ Console.WriteLine("Using fast file enumeration");
+
+ GetUnityInstallations(Path.GetFullPath(unityPath), useFastFileEnumerator)
+ .AsParallel()
+ .Where(exe => File.Exists(exe))
+ .Select(exe => new UnitySkin(exe))
+ .Where(unity => unity.OffsetOfSkinFlags != -1 && unity.SkinIndex != -1)
+ .Where(unity => {
+ var shouldChange = (toEnable && unity.IsWhiteSkin) || (!toEnable && unity.IsDarkSkin);
+ if (!shouldChange)
+ unity.Log("Skin already applied, ignoring");
+ return shouldChange;
+ })
+ .ForAll(unity => unity.SetDarkSkinEnable(toEnable));
+ }
- var toEnable = args.Contains("enable");
- var toDisable = args.Contains("disable");
- var help = args.Contains("-h") || args.Contains("--help");
-
- if (toEnable == toDisable || help) {
- if (!help)
- Console.Error.WriteLine("Invalid parameters");
- Console.WriteLine("Usage:");
- Console.WriteLine(" dark-skin.exe enable | disable [options]");
- Console.WriteLine("");
- Console.WriteLine(" findHex unityExe Find the address of the GetSkinIdx method for a particular Unity version");
- Console.WriteLine("-h, --help Show this screen");
- Console.WriteLine("-f, --fast-enumerator Use fast file enumeration, otherwise use recursive enumeration");
- return;
+ private static void HandleException(Exception ex) {
+ using(new TempConsoleColor(ConsoleColor.DarkRed)) {
+ Console.Error.WriteLine("\nError");
+ Console.Error.WriteLine(ex);
}
+ }
- m_toEnable = toEnable;
- m_useFastFileEnumerator = args.Contains("-f") || args.Contains("--fast-enumerator");
+ private static int Main(params string[] args) {
Console.Title = "Dark Skin for Unity";
- try {
-
- // try {
- // var exeBytes = File.ReadAllBytes(@"C:\Unity\2019.2.0a11\Editor\Unity.exe");
- // var functionOffset = 0x00AB6CF0;
- // var baseAddr = 0x400;
- // Console.WriteLine(UnitySkin.FormatBytes(exeBytes, functionOffset + baseAddr, 1000));
- // } catch (Exception e) {
- // Console.WriteLine(e);
- // } finally {
- // Console.ReadLine();
- // }
-
- Console.WriteLine("Fetching unity installations...");
-
- GetUnityInstallations(Environment.CurrentDirectory)
- .AsParallel()
- .Where(exe => File.Exists(exe))
- .Select(exe => new UnitySkin(exe))
- .Where(unity => unity.OffsetOfSkinFlags != -1 && unity.SkinIndex != -1)
- .Where(unity => {
- var shouldChange = (toEnable && unity.IsWhiteSkin) || (!toEnable && unity.IsDarkSkin);
- if (!shouldChange)
- unity.Log("Skin already applied, ignoring");
- return shouldChange;
- })
- .ForAll(unity => unity.SetDarkSkinEnable(toEnable));
-
- } catch (Exception e) {
- Console.Error.WriteLine("\nError");
- Console.Error.WriteLine(e);
- }
+ return Parser.Default.ParseArguments(args)
+ .MapResult(
+ (EnableOptions opts) => {
+ try {
+ Run(true, opts.InputFile, opts.FastEnumerator);
+ return 0;
+ } catch (Exception ex) {
+ HandleException(ex);
+ return 1;
+ }
+ },
+ (DisableOptions opts) => {
+ try {
+ Run(false, opts.InputFile, opts.FastEnumerator);
+ return 0;
+ } catch (Exception ex) {
+ HandleException(ex);
+ return 1;
+ }
+ },
+ (FindHexOptions opts) => {
+ try {
+ FindHex(opts.InputFile, opts.FastEnumerator);
+ return 0;
+ } catch (Exception ex) {
+ HandleException(ex);
+ return 1;
+ }
+ },
+ (errs) => 1);
}
- private static List GetUnityInstallations(string root) {
+ private static List GetUnityInstallations(string root, bool useFastFileEnumerator) {
- if (m_useFastFileEnumerator)
+ if (useFastFileEnumerator)
return FastDirectoryEnumerator.EnumerateFiles(root, "Unity.exe", SearchOption.AllDirectories)
.AsParallel()
.Tap(file => Console.WriteLine("Found {0}", file.Path))
@@ -156,7 +163,7 @@ public static class Program {
}
foreach (var directory in Directory.EnumerateDirectories(root))
- folders.AddRange(GetUnityInstallations(directory));
+ folders.AddRange(GetUnityInstallations(directory, useFastFileEnumerator));
return folders;
}
diff --git a/dark-skin/UnitySkin.cs b/dark-skin/UnitySkin.cs
index 5af8a87..33db65b 100644
--- a/dark-skin/UnitySkin.cs
+++ b/dark-skin/UnitySkin.cs
@@ -6,6 +6,8 @@
namespace DarkSkin {
public class UnitySkin {
+ private static readonly object obj = new object();
+
public static readonly string[] WHITE_HEX = new [] {
"84 C0 75 08 33 C0 48 83 C4 20 5B C3 8B 03 48 83 C4 20 5B C3", // <= 2018.2
"84 C0 75 08 33 C0 48 83 C4 30 5B C3 8B 03 48 83 C4 30 5B C3", // == 2018.3
@@ -63,7 +65,10 @@ public class UnitySkin {
EnsureBackup();
try {
+ lock(obj)
+ using(new TempConsoleColor(ConsoleColor.DarkGreen))
Log("Applying {0} skin...", enable ? "dark" : "white");
+
using(var stream = File.Open(UnityExe, FileMode.Open)) {
stream.Position = OffsetOfSkinFlags;
stream.Write(enable ? darkBytes[SkinIndex] : whiteBytes[SkinIndex], 0, (enable ? darkBytes[SkinIndex] : whiteBytes[SkinIndex]).Length);
diff --git a/dark-skin/dark-skin.csproj b/dark-skin/dark-skin.csproj
index 95b9098..6047350 100644
--- a/dark-skin/dark-skin.csproj
+++ b/dark-skin/dark-skin.csproj
@@ -1,6 +1,10 @@
-
-
+
+
+
+
+
Debug
AnyCPU
@@ -8,12 +12,13 @@
Exe
DarkSkin
dark-skin
- v4.5
+ v4.7.1
512
true
true
-
+
+
AnyCPU
true
full
@@ -23,7 +28,8 @@
prompt
4
-
+
+
AnyCPU
pdbonly
true
@@ -32,29 +38,54 @@
prompt
4
+
+
UnityIcon.ico
+
+
+
+
+
+
+ ..\packages\CommandLineParser.2.4.3\lib\netstandard2.0\CommandLine.dll
+
+
+ ..\packages\Costura.Fody.3.3.3\lib\net40\Costura.dll
+
+
+
+
+
+
+
+ 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}.
+
+
+
+
+
\ No newline at end of file
diff --git a/dark-skin/dark-skin.csproj.user b/dark-skin/dark-skin.csproj.user
index 0e53f81..d006fcf 100644
--- a/dark-skin/dark-skin.csproj.user
+++ b/dark-skin/dark-skin.csproj.user
@@ -1,7 +1,8 @@
-
- enable
+
+ findHex C:\Unity\2019.3.0a11\Editor\Unity.exe
C:\Unity\
+ true
\ No newline at end of file
diff --git a/dark-skin/packages.config b/dark-skin/packages.config
new file mode 100644
index 0000000..dde3857
--- /dev/null
+++ b/dark-skin/packages.config
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file