diff --git a/BuildTools b/BuildTools
index e0cefce0..de919c49 160000
--- a/BuildTools
+++ b/BuildTools
@@ -1 +1 @@
-Subproject commit e0cefce0a1bb1aacc0afdbf305df1fa65da55464
+Subproject commit de919c49496a7e7e11382bd876473018ddceaa1a
diff --git a/IPA.Injector/IPA.Injector.csproj b/IPA.Injector/IPA.Injector.csproj
index c088d9f0..14e11358 100644
--- a/IPA.Injector/IPA.Injector.csproj
+++ b/IPA.Injector/IPA.Injector.csproj
@@ -56,7 +56,6 @@
-
diff --git a/IPA.Injector/Injector.cs b/IPA.Injector/Injector.cs
index d883e16e..fae10e9f 100644
--- a/IPA.Injector/Injector.cs
+++ b/IPA.Injector/Injector.cs
@@ -35,14 +35,14 @@ namespace IPA.Injector
SetupLibraryLoading();
- EnsureUserData();
+ EnsureDirectories();
// this is weird, but it prevents Mono from having issues loading the type.
// IMPORTANT: NO CALLS TO ANY LOGGER CAN HAPPEN BEFORE THIS
var unused = StandardLogger.PrintFilter;
#region // Above hack explaination
/*
- * Due to an unknown bug in the version of Mono that Unity 2018.1.8 uses, if the first access to StandardLogger
+ * Due to an unknown bug in the version of Mono that Unity uses, if the first access to StandardLogger
* is a call to a constructor, then Mono fails to load the type correctly. However, if the first access is to
* the above static property (or maybe any, but I don't really know) it behaves as expected and works fine.
*/
@@ -66,11 +66,13 @@ namespace IPA.Injector
}
}
- private static void EnsureUserData()
+ private static void EnsureDirectories()
{
string path;
if (!Directory.Exists(path = Path.Combine(Environment.CurrentDirectory, "UserData")))
Directory.CreateDirectory(path);
+ if (!Directory.Exists(path = Path.Combine(Environment.CurrentDirectory, "Plugins")))
+ Directory.CreateDirectory(path);
}
private static void SetupLibraryLoading()
diff --git a/IPA.Loader/IPA.Loader.csproj b/IPA.Loader/IPA.Loader.csproj
index 91170d48..b839eea7 100644
--- a/IPA.Loader/IPA.Loader.csproj
+++ b/IPA.Loader/IPA.Loader.csproj
@@ -73,6 +73,8 @@
+
+
diff --git a/IPA.Injector/ConsoleWindow.cs b/IPA.Loader/Logging/ConsoleWindow.cs
similarity index 81%
rename from IPA.Injector/ConsoleWindow.cs
rename to IPA.Loader/Logging/ConsoleWindow.cs
index a44e8d24..f8e655ae 100644
--- a/IPA.Injector/ConsoleWindow.cs
+++ b/IPA.Loader/Logging/ConsoleWindow.cs
@@ -3,11 +3,22 @@ using System.IO;
using System.Runtime.InteropServices;
using Microsoft.Win32.SafeHandles;
-namespace IPA.Injector
+namespace IPA.Logging
{
// https://stackoverflow.com/a/48864902/3117125
internal static class WinConsole
{
+ internal static TextWriter ConOut;
+ internal static TextReader ConIn;
+
+ private static SafeFileHandle outHandle;
+ private static SafeFileHandle inHandle;
+
+ internal static IntPtr OutHandle => outHandle.DangerousGetHandle();
+ internal static IntPtr InHandle => inHandle.DangerousGetHandle();
+
+ internal static bool IsInitialized;
+
public static void Initialize(bool alwaysCreateNewConsole = true)
{
bool consoleAttached = true;
@@ -21,6 +32,7 @@ namespace IPA.Injector
if (consoleAttached)
{
InitializeStreams();
+ IsInitialized = true;
}
}
@@ -32,10 +44,11 @@ namespace IPA.Injector
private static void InitializeOutStream()
{
- var fs = CreateFileStream("CONOUT$", GenericWrite, FileShareWrite, FileAccess.Write);
+ var fs = CreateFileStream("CONOUT$", GenericWrite, FileShareWrite, FileAccess.Write, out outHandle);
if (fs != null)
{
var writer = new StreamWriter(fs) { AutoFlush = true };
+ ConOut = writer;
Console.SetOut(writer);
Console.SetError(writer);
}
@@ -43,22 +56,25 @@ namespace IPA.Injector
private static void InitializeInStream()
{
- var fs = CreateFileStream("CONIN$", GenericRead, FileShareRead, FileAccess.Read);
+ var fs = CreateFileStream("CONIN$", GenericRead, FileShareRead, FileAccess.Read, out inHandle);
if (fs != null)
{
- Console.SetIn(new StreamReader(fs));
+ Console.SetIn(ConIn = new StreamReader(fs));
}
}
private static FileStream CreateFileStream(string name, uint win32DesiredAccess, uint win32ShareMode,
- FileAccess dotNetFileAccess)
+ FileAccess dotNetFileAccess, out SafeFileHandle handle)
{
var file = new SafeFileHandle(CreateFileW(name, win32DesiredAccess, win32ShareMode, IntPtr.Zero, OpenExisting, FileAttributeNormal, IntPtr.Zero), true);
if (!file.IsInvalid)
{
+ handle = file;
var fs = new FileStream(file, dotNetFileAccess);
return fs;
}
+
+ handle = null;
return null;
}
diff --git a/IPA.Loader/Logging/Printers/ColoredConsolePrinter.cs b/IPA.Loader/Logging/Printers/ColoredConsolePrinter.cs
index 39e6b22f..2cab7277 100644
--- a/IPA.Loader/Logging/Printers/ColoredConsolePrinter.cs
+++ b/IPA.Loader/Logging/Printers/ColoredConsolePrinter.cs
@@ -1,4 +1,5 @@
using System;
+using System.Runtime.InteropServices;
namespace IPA.Logging.Printers
{
@@ -7,7 +8,7 @@ namespace IPA.Logging.Printers
///
public class ColoredConsolePrinter : LogPrinter
{
- Logger.LogLevel filter = Logger.LogLevel.All;
+ private Logger.LogLevel filter = Logger.LogLevel.All;
///
/// A filter for this specific printer.
@@ -19,7 +20,7 @@ namespace IPA.Logging.Printers
public ConsoleColor Color { get; set; } = Console.ForegroundColor;
///
- /// Prints an entry to the associated file.
+ /// Prints an entry to the console window.
///
/// the of the message
/// the the message was recorded at
@@ -28,10 +29,79 @@ namespace IPA.Logging.Printers
public override void Print(Logger.Level level, DateTime time, string logName, string message)
{
if (((byte)level & (byte)StandardLogger.PrintFilter) == 0) return;
- Console.ForegroundColor = Color;
+ EnsureDefaultsPopulated(WinConsole.OutHandle);
+ SetColor(Color, WinConsole.OutHandle);
foreach (var line in message.Split(new[] { "\n", Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries))
- Console.WriteLine(Logger.LogFormat, line, logName, time, level.ToString().ToUpper());
- Console.ResetColor();
+ WinConsole.ConOut.WriteLine(Logger.LogFormat, line, logName, time, level.ToString().ToUpper());
+ ResetColor(WinConsole.OutHandle);
}
+
+ private static bool _haveReadDefaultColors;
+ private static short _defaultColors;
+
+ private void EnsureDefaultsPopulated(IntPtr handle, bool force = false)
+ {
+ if (!_haveReadDefaultColors | force)
+ {
+ GetConsoleScreenBufferInfo(handle, out var info);
+ _defaultColors = (short)(info.Attribute & ~15);
+ _haveReadDefaultColors = true;
+ }
+ }
+
+ private void ResetColor(IntPtr handle)
+ {
+ GetConsoleScreenBufferInfo(handle, out var info);
+ var otherAttrs = (short)(info.Attribute & ~15);
+ SetConsoleTextAttribute(handle, (short)(otherAttrs | _defaultColors));
+ }
+
+ private void SetColor(ConsoleColor col, IntPtr handle)
+ {
+ GetConsoleScreenBufferInfo(handle, out var info);
+ var attr = GetAttrForeground(info.Attribute, col);
+ SetConsoleTextAttribute(handle, attr);
+ }
+
+ private static short GetAttrForeground(int attr, ConsoleColor color)
+ {
+ attr &= ~15;
+ return (short)(attr | (int)color);
+ }
+
+
+ // ReSharper disable NotAccessedField.Local
+#pragma warning disable 649
+ private struct Coordinate
+ {
+ public short X;
+ public short Y;
+ }
+
+ private struct SmallRect
+ {
+ public short Left;
+ public short Top;
+ public short Right;
+ public short Bottom;
+ }
+
+ private struct ConsoleScreenBufferInfo
+ {
+ public Coordinate Size;
+ public Coordinate CursorPosition;
+ public short Attribute;
+ public SmallRect Window;
+ public Coordinate MaxWindowSize;
+ }
+ #pragma warning restore 649
+ // ReSharper restore NotAccessedField.Local
+
+
+ [DllImport("kernel32.dll", EntryPoint = "GetConsoleScreenBufferInfo", SetLastError = true, CharSet = CharSet.Unicode)]
+ private static extern bool GetConsoleScreenBufferInfo(IntPtr handle, out ConsoleScreenBufferInfo info);
+
+ [DllImport("kernel32.dll", EntryPoint = "SetConsoleTextAttribute", SetLastError = true, CharSet = CharSet.Unicode)]
+ private static extern bool SetConsoleTextAttribute(IntPtr handle, short attribute);
}
}
diff --git a/IPA.Loader/Logging/Printers/ColorlessConsolePrinter.cs b/IPA.Loader/Logging/Printers/ColorlessConsolePrinter.cs
new file mode 100644
index 00000000..754b75ed
--- /dev/null
+++ b/IPA.Loader/Logging/Printers/ColorlessConsolePrinter.cs
@@ -0,0 +1,33 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace IPA.Logging.Printers
+{
+ ///
+ /// A colorless version of , that indiscriminantly prints to standard out.
+ ///
+ public class ColorlessConsolePrinter : LogPrinter
+ {
+ ///
+ /// A filter for this specific printer.
+ ///
+ public override Logger.LogLevel Filter { get; set; }
+
+ ///
+ /// Prints an entry to standard out.
+ ///
+ /// the of the message
+ /// the the message was recorded at
+ /// the name of the log that sent the message
+ /// the message to print
+ public override void Print(Logger.Level level, DateTime time, string logName, string message)
+ {
+ if (((byte)level & (byte)StandardLogger.PrintFilter) == 0) return;
+ foreach (var line in message.Split(new[] { "\n", Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries))
+ Console.WriteLine(Logger.LogFormat, line, logName, time, level.ToString().ToUpper());
+ }
+ }
+}
diff --git a/IPA.Loader/Logging/StandardLogger.cs b/IPA.Loader/Logging/StandardLogger.cs
index 83ff7dd3..197c3ac9 100644
--- a/IPA.Loader/Logging/StandardLogger.cs
+++ b/IPA.Loader/Logging/StandardLogger.cs
@@ -24,39 +24,57 @@ namespace IPA.Logging
{
private static readonly List defaultPrinters = new List()
{
- new ColoredConsolePrinter()
- {
- Filter = LogLevel.DebugOnly,
- Color = ConsoleColor.Green,
- },
- new ColoredConsolePrinter()
- {
- Filter = LogLevel.InfoOnly,
- Color = ConsoleColor.White,
- },
- new ColoredConsolePrinter()
- {
- Filter = LogLevel.NoticeOnly,
- Color = ConsoleColor.Cyan
- },
- new ColoredConsolePrinter()
- {
- Filter = LogLevel.WarningOnly,
- Color = ConsoleColor.Yellow,
- },
- new ColoredConsolePrinter()
- {
- Filter = LogLevel.ErrorOnly,
- Color = ConsoleColor.Red,
- },
- new ColoredConsolePrinter()
- {
- Filter = LogLevel.CriticalOnly,
- Color = ConsoleColor.Magenta,
- },
new GlobalLogFilePrinter()
};
+ static StandardLogger()
+ {
+ ConsoleColorSupport();
+ }
+
+ private static bool addedConsolePrinters;
+ private static bool finalizedDefaultPrinters;
+ internal static void ConsoleColorSupport()
+ {
+ if (!addedConsolePrinters && !finalizedDefaultPrinters && WinConsole.IsInitialized )
+ {
+ defaultPrinters.AddRange(new []
+ {
+ new ColoredConsolePrinter()
+ {
+ Filter = LogLevel.DebugOnly,
+ Color = ConsoleColor.Green,
+ },
+ new ColoredConsolePrinter()
+ {
+ Filter = LogLevel.InfoOnly,
+ Color = ConsoleColor.White,
+ },
+ new ColoredConsolePrinter()
+ {
+ Filter = LogLevel.NoticeOnly,
+ Color = ConsoleColor.Cyan
+ },
+ new ColoredConsolePrinter()
+ {
+ Filter = LogLevel.WarningOnly,
+ Color = ConsoleColor.Yellow,
+ },
+ new ColoredConsolePrinter()
+ {
+ Filter = LogLevel.ErrorOnly,
+ Color = ConsoleColor.Red,
+ },
+ new ColoredConsolePrinter()
+ {
+ Filter = LogLevel.CriticalOnly,
+ Color = ConsoleColor.Magenta,
+ }
+ });
+ addedConsolePrinters = true;
+ }
+ }
+
///
/// The for writing directly to the console window, or stdout if no window open.
///
@@ -112,6 +130,15 @@ namespace IPA.Logging
internal StandardLogger(string name)
{
+ ConsoleColorSupport();
+ if (!finalizedDefaultPrinters)
+ {
+ if (!addedConsolePrinters)
+ AddDefaultPrinter(new ColorlessConsolePrinter());
+
+ finalizedDefaultPrinters = true;
+ }
+
logName = name;
printers.Add(new PluginLogFilePrinter(name));
diff --git a/IPA/obj/Debug/IPA.csproj.CoreCompileInputs.cache b/IPA/obj/Debug/IPA.csproj.CoreCompileInputs.cache
index 0e65ef0f..d16fba0d 100644
--- a/IPA/obj/Debug/IPA.csproj.CoreCompileInputs.cache
+++ b/IPA/obj/Debug/IPA.csproj.CoreCompileInputs.cache
@@ -1 +1 @@
-0a3222410c8b7f878f3aac05d926ef18ba74d12a
+5d76d76cc5c14257f2b9071c928c27b3edd80cc0
diff --git a/Refs/UnityEngine.CoreModule.dll b/Refs/UnityEngine.CoreModule.dll
index ec2d2901..f6478af7 100644
Binary files a/Refs/UnityEngine.CoreModule.dll and b/Refs/UnityEngine.CoreModule.dll differ