Skip to content

Commit

Permalink
Add Console Color support for wine
Browse files Browse the repository at this point in the history
  • Loading branch information
RinLovesYou committed Dec 29, 2023
1 parent 7565516 commit 89612be
Show file tree
Hide file tree
Showing 3 changed files with 123 additions and 35 deletions.
5 changes: 2 additions & 3 deletions MelonLoader/MelonLoader.Shared/Core.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,11 @@ public class Core
public static readonly bool IsAlpha = true;
public static void Startup(string engineModulePath)
{
OsUtils.SetupWineCheck();
MelonEnvironment.Initialize();
MelonLaunchOptions.Load();
OsUtils.SetupWineCheck();

if (MelonUtils.IsUnderWineOrSteamProton())
Pastel.ConsoleExtensions.Disable();
Pastel.ConsoleExtensions.Disable();

MelonDebug.Msg("MelonLoader.Core.Startup");

Expand Down
151 changes: 120 additions & 31 deletions MelonLoader/MelonLoader.Shared/Utils/MelonLogger.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Text;
using MelonLoader.Pastel;

Expand All @@ -10,22 +11,37 @@ public class MelonLogger
public static readonly Color DefaultMelonColor = Color.Cyan;

//Identical to Msg(string) except it skips walking the stack to find a melon
internal static void MsgDirect(string txt) => NativeMsg(DefaultMelonColor, MelonUtils.DefaultTextColor, null, txt, true);
internal static void MsgDirect(string txt) =>
NativeMsg(DefaultMelonColor, MelonUtils.DefaultTextColor, null, txt, true);

public static void Msg(object obj) =>
NativeMsg(DefaultMelonColor, MelonUtils.DefaultTextColor, null, obj.ToString());

public static void Msg(object obj) => NativeMsg(DefaultMelonColor, MelonUtils.DefaultTextColor, null, obj.ToString());
public static void Msg(string txt) => NativeMsg(DefaultMelonColor, MelonUtils.DefaultTextColor, null, txt);
public static void Msg(string txt, params object[] args) => NativeMsg(DefaultMelonColor, MelonUtils.DefaultTextColor, null, string.Format(txt, args));

public static void Msg(ConsoleColor txt_color, object obj) => NativeMsg(DefaultMelonColor, txt_color.ToDrawingColor(), null, obj.ToString());
public static void Msg(ConsoleColor txt_color, string txt) => NativeMsg(DefaultMelonColor, txt_color.ToDrawingColor(), null, txt);
public static void Msg(ConsoleColor txt_color, string txt, params object[] args) => NativeMsg(DefaultMelonColor, txt_color.ToDrawingColor(), null, string.Format(txt, args));
public static void Msg(string txt, params object[] args) => NativeMsg(DefaultMelonColor,
MelonUtils.DefaultTextColor, null, string.Format(txt, args));

public static void Msg(ConsoleColor txt_color, object obj) =>
NativeMsg(DefaultMelonColor, txt_color.ToDrawingColor(), null, obj.ToString());

public static void Msg(ConsoleColor txt_color, string txt) =>
NativeMsg(DefaultMelonColor, txt_color.ToDrawingColor(), null, txt);

public static void Msg(ConsoleColor txt_color, string txt, params object[] args) => NativeMsg(DefaultMelonColor,
txt_color.ToDrawingColor(), null, string.Format(txt, args));

//Identical to Msg(Color, string) except it skips walking the stack to find a melon
public static void MsgDirect(Color txt_color, string txt) => NativeMsg(DefaultMelonColor, txt_color, null, txt, true);

public static void Msg(Color txt_color, object obj) => NativeMsg(DefaultMelonColor, txt_color, null, obj.ToString());
public static void MsgDirect(Color txt_color, string txt) =>
NativeMsg(DefaultMelonColor, txt_color, null, txt, true);

public static void Msg(Color txt_color, object obj) =>
NativeMsg(DefaultMelonColor, txt_color, null, obj.ToString());

public static void Msg(Color txt_color, string txt) => NativeMsg(DefaultMelonColor, txt_color, null, txt);
public static void Msg(Color txt_color, string txt, params object[] args) => NativeMsg(DefaultMelonColor, txt_color, null, string.Format(txt, args));

public static void Msg(Color txt_color, string txt, params object[] args) =>
NativeMsg(DefaultMelonColor, txt_color, null, string.Format(txt, args));


public static void Warning(object obj) => NativeWarning(null, obj.ToString());
Expand All @@ -40,8 +56,9 @@ public class MelonLogger

public static void WriteLine(int length = 30) => MsgDirect(new string('-', length));
public static void WriteLine(Color color, int length = 30) => MsgDirect(color, new string('-', length));

private static void NativeMsg(Color namesection_color, Color txt_color, string namesection, string txt, bool skipStackWalk = false)

private static void NativeMsg(Color namesection_color, Color txt_color, string namesection, string txt,
bool skipStackWalk = false)
{
Internal_Msg(namesection_color, txt_color, namesection, txt ?? "null");
RunMsgCallbacks(namesection_color, txt_color, namesection, txt ?? "null");
Expand Down Expand Up @@ -73,10 +90,17 @@ internal static void RunMsgCallbacks(Color namesection_color, Color txt_color, s
{
MsgCallbackHandler?.Invoke(namesection_color, txt_color, namesection, txt);
}

public static event Action<Color, Color, string, string> MsgCallbackHandler;
internal static void RunWarningCallbacks(string namesection, string txt) => WarningCallbackHandler?.Invoke(namesection, txt);

internal static void RunWarningCallbacks(string namesection, string txt) =>
WarningCallbackHandler?.Invoke(namesection, txt);

public static event Action<string, string> WarningCallbackHandler;
internal static void RunErrorCallbacks(string namesection, string txt) => ErrorCallbackHandler?.Invoke(namesection, txt);

internal static void RunErrorCallbacks(string namesection, string txt) =>
ErrorCallbackHandler?.Invoke(namesection, txt);

public static event Action<string, string> ErrorCallbackHandler;

public class Instance
Expand All @@ -89,16 +113,25 @@ public class Instance

public void Msg(object obj) => NativeMsg(DrawingColor, MelonUtils.DefaultTextColor, Name, obj.ToString());
public void Msg(string txt) => NativeMsg(DrawingColor, MelonUtils.DefaultTextColor, Name, txt);
public void Msg(string txt, params object[] args) => NativeMsg(DrawingColor, MelonUtils.DefaultTextColor, Name, string.Format(txt, args));

public void Msg(string txt, params object[] args) => NativeMsg(DrawingColor, MelonUtils.DefaultTextColor,
Name, string.Format(txt, args));


public void Msg(ConsoleColor txt_color, object obj) => NativeMsg(DrawingColor, txt_color.ToDrawingColor(), Name, obj.ToString());
public void Msg(ConsoleColor txt_color, string txt) => NativeMsg(DrawingColor, txt_color.ToDrawingColor(), Name, txt);
public void Msg(ConsoleColor txt_color, string txt, params object[] args) => NativeMsg(DrawingColor, txt_color.ToDrawingColor(), Name, string.Format(txt, args));
public void Msg(ConsoleColor txt_color, object obj) =>
NativeMsg(DrawingColor, txt_color.ToDrawingColor(), Name, obj.ToString());

public void Msg(ConsoleColor txt_color, string txt) =>
NativeMsg(DrawingColor, txt_color.ToDrawingColor(), Name, txt);

public void Msg(ConsoleColor txt_color, string txt, params object[] args) => NativeMsg(DrawingColor,
txt_color.ToDrawingColor(), Name, string.Format(txt, args));

public void Msg(Color txt_color, object obj) => NativeMsg(DrawingColor, txt_color, Name, obj.ToString());
public void Msg(Color txt_color, string txt) => NativeMsg(DrawingColor, txt_color, Name, txt);
public void Msg(Color txt_color, string txt, params object[] args) => NativeMsg(DrawingColor, txt_color, Name, string.Format(txt, args));

public void Msg(Color txt_color, string txt, params object[] args) =>
NativeMsg(DrawingColor, txt_color, Name, string.Format(txt, args));

public void Warning(object obj) => NativeWarning(Name, obj.ToString());
public void Warning(string txt) => NativeWarning(Name, txt);
Expand All @@ -108,32 +141,84 @@ public class Instance
public void Error(string txt) => NativeError(Name, txt);
public void Error(string txt, params object[] args) => NativeError(Name, string.Format(txt, args));
public void Error(string txt, Exception ex) => NativeError(Name, $"{txt}\n{ex}");

public void WriteSpacer() => MelonLogger.WriteSpacer();
public void WriteLine(int length = 30) => MelonLogger.WriteLine(length);
public void WriteLine(Color color, int length = 30) => MelonLogger.WriteLine(color, length);

public void BigError(string txt) => MelonLogger.BigError(Name, txt);
}

internal static void Internal_Msg(Color namesection_color, Color txt_color, string namesection, string txt)
internal static void Internal_Msg(Color namesection_color, Color txt_color, string namesection, string txt,
bool error = false)
{
BootstrapInterop.NativeWriteLogToFile($"[{MelonUtils.TimeStamp}] {(namesection is null ? "" : $"[{namesection}] ")}{txt}");
BootstrapInterop.NativeWriteLogToFile(
$"[{MelonUtils.TimeStamp}] {(error ? "[ERROR] " : "")}{(namesection is null ? "" : $"[{namesection}] ")}{txt}");

StringBuilder builder = new StringBuilder();
if (MelonUtils.IsUnderWineOrSteamProton())
{
WriteTimestampWine(error);
if (error)
WriteConsoleColor(ConsoleColor.Red, "[ERROR] ");

if (namesection is not null)
{
WriteConsoleColor(error ? ConsoleColor.Red : ConsoleColor.Gray, "[");
WriteConsoleColor(namesection_color.ToConsoleColor(), namesection);
WriteConsoleColor(error ? ConsoleColor.Red : ConsoleColor.Gray, "] ");
}

WriteConsoleColor(txt_color.ToConsoleColor(), txt, "\n");

return;
}

builder.Append(GetTimestamp(namesection_color == Color.IndianRed && txt_color == Color.IndianRed));

StringBuilder builder = new StringBuilder();

if (error)
builder.Append("[ERROR]".Pastel(Color.IndianRed));

builder.Append(GetTimestamp(error));

if (namesection is not null)
{
builder.Append("[".Pastel(Color.LightGray));
builder.Append("[".Pastel(error ? Color.IndianRed : Color.LightGray));
builder.Append(namesection.Pastel(namesection_color));
builder.Append("] ".Pastel(Color.LightGray));
builder.Append("] ".Pastel(error ? Color.IndianRed : Color.LightGray));
}

builder.Append(txt.Pastel(txt_color));
Console.WriteLine(builder.ToString());
}
[DllImport("Kernel32")]
internal static extern int SetConsoleTextAttribute(IntPtr hConsoleOutput, int wAttributes);

[DllImport("Kernel32")]
internal static extern IntPtr GetStdHandle(uint handleType);
internal static void WriteConsoleColor(params object[] oo)
{
foreach (var o in oo)
if (o == null)
Console.ResetColor();
else if (o is ConsoleColor color)
SetConsoleTextAttribute(GetStdHandle(4294967285), (int)color);
else
Console.Write(o.ToString());
}

internal static void WriteTimestampWine(bool error)
{
if (error)
{
WriteConsoleColor(ConsoleColor.Red, $"[{MelonUtils.TimeStamp}] ");
return;
}

WriteConsoleColor(ConsoleColor.Gray, $"[");
WriteConsoleColor(ConsoleColor.Green, MelonUtils.TimeStamp);
WriteConsoleColor(ConsoleColor.Gray, $"] ");
}

internal static string GetTimestamp(bool error)
{
Expand All @@ -159,17 +244,20 @@ internal static void Internal_Warning(string namesection, string txt)
}


internal static void Internal_Error(string namesection, string txt) => Internal_Msg(Color.IndianRed, Color.IndianRed, namesection, txt);
internal static void Internal_Error(string namesection, string txt) =>
Internal_Msg(Color.IndianRed, Color.IndianRed, namesection, txt, true);

public static void WriteSpacer()
{
BootstrapInterop.NativeWriteLogToFile("");
Console.WriteLine();
}

internal static void Internal_PrintModName(Color meloncolor, Color authorcolor, string name, string author, string additionalCredits, string version, string id)
internal static void Internal_PrintModName(Color meloncolor, Color authorcolor, string name, string author,
string additionalCredits, string version, string id)
{
BootstrapInterop.NativeWriteLogToFile($"[{MelonUtils.TimeStamp}] {name} v{version}{(id == null ? "" : $" ({id})")}");
BootstrapInterop.NativeWriteLogToFile(
$"[{MelonUtils.TimeStamp}] {name} v{version}{(id == null ? "" : $" ({id})")}");
BootstrapInterop.NativeWriteLogToFile($"[{MelonUtils.TimeStamp}] by {author}");

StringBuilder builder = new StringBuilder();
Expand All @@ -180,12 +268,13 @@ internal static void Internal_PrintModName(Color meloncolor, Color authorcolor,
builder.Append(GetTimestamp(false));
builder.Append($"by {author}".Pastel(authorcolor));

if (additionalCredits is not null) {
if (additionalCredits is not null)
{
builder.AppendLine();
builder.Append(GetTimestamp(false));
builder.Append($"Additional credits: {additionalCredits}");
}

Console.WriteLine(builder.ToString());
}
}
Expand Down
2 changes: 1 addition & 1 deletion Rust/MelonBootstrap/src/console/os/windows/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ pub unsafe fn init() -> Result<(), Box<dyn Error>> {

mode |= ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT;

if SetConsoleMode(*output_handle, mode).is_err() {
if SetConsoleMode(*output_handle, mode).is_err() {
mode &= !(ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT);
} else {
mode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
Expand Down

0 comments on commit 89612be

Please sign in to comment.