diff --git a/buildnumber.txt b/buildnumber.txt index 9a32da21..d8292c28 100644 --- a/buildnumber.txt +++ b/buildnumber.txt @@ -1 +1 @@ -984 \ No newline at end of file +996 \ No newline at end of file diff --git a/source/funkin/desktop/theme/Theme.hx b/source/funkin/desktop/theme/Theme.hx index d52bc15d..fb10beed 100644 --- a/source/funkin/desktop/theme/Theme.hx +++ b/source/funkin/desktop/theme/Theme.hx @@ -81,8 +81,7 @@ class Theme { } } catch(e) { - // TODO: logs system - trace(e.details()); + Logs.trace('Failed to load Desktop Theme: $e', ERROR); } } } diff --git a/source/funkin/game/Stage.hx b/source/funkin/game/Stage.hx index 08fe6cce..db31ab38 100644 --- a/source/funkin/game/Stage.hx +++ b/source/funkin/game/Stage.hx @@ -117,7 +117,6 @@ class Stage extends FlxBasic implements IBeatReceiver { } if (sprite != null) { for(e in node.nodes.property) { - // TODO: Proper logging system XMLUtil.applyXMLProperty(sprite, e); } } diff --git a/source/funkin/import.hx b/source/funkin/import.hx index f027a37e..82b5a17c 100644 --- a/source/funkin/import.hx +++ b/source/funkin/import.hx @@ -3,6 +3,7 @@ import funkin.system.Paths; import funkin.system.MusicBeatState; import funkin.system.MusicBeatSubstate; import funkin.system.CoolUtil; +import funkin.system.Logs; import funkin.game.PlayState; using StringTools; diff --git a/source/funkin/menus/TitleState.hx b/source/funkin/menus/TitleState.hx index 652fc7bf..bf8f9016 100644 --- a/source/funkin/menus/TitleState.hx +++ b/source/funkin/menus/TitleState.hx @@ -305,8 +305,7 @@ class TitleState extends MusicBeatState } } } catch(e) { - // TODO: Logging!! - trace(e.details()); + Logs.trace('Failed to load titlescreen XML: $e', ERROR); } } #end diff --git a/source/funkin/options/OptionsMenu.hx b/source/funkin/options/OptionsMenu.hx index 507ebdb0..c47bd582 100644 --- a/source/funkin/options/OptionsMenu.hx +++ b/source/funkin/options/OptionsMenu.hx @@ -39,6 +39,11 @@ class OptionsMenu extends MusicBeatState { name: 'Save Data', desc: 'Use this menu to reset save data or engine settings.', state: SaveDataOptions + }, + { + name: 'Debug Options', + desc: 'Use this menu to change debug options.', + state: DebugOptions } ]; diff --git a/source/funkin/options/categories/DebugOptions.hx b/source/funkin/options/categories/DebugOptions.hx new file mode 100644 index 00000000..a01dbe2e --- /dev/null +++ b/source/funkin/options/categories/DebugOptions.hx @@ -0,0 +1,19 @@ +package funkin.options.categories; + +import funkin.windows.WindowsAPI; + +class DebugOptions extends OptionsScreen { + public override function create() { + options = [ + #if windows + new TextOption( + "Show Console", + "Select this to show the debug console, which contains log information about the game.", + function() { + WindowsAPI.allocConsole(); + }), + #end + ]; + super.create(); + } +} \ No newline at end of file diff --git a/source/funkin/scripting/HScript.hx b/source/funkin/scripting/HScript.hx index 9f008826..3a87ef62 100644 --- a/source/funkin/scripting/HScript.hx +++ b/source/funkin/scripting/HScript.hx @@ -17,6 +17,7 @@ class HScript extends Script { var parser = new hscript.Parser(); parser.allowJSON = parser.allowMetadata = parser.allowTypes = true; interp.errorHandler = _errorHandler; + interp.variables.set("trace", this.trace); try { expr = parser.parseString(code, fileName); } catch(e) { @@ -70,4 +71,12 @@ class HScript extends Script { public override function set(val:String, value:Dynamic) { interp.variables.set(val, value); } + + public override function trace(v:Dynamic) { + var posInfo = interp.posInfos(); + Logs.traceColored([ + Logs.logText('${fileName}:${posInfo.lineNumber}: ', GREEN), + Logs.logText(Std.string(v)) + ], TRACE); + } } \ No newline at end of file diff --git a/source/funkin/scripting/Script.hx b/source/funkin/scripting/Script.hx index 7fa4c737..598dc0dd 100644 --- a/source/funkin/scripting/Script.hx +++ b/source/funkin/scripting/Script.hx @@ -135,6 +135,17 @@ class Script extends FlxBasic implements IFlxDestroyable { } + /** + * Traces something as this script. + */ + public function trace(v:Dynamic) { + Logs.traceColored([ + Logs.logText('${fileName}: ', GREEN), + Logs.logText(Std.string(v)) + ], TRACE); + } + + /** * Calls the function `func` defined in the script. * @param func Name of the function @@ -177,8 +188,10 @@ class Script extends FlxBasic implements IFlxDestroyable { * @param additionalInfo Additional information you could provide. */ public function error(text:String, ?additionalInfo:Dynamic):Void { - // TODO: Logs (like on YCE) - trace('$text'); + Logs.traceColored([ + Logs.logText(fileName, GREEN), + Logs.logText(text) + ], ERROR); } /** diff --git a/source/funkin/system/Logs.hx b/source/funkin/system/Logs.hx new file mode 100644 index 00000000..df6f2de6 --- /dev/null +++ b/source/funkin/system/Logs.hx @@ -0,0 +1,87 @@ +package funkin.system; + +import haxe.Log; +import funkin.windows.WindowsAPI; +import funkin.windows.WindowsAPI.ConsoleColor; + +class Logs { + private static var __showing:Bool = false; + public static function init() { + __showInConsole([ + logText("Hello, World! ", CYAN), + logText("I am..."), + logText("COLORED!!", RED)]); + + Log.trace = function(v : Dynamic, ?infos : Null) { + __showInConsole(prepareColoredTrace([ + logText('${infos.fileName}:${infos.lineNumber}: ', CYAN), + logText(Std.string(v)) + ], TRACE)); + }; + } + + public static function prepareColoredTrace(text:Array, level:Level = INFO) { + var time = Date.now(); + var superCoolText = [ + logText('[ '), + logText('${Std.string(time.getHours()).addZeros(2)}:${Std.string(time.getMinutes()).addZeros(2)}:${Std.string(time.getSeconds()).addZeros(2)}', DARKMAGENTA), + logText(' |'), + switch(level) { + case WARNING: logText(' WARNING ', DARKYELLOW); + case ERROR: logText(' ERROR ', DARKRED); + case TRACE: logText(' TRACE ', GRAY); + default: logText(' INFORMATION ', CYAN); + }, + logText('] ') + ]; + for(k=>e in superCoolText) + text.insert(k, e); + return text; + } + + public static function logText(text:String, color:ConsoleColor = LIGHTGRAY):LogText { + return { + text: text, + color: color + }; + } + + public static function __showInConsole(text:Array) { + #if sys + while(__showing) { + Sys.sleep(0.05); + } + __showing = true; + for(t in text) { + WindowsAPI.setConsoleColors(t.color); + Sys.print(t.text); + } + WindowsAPI.setConsoleColors(); + Sys.print("\r\n"); + __showing = false; + #else + trace(text); + #end + } + + public static function traceColored(text:Array, level:Level = INFO) { + __showInConsole(prepareColoredTrace(text, level)); + } + public static function trace(text:String, level:Level = INFO, color:ConsoleColor = LIGHTGRAY) { + traceColored([{ + text: text, + color: color + }], level); + } +} + +enum abstract Level(Int) { + var INFO = 0; + var WARNING = 1; + var ERROR = 2; + var TRACE = 3; +} +typedef LogText = { + var text:String; + var color:ConsoleColor; +} \ No newline at end of file diff --git a/source/funkin/system/Main.hx b/source/funkin/system/Main.hx index e80f81a0..adb56996 100644 --- a/source/funkin/system/Main.hx +++ b/source/funkin/system/Main.hx @@ -112,6 +112,8 @@ class Main extends Sprite ModsFolder.loadMod("introMod"); ModsFolder.currentModFolder = "introMod"; + Logs.init(); + #if sys if (Sys.args().contains("-livereload")) { trace("Used lime test windows. Switching into source assets."); diff --git a/source/funkin/system/XMLUtil.hx b/source/funkin/system/XMLUtil.hx index e2c212bc..24ea0f16 100644 --- a/source/funkin/system/XMLUtil.hx +++ b/source/funkin/system/XMLUtil.hx @@ -17,7 +17,7 @@ class XMLUtil { */ public static function applyXMLProperty(object:Dynamic, property:Access):ErrorCode { if (!property.has.name || !property.has.type || !property.has.value) { - // TODO: show in logs + Logs.trace('Failed to apply XML property: XML Element misses name, type, or value attributes.', WARNING); return MISSING_PROPERTY; } @@ -33,8 +33,7 @@ class XMLUtil { try { Reflect.setProperty(object, property.att.name, value); } catch(e) { - // TODO: Correct Logs - trace(e); + Logs.trace('Failed to apply XML property: $e on ${Type.getClass(object)}', WARNING); return REFLECT_ERROR; } return OK; diff --git a/source/funkin/windows/WindowsAPI.hx b/source/funkin/windows/WindowsAPI.hx index d21ab0b0..fcaa58f9 100644 --- a/source/funkin/windows/WindowsAPI.hx +++ b/source/funkin/windows/WindowsAPI.hx @@ -19,6 +19,7 @@ class WindowsAPI { public static function allocConsole() { #if windows native.WinAPI.allocConsole(); + native.WinAPI.clearScreen(); #end } @@ -30,4 +31,55 @@ class WindowsAPI { native.WinAPI.setDarkMode(enable); #end } + + /** + * Sets the console colors + */ + public static function setConsoleColors(foregroundColor:ConsoleColor = LIGHTGRAY, ?backgroundColor:ConsoleColor = BLACK) { + #if windows + var fg = cast(foregroundColor, Int); + var bg = cast(backgroundColor, Int); + native.WinAPI.setConsoleColors((bg * 16) + fg); + #end + } + + public static function consoleColorToOpenFL(color:ConsoleColor) { + return switch(color) { + case BLACK: 0xFF000000; + case DARKBLUE: 0xFF000088; + case DARKGREEN: 0xFF008800; + case DARKCYAN: 0xFF008888; + case DARKRED: 0xFF880000; + case DARKMAGENTA: 0xFF880000; + case DARKYELLOW: 0xFF888800; + case LIGHTGRAY: 0xFFBBBBBB; + case GRAY: 0xFF888888; + case BLUE: 0xFF0000FF; + case GREEN: 0xFF00FF00; + case CYAN: 0xFF00FFFF; + case RED: 0xFFFF0000; + case MAGENTA: 0xFFFF00FF; + case YELLOW: 0xFFFFFF00; + case WHITE | _: 0xFFFFFFFF; + } + } +} + +@:enum abstract ConsoleColor(Int) { + var BLACK:ConsoleColor = 0; + var DARKBLUE:ConsoleColor = 1; + var DARKGREEN:ConsoleColor = 2; + var DARKCYAN:ConsoleColor = 3; + var DARKRED:ConsoleColor = 4; + var DARKMAGENTA:ConsoleColor = 5; + var DARKYELLOW:ConsoleColor = 6; + var LIGHTGRAY:ConsoleColor = 7; + var GRAY:ConsoleColor = 8; + var BLUE:ConsoleColor = 9; + var GREEN:ConsoleColor = 10; + var CYAN:ConsoleColor = 11; + var RED:ConsoleColor = 12; + var MAGENTA:ConsoleColor = 13; + var YELLOW:ConsoleColor = 14; + var WHITE:ConsoleColor = 15; } \ No newline at end of file diff --git a/source/native/WinAPI.hx b/source/native/WinAPI.hx index c6ab3d63..33ee9878 100644 --- a/source/native/WinAPI.hx +++ b/source/native/WinAPI.hx @@ -142,31 +142,32 @@ class WinAPI { if (!AllocConsole()) return; - FILE* fDummy; - freopen_s(&fDummy, "CONOUT$", "w", stdout); - freopen_s(&fDummy, "CONOUT$", "w", stderr); - freopen_s(&fDummy, "CONIN$", "r", stdin); - std::cout.clear(); - std::clog.clear(); - std::cerr.clear(); - std::cin.clear(); - - // std::wcout, std::wclog, std::wcerr, std::wcin - HANDLE hConOut = CreateFile(_T("CONOUT$"), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); - HANDLE hConIn = CreateFile(_T("CONIN$"), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); - SetStdHandle(STD_OUTPUT_HANDLE, hConOut); - SetStdHandle(STD_ERROR_HANDLE, hConOut); - SetStdHandle(STD_INPUT_HANDLE, hConIn); - std::wcout.clear(); - std::wclog.clear(); - std::wcerr.clear(); - std::wcin.clear(); + freopen("CONIN$", "r", stdin); + freopen("CONOUT$", "w", stdout); + freopen("CONOUT$", "w", stderr); ') public static function allocConsole() { - // LogsOverlay.consoleOpened = LogsOverlay.consoleVisible = true; - haxe.Log.trace = function(v:Dynamic, ?infos:haxe.PosInfos) { - // nothing here so that it keeps shit clean - } + } + + + #if windows + @:functionCode(' + HANDLE console = GetStdHandle(STD_OUTPUT_HANDLE); + SetConsoleTextAttribute(console, color); + ') + #end + public static function setConsoleColors(color:Int) { + + } + + #if windows + @:functionCode(' + system("CLS"); + std::cout<< "" <