Browse Source

Updated to VS 2019

Better support for no console
Stdout now gets passed through the logging system for unified log locations
pull/11/head
Anairkoen Schno 5 years ago
parent
commit
759cf10cda
16 changed files with 245 additions and 18 deletions
  1. +1
    -1
      BuildTools
  2. +1
    -1
      Doorstop
  3. +0
    -1
      IPA.Injector/IPA.Injector.csproj
  4. +1
    -1
      IPA.Injector/Injector.cs
  5. +4
    -1
      IPA.Loader/IPA.Loader.csproj
  6. +22
    -0
      IPA.Loader/Logging/ConsoleWindow.cs
  7. +12
    -0
      IPA.Loader/Logging/Logger.cs
  8. +0
    -4
      IPA.Loader/Logging/Printers/ColorlessConsolePrinter.cs
  9. +4
    -1
      IPA.Loader/Logging/Printers/GZFilePrinter.cs
  10. +1
    -1
      IPA.Loader/Logging/Printers/GlobalLogFilePrinter.cs
  11. +1
    -1
      IPA.Loader/Logging/Printers/PluginLogFilePrinter.cs
  12. +1
    -1
      IPA.Loader/Logging/Printers/PluginSubLogPrinter.cs
  13. +3
    -1
      IPA.Loader/Logging/StandardLogger.cs
  14. +190
    -0
      IPA.Loader/Logging/StdoutInterceptor.cs
  15. +1
    -1
      IPA/obj/Debug/IPA.csproj.CoreCompileInputs.cache
  16. +3
    -3
      README.md

+ 1
- 1
BuildTools

@ -1 +1 @@
Subproject commit de919c49496a7e7e11382bd876473018ddceaa1a
Subproject commit af3be92b829e0068671666d74b25fb7f2ec4b520

+ 1
- 1
Doorstop

@ -1 +1 @@
Subproject commit 6b6de3b81cf142c73a8ef845f705fb1e51a7670d
Subproject commit 642c22e38a76bbdaa46dbb3aaa565c354a2ef68e

+ 0
- 1
IPA.Injector/IPA.Injector.csproj View File

@ -14,7 +14,6 @@
<Deterministic>true</Deterministic> <Deterministic>true</Deterministic>
<PathMap>$(SolutionDir)=C:\</PathMap> <PathMap>$(SolutionDir)=C:\</PathMap>
<DebugType>portable</DebugType> <DebugType>portable</DebugType>
<TargetFrameworkProfile />
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols> <DebugSymbols>true</DebugSymbols>


+ 1
- 1
IPA.Injector/Injector.cs View File

@ -239,7 +239,7 @@ namespace IPA.Injector
}; };
// need to reinit streams singe Unity seems to redirect stdout // need to reinit streams singe Unity seems to redirect stdout
WinConsole.InitializeStreams();
StdoutInterceptor.RedirectConsole();
var bootstrapper = new GameObject("NonDestructiveBootstrapper").AddComponent<Bootstrapper>(); var bootstrapper = new GameObject("NonDestructiveBootstrapper").AddComponent<Bootstrapper>();
bootstrapper.Destroyed += Bootstrapper_Destroyed; bootstrapper.Destroyed += Bootstrapper_Destroyed;


+ 4
- 1
IPA.Loader/IPA.Loader.csproj View File

@ -14,7 +14,6 @@
<Deterministic>true</Deterministic> <Deterministic>true</Deterministic>
<PathMap>$(SolutionDir)=C:\</PathMap> <PathMap>$(SolutionDir)=C:\</PathMap>
<DebugType>portable</DebugType> <DebugType>portable</DebugType>
<TargetFrameworkProfile />
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols> <DebugSymbols>true</DebugSymbols>
@ -39,6 +38,9 @@
<DocumentationFile>bin\Release\IPA.Loader.xml</DocumentationFile> <DocumentationFile>bin\Release\IPA.Loader.xml</DocumentationFile>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<Reference Include="0Harmony">
<HintPath>..\Libs\0Harmony.dll</HintPath>
</Reference>
<Reference Include="System" /> <Reference Include="System" />
<Reference Include="System.Core" /> <Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" /> <Reference Include="System.Xml.Linq" />
@ -76,6 +78,7 @@
<Compile Include="Logging\ConsoleWindow.cs" /> <Compile Include="Logging\ConsoleWindow.cs" />
<Compile Include="Logging\Printers\ColorlessConsolePrinter.cs" /> <Compile Include="Logging\Printers\ColorlessConsolePrinter.cs" />
<Compile Include="Logging\Printers\PluginSubLogPrinter.cs" /> <Compile Include="Logging\Printers\PluginSubLogPrinter.cs" />
<Compile Include="Logging\StdoutInterceptor.cs" />
<Compile Include="PluginInterfaces\BeatSaber\IBeatSaberPlugin.cs" /> <Compile Include="PluginInterfaces\BeatSaber\IBeatSaberPlugin.cs" />
<Compile Include="PluginInterfaces\BeatSaber\IEnhancedBeatSaberPlugin.cs" /> <Compile Include="PluginInterfaces\BeatSaber\IEnhancedBeatSaberPlugin.cs" />
<Compile Include="PluginInterfaces\BeatSaber\ModsaberModInfo.cs" /> <Compile Include="PluginInterfaces\BeatSaber\ModsaberModInfo.cs" />


+ 22
- 0
IPA.Loader/Logging/ConsoleWindow.cs View File

@ -1,4 +1,5 @@
using System; using System;
using System.ComponentModel;
using System.IO; using System.IO;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using Microsoft.Win32.SafeHandles; using Microsoft.Win32.SafeHandles;
@ -51,6 +52,16 @@ namespace IPA.Logging
ConOut = writer; ConOut = writer;
Console.SetOut(writer); Console.SetOut(writer);
Console.SetError(writer); Console.SetError(writer);
var handle = GetStdHandle(-11); // get stdout handle (should be CONOUT$ at this point)
if (GetConsoleMode(handle, out var mode))
{
mode |= EnableVTProcessing;
if (!SetConsoleMode(handle, mode))
throw new Win32Exception(Marshal.GetLastWin32Error());
}
else
throw new Win32Exception(Marshal.GetLastWin32Error());
} }
} }
@ -108,6 +119,17 @@ namespace IPA.Logging
IntPtr hTemplateFile IntPtr hTemplateFile
); );
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern bool GetConsoleMode(IntPtr hConsoleHandle, out uint lpMode);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern bool SetConsoleMode(IntPtr hConsoleHandle, uint dwMode);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr GetStdHandle(int nStdHandle);
private const uint EnableVTProcessing = 0x0004;
private const uint GenericWrite = 0x40000000; private const uint GenericWrite = 0x40000000;
private const uint GenericRead = 0x80000000; private const uint GenericRead = 0x80000000;
private const uint FileShareRead = 0x00000001; private const uint FileShareRead = 0x00000001;


+ 12
- 0
IPA.Loader/Logging/Logger.cs View File

@ -21,6 +21,18 @@ namespace IPA.Logging
} }
} }
private static StandardLogger _stdout;
internal static StandardLogger stdout
{
get
{
if (_stdout == null)
_stdout = new StandardLogger("_");
return _stdout;
}
}
internal static Logger updater => log.GetChildLogger("Updater"); internal static Logger updater => log.GetChildLogger("Updater");
internal static Logger libLoader => log.GetChildLogger("LibraryLoader"); internal static Logger libLoader => log.GetChildLogger("LibraryLoader");
internal static Logger loader => log.GetChildLogger("Loader"); internal static Logger loader => log.GetChildLogger("Loader");


+ 0
- 4
IPA.Loader/Logging/Printers/ColorlessConsolePrinter.cs View File

@ -1,8 +1,4 @@
using System; using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace IPA.Logging.Printers namespace IPA.Logging.Printers
{ {


+ 4
- 1
IPA.Loader/Logging/Printers/GZFilePrinter.cs View File

@ -3,6 +3,7 @@ using System;
using System.IO; using System.IO;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Text; using System.Text;
using System.Text.RegularExpressions;
namespace IPA.Logging.Printers namespace IPA.Logging.Printers
{ {
@ -18,6 +19,8 @@ namespace IPA.Logging.Printers
IntPtr lpSecurityAttributes IntPtr lpSecurityAttributes
); );
internal static Regex removeControlCodes = new Regex("\x1b\\[\\d+m", RegexOptions.Compiled);
private FileInfo fileInfo; private FileInfo fileInfo;
/// <summary> /// <summary>
@ -45,7 +48,7 @@ namespace IPA.Logging.Printers
fileInfo = new FileInfo(fileInfo.FullName + ".gz"); fileInfo = new FileInfo(fileInfo.FullName + ".gz");
fileInfo.Create().Close(); fileInfo.Create().Close();
var symlink = new FileInfo(Path.Combine(fileInfo.DirectoryName ?? throw new InvalidOperationException(), $"latest{ext}.gz"));
var symlink = new FileInfo(Path.Combine(fileInfo.DirectoryName ?? throw new InvalidOperationException(), $"_latest{ext}.gz"));
if (symlink.Exists) symlink.Delete(); if (symlink.Exists) symlink.Delete();
try try


+ 1
- 1
IPA.Loader/Logging/Printers/GlobalLogFilePrinter.cs View File

@ -22,7 +22,7 @@ namespace IPA.Logging.Printers
/// <param name="message">the message to print</param> /// <param name="message">the message to print</param>
public override void Print(Logger.Level level, DateTime time, string logName, string message) public override void Print(Logger.Level level, DateTime time, string logName, string message)
{ {
foreach (var line in message.Split(new[] { "\n", Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries))
foreach (var line in removeControlCodes.Replace(message, "").Split(new[] { "\n", Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries))
FileWriter.WriteLine(Logger.LogFormat, line, logName, time, level.ToString().ToUpper()); FileWriter.WriteLine(Logger.LogFormat, line, logName, time, level.ToString().ToUpper());
} }


+ 1
- 1
IPA.Loader/Logging/Printers/PluginLogFilePrinter.cs View File

@ -45,7 +45,7 @@ namespace IPA.Logging.Printers
/// <param name="message">the message to print</param> /// <param name="message">the message to print</param>
public override void Print(Logger.Level level, DateTime time, string logName, string message) public override void Print(Logger.Level level, DateTime time, string logName, string message)
{ {
foreach (var line in message.Split(new[] { "\n", Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries))
foreach (var line in removeControlCodes.Replace(message, "").Split(new[] { "\n", Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries))
FileWriter.WriteLine(Logger.LogFormat, line, logName, time, level.ToString().ToUpper()); FileWriter.WriteLine(Logger.LogFormat, line, logName, time, level.ToString().ToUpper());
} }
} }

+ 1
- 1
IPA.Loader/Logging/Printers/PluginSubLogPrinter.cs View File

@ -48,7 +48,7 @@ namespace IPA.Logging.Printers
/// <param name="message">the message to print</param> /// <param name="message">the message to print</param>
public override void Print(Logger.Level level, DateTime time, string logName, string message) public override void Print(Logger.Level level, DateTime time, string logName, string message)
{ {
foreach (var line in message.Split(new[] { "\n", Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries))
foreach (var line in removeControlCodes.Replace(message, "").Split(new[] { "\n", Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries))
FileWriter.WriteLine("[{2} @ {1:HH:mm:ss}] {0}", line, time, level.ToString().ToUpper()); FileWriter.WriteLine("[{2} @ {1:HH:mm:ss}] {0}", line, time, level.ToString().ToUpper());
} }
} }

+ 3
- 1
IPA.Loader/Logging/StandardLogger.cs View File

@ -71,6 +71,7 @@ namespace IPA.Logging
Color = ConsoleColor.Magenta, Color = ConsoleColor.Magenta,
} }
}); });
addedConsolePrinters = true; addedConsolePrinters = true;
} }
} }
@ -135,7 +136,8 @@ namespace IPA.Logging
{ {
if (!addedConsolePrinters) if (!addedConsolePrinters)
AddDefaultPrinter(new ColorlessConsolePrinter()); AddDefaultPrinter(new ColorlessConsolePrinter());
StdoutInterceptor.Intercept();
finalizedDefaultPrinters = true; finalizedDefaultPrinters = true;
} }


+ 190
- 0
IPA.Loader/Logging/StdoutInterceptor.cs View File

@ -0,0 +1,190 @@
using Harmony;
using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection.Emit;
using System.Text;
namespace IPA.Logging
{
internal class StdoutInterceptor : TextWriter
{
public override Encoding Encoding => Encoding.Default;
private bool isStdErr;
public override void Write(char value)
{
Write(value.ToString());
}
private string lineBuffer = "";
public override void Write(string value)
{
lineBuffer += value;
var parts = lineBuffer.Split(new[] { Environment.NewLine, "\n", "\r" }, StringSplitOptions.None);
for (int i = 0; i < parts.Length; i++)
{
if (i + 1 == parts.Length) // last element
lineBuffer = parts[i];
else
{
var str = parts[i];
if (string.IsNullOrEmpty(str)) continue;
if (!isStdErr && WinConsole.IsInitialized)
str = ConsoleColorToForegroundSet(currentColor) + str;
if (isStdErr)
Logger.stdout.Error(str);
else
Logger.stdout.Info(str);
}
}
}
private const ConsoleColor defaultColor = ConsoleColor.Gray;
private ConsoleColor currentColor = defaultColor;
private static string ConsoleColorToForegroundSet(ConsoleColor col)
{
string code = "0"; // reset
switch (col)
{
case ConsoleColor.Black:
code = "30";
break;
case ConsoleColor.DarkBlue:
code = "34";
break;
case ConsoleColor.DarkGreen:
code = "32";
break;
case ConsoleColor.DarkCyan:
code = "36";
break;
case ConsoleColor.DarkRed:
code = "31";
break;
case ConsoleColor.DarkMagenta:
code = "35";
break;
case ConsoleColor.DarkYellow:
code = "33";
break;
case ConsoleColor.Gray:
code = "37";
break;
case ConsoleColor.DarkGray:
code = "90"; // literally bright black
break;
case ConsoleColor.Blue:
code = "94";
break;
case ConsoleColor.Green:
code = "92";
break;
case ConsoleColor.Cyan:
code = "96";
break;
case ConsoleColor.Red:
code = "91";
break;
case ConsoleColor.Magenta:
code = "95";
break;
case ConsoleColor.Yellow:
code = "93";
break;
case ConsoleColor.White:
code = "97";
break;
}
return "\x1b[" + code + "m";
}
private static StdoutInterceptor stdoutInterceptor;
private static StdoutInterceptor stderrInterceptor;
private static class ConsoleHarmonyPatches
{
public static void Patch(HarmonyInstance harmony)
{
var console = typeof(Console);
var resetColor = console.GetMethod("ResetColor");
var foregroundProperty = console.GetProperty("ForegroundColor");
var setFg = foregroundProperty.SetMethod;
var getFg = foregroundProperty.GetMethod;
harmony.Patch(resetColor, transpiler: new HarmonyMethod(typeof(ConsoleHarmonyPatches), "PatchResetColor"));
harmony.Patch(setFg, transpiler: new HarmonyMethod(typeof(ConsoleHarmonyPatches), "PatchSetForegroundColor"));
harmony.Patch(getFg, transpiler: new HarmonyMethod(typeof(ConsoleHarmonyPatches), "PatchGetForegroundColor"));
}
public static ConsoleColor GetColor() => stdoutInterceptor.currentColor;
public static void SetColor(ConsoleColor col) => stdoutInterceptor.currentColor = col;
public static void ResetColor() => stdoutInterceptor.currentColor = defaultColor;
public static IEnumerable<CodeInstruction> PatchGetForegroundColor(IEnumerable<CodeInstruction> _)
{
var getColorM = typeof(ConsoleHarmonyPatches).GetMethod("GetColor");
return new[] {
new CodeInstruction(OpCodes.Call, getColorM),
new CodeInstruction(OpCodes.Ret)
};
}
public static IEnumerable<CodeInstruction> PatchSetForegroundColor(IEnumerable<CodeInstruction> _)
{
var setColorM = typeof(ConsoleHarmonyPatches).GetMethod("SetColor");
return new[] {
new CodeInstruction(OpCodes.Ldarg_0),
new CodeInstruction(OpCodes.Call, setColorM),
new CodeInstruction(OpCodes.Ret)
};
}
public static IEnumerable<CodeInstruction> PatchResetColor(IEnumerable<CodeInstruction> _)
{
var resetColor = typeof(ConsoleHarmonyPatches).GetMethod("ResetColor");
return new[] {
new CodeInstruction(OpCodes.Call, resetColor),
new CodeInstruction(OpCodes.Ret)
};
}
}
private static HarmonyInstance harmony;
private static bool usingInterceptor = false;
public static void Intercept()
{
if (!usingInterceptor)
{
usingInterceptor = true;
if (harmony == null)
harmony = HarmonyInstance.Create("BSIPA Console Redirector Patcher");
if (stdoutInterceptor == null)
stdoutInterceptor = new StdoutInterceptor();
if (stderrInterceptor == null)
stderrInterceptor = new StdoutInterceptor() { isStdErr = true };
RedirectConsole();
ConsoleHarmonyPatches.Patch(harmony);
}
}
public static void RedirectConsole()
{
if (usingInterceptor)
{
Console.SetOut(stdoutInterceptor);
Console.SetError(stderrInterceptor);
}
}
}
}

+ 1
- 1
IPA/obj/Debug/IPA.csproj.CoreCompileInputs.cache View File

@ -1 +1 @@
5d76d76cc5c14257f2b9071c928c27b3edd80cc0
b1078c6b90a14bd4bd5a5e7f04507fbb89e2b3a7

+ 3
- 3
README.md View File

@ -47,9 +47,9 @@ BSIPA will automatically repatch the game when it updates, as long as `winhttp.d
### Prerequisites ### Prerequisites
- Microsoft Visual Studio 2017 or later
- Tools for C/C++ (MSVC)
- .NET 4.6 SDK and .NET 4.7.1 SDK
- Microsoft Visual Studio 2019 or later
- Tools for C/C++ (MSVC) v142
- .NET 4.6.1 SDK and .NET 4.7.2 SDK
### Building ### Building


Loading…
Cancel
Save