diff --git a/.gitignore b/.gitignore index 59fb2c28..259123b1 100644 --- a/.gitignore +++ b/.gitignore @@ -8,4 +8,5 @@ latest/windows/haxe/ .haxelib/ pages/ docs/doc.xml -mods/Baldi's Basics in Funkin'/ \ No newline at end of file +mods/Baldi's Basics in Funkin'/ +dev-libs/ \ No newline at end of file diff --git a/commandline/Utils.hx b/commandline/Utils.hx new file mode 100644 index 00000000..20216822 --- /dev/null +++ b/commandline/Utils.hx @@ -0,0 +1,69 @@ +package; + +using StringTools; + +class Utils { + // trace(evaluateArgsCondition("hello && (world || world)", ["hello", "world"])); // true + // trace(evaluateArgsCondition("hello && (!world || world)", ["hello"])); // true + // trace(evaluateArgsCondition("hello && (!world && world)", ["hello", "world"])); // false + public static function evaluateArgsCondition(condition:String, args:Array):Bool { + function evaluateToken(token:String):Bool { + if (token.charAt(0) == '!') { + return !args.contains(token.substr(1)); + } else { + return args.contains(token); + } + } + + condition = condition.replace('&&', '&').replace('||', '|').replace(" ", ""); + + var stack:Array = []; + var i = 0; + + while (i < condition.length) { + var char = condition.charAt(i); + + switch (char) { + case '(': + var j = i; + var balance = 1; + while (balance != 0) { + j++; + if (condition.charAt(j) == '(') balance++; + if (condition.charAt(j) == ')') balance--; + } + var subExpr = condition.substr(i + 1, j - i - 1); + stack.push(evaluateArgsCondition(subExpr, args)); + i = j; + case '&', '|': + stack.push(char); + default: + var token = ""; + while (i < condition.length && condition.charAt(i) != '&' && condition.charAt(i) != '|' && condition.charAt(i) != '(' && condition.charAt(i) != ')') { + token += condition.charAt(i); + i++; + } + stack.push(evaluateToken(token)); + i--; + } + i++; + } + + return evaluate(stack); + } + + public static function evaluate(stack:Array):Bool { + var result = stack.shift(); + while (stack.length > 0) { + var op = stack.shift(); + var next = stack.shift(); + switch(op) { + case '&': + result = result && next; + case '|': + result = result || next; + } + } + return result; + } +} diff --git a/commandline/commands/Compiler.hx b/commandline/commands/Compiler.hx index 6d09f5aa..5f573328 100644 --- a/commandline/commands/Compiler.hx +++ b/commandline/commands/Compiler.hx @@ -15,21 +15,19 @@ class Compiler { } private static function __build(args:Array, arg:Array) { + arg.insert(0, "lime"); + arg.insert(0, "run"); for(a in args) arg.push(a); - Sys.command("lime", arg); + Sys.command("haxelib", arg); } public static function getBuildTarget() { return switch(Sys.systemName()) { - case "Windows": - "windows"; - case "Mac": - "macos"; - case "Linux": - "linux"; - case def: - def.toLowerCase(); + case "Windows": "windows"; + case "Mac": "macos"; + case "Linux": "linux"; + case def: def.toLowerCase(); } } } \ No newline at end of file diff --git a/commandline/commands/Update.hx b/commandline/commands/Update.hx index 269b2035..36a790ad 100644 --- a/commandline/commands/Update.hx +++ b/commandline/commands/Update.hx @@ -8,11 +8,9 @@ import sys.FileSystem; class Update { public static function main(args:Array) { - prettyPrint("Preparing installation..."); - var args = ArgParser.parse(args, ["S" => "silent-progress", "silent" => "silent-progress"]); var CHECK_VSTUDIO = !args.existsOption("no-vscheck"); - var REINSTALL_ALL = args.existsOption("all"); + var REINSTALL_ALL = args.existsOption("reinstall"); var SILENT = args.existsOption("silent-progress"); // to prevent messing with currently installed libs @@ -24,44 +22,168 @@ class Update { FileSystem.createDirectory('.haxelib'); } - var libs:Array = []; - var libsXML:Access = new Access(Xml.parse(File.getContent('./libs.xml')).firstElement()); + var libFile = "./libs.xml"; + if(args.existsOption("lib")) { + libFile = args.getOption("lib"); + if(libFile == null) { + Sys.println('Please specify a file with the --lib option as --lib=path/to/libs.xml'); + return; + } + } + if(!FileSystem.exists(libFile)) { + Sys.println('File $libFile does not exist.'); + return; + } + + var events:Array = []; + var libsXML:Access = new Access(Xml.parse(File.getContent(libFile)).firstElement()); + + function handleLib(libNode:Access) { + switch(libNode.name) { + case "lib" | "git": + var lib:Library = { + name: libNode.att.name, + type: libNode.name + }; + if (libNode.has.global) lib.global = libNode.att.global; + switch (lib.type) { + case "lib": + if (libNode.has.version) lib.version = libNode.att.version; + case "git": + if (libNode.has.url) lib.url = libNode.att.url; + if (libNode.has.ref) lib.ref = libNode.att.ref; + } + events.push({ + type: INSTALL, + data: lib + }); + case "cmd": + + events.push({ + type: CMD, + data: { + inLib: libNode.has.inLib ? libNode.att.inLib : null, + lines: { + if(Lambda.count(libNode.nodes.line) > 0) + [ + for(line in libNode.nodes.line) + line.innerData + ]; + else + [ + libNode.has.cmd ? libNode.att.cmd : "echo 'No command specified'" + ]; + } + } + }); + case "print": + events.push({ + type: PRINT, + data: { + text: libNode.innerData, + pretty: libNode.has.pretty && libNode.att.pretty == "true" + } + }); + default: + Sys.println('Unknown library type ${libNode.name}'); + } + } + + var platform = switch(Sys.systemName()) { + case "Windows": "windows"; + case "Mac": "mac"; + case "Linux": "linux"; + case def: def.toLowerCase(); + } + + var defines = args.args.copy(); + defines.push(platform); + if(args.args.length == 0) defines.push("all"); + + function parse(libNode:Access) { + if(libNode.name == "if") { + var cond = libNode.att.cond; + if(!Utils.evaluateArgsCondition(cond, defines)) { + return; + } + + for(child in libNode.elements) { + parse(child); + } + } else { + handleLib(libNode); + } + } for (libNode in libsXML.elements) { - var lib:Library = { - name: libNode.att.name, - type: libNode.name - }; - if (libNode.has.global) lib.global = libNode.att.global; - switch (lib.type) { - case "lib": - if (libNode.has.version) lib.version = libNode.att.version; - case "git": - if (libNode.has.url) lib.url = libNode.att.url; - if (libNode.has.ref) lib.ref = libNode.att.ref; - } - libs.push(lib); + parse(libNode); } var commandSuffix = " --always"; if (SILENT) commandSuffix += " --silent"; - for(lib in libs) { - var globalism:Null = lib.global == "true" ? "--global" : null; - var globalSuffix = globalism != null ? ' $globalism' : ''; - switch(lib.type) { - case "lib": - prettyPrint((lib.global == "true" ? "Globally installing" : "Locally installing") + ' "${lib.name}"...'); - Sys.command('haxelib install ${lib.name} ${lib.version != null ? " " + lib.version : " "}$globalSuffix$commandSuffix'); - case "git": - prettyPrint((lib.global == "true" ? "Globally installing" : "Locally installing") + ' "${lib.name}" from git url "${lib.url}"'); - Sys.command('haxelib git ${lib.name} ${lib.url}${lib.ref != null ? ' ${lib.ref}' : ''}$globalSuffix$commandSuffix'); - default: - prettyPrint('Cannot resolve library of type "${lib.type}"'); + for(event in events) { + switch(event.type) { + case INSTALL: + var lib:Library = event.data; + var globalism:Null = lib.global == "true" ? "--global" : null; + var globalSuffix = globalism != null ? ' $globalism' : ''; + switch(lib.type) { + case "lib": + prettyPrint((lib.global == "true" ? "Globally installing" : "Locally installing") + ' "${lib.name}"...'); + Sys.command('haxelib install ${lib.name} ${lib.version != null ? " " + lib.version : " "}$globalSuffix$commandSuffix'); + case "git": + prettyPrint((lib.global == "true" ? "Globally installing" : "Locally installing") + ' "${lib.name}" from git url "${lib.url}"'); + Sys.command('haxelib git ${lib.name} ${lib.url}${lib.ref != null ? ' ${lib.ref}' : ''}$globalSuffix$commandSuffix'); + default: + prettyPrint('Cannot resolve library of type "${lib.type}"'); + } + case CMD: + var cmd:CmdData = event.data; + var lib = cmd.inLib; + var oldCwd = Sys.getCwd(); + if(lib != null) { + var libPrefix = '.haxelib/$lib'; + if(FileSystem.exists(libPrefix)) { + if(FileSystem.exists(libPrefix + '/.dev')) { // haxelib dev + var devPath = File.getContent(libPrefix + '/.dev'); + if(!FileSystem.exists(devPath)) { + Sys.println('Cannot find dev path $devPath for $lib'); + Sys.setCwd(oldCwd); + continue; + } + Sys.setCwd(devPath); + } else if(FileSystem.exists(libPrefix + '/.current')) { + var version = StringTools.replace(File.getContent(libPrefix + '/.current'), ".", ","); + if(!FileSystem.exists(libPrefix + '/$version')) { + Sys.println('Cannot find version $version of $lib'); + Sys.setCwd(oldCwd); + continue; + } + Sys.setCwd(libPrefix + '/$version'); + } else { + Sys.println('Cannot find .dev or .current file in $libPrefix'); + Sys.setCwd(oldCwd); + continue; + } + } + } + for(line in cmd.lines) { + var line = StringTools.replace(line, "$PLATFORM", platform); + //Sys.println(line); + Sys.command(line); + } + Sys.setCwd(oldCwd); + case PRINT: + var data:PrintData = event.data; + if(data.pretty) + prettyPrint(data.text); + else + Sys.println(data.text); } } - var proc = new Process('haxe --version'); + /*var proc = new Process('haxe --version'); proc.exitCode(true); var haxeVer = proc.stdout.readLine(); if (haxeVer != "4.2.5") { @@ -84,7 +206,7 @@ class Update { break; } } - } + }*/ // vswhere.exe its used to find any visual studio related installations on the system, including full visual studio ide installations, visual studio build tools installations, and other related components - Nex if (CHECK_VSTUDIO && Compiler.getBuildTarget().toLowerCase() == "windows" && new Process('"C:/Program Files (x86)/Microsoft Visual Studio/Installer/vswhere.exe" -property catalog_productDisplayVersion').exitCode(true) == 1) { @@ -142,3 +264,24 @@ typedef Library = { var ?ref:String; var ?url:String; } + +typedef Event = { + var type:EventType; + var data:Dynamic; +} + +typedef CmdData = { + var ?inLib:String; + var lines:Array; +} + +typedef PrintData = { + var text:String; + var ?pretty:Bool; +} + +enum abstract EventType(Int) { + var INSTALL = 0; + var CMD = 1; + var PRINT = 2; +} \ No newline at end of file diff --git a/libs.xml b/libs.xml index cfdec718..838a9991 100644 --- a/libs.xml +++ b/libs.xml @@ -1,22 +1,43 @@ - - - + + Preparing installation... - - - + + + - - - - - + + + - - - - - + + + + + + + + + + + + + + + + + + + + Building Lime... + + + + + cd tools + haxe tools.hxml + cd ..s + + diff --git a/setup-dev.xml b/setup-dev.xml new file mode 100644 index 00000000..dc2762ff --- /dev/null +++ b/setup-dev.xml @@ -0,0 +1,90 @@ + + + Setting up dev libs... + + + mkdir dev-libs + + + + + cd dev-libs + git clone https://github.com/FNF-CNE-Devs/openfl openfl + cd .. + haxelib dev openfl dev-libs/openfl + + + + + + cd dev-libs + git clone https://github.com/FNF-CNE-Devs/lime lime + cd .. + haxelib dev lime dev-libs/lime + + + + + + cd tools + haxe tools.hxml + cd ..s + + + + + + cd dev-libs + git clone https://github.com/FNF-CNE-Devs/flixel flixel + cd .. + haxelib dev flixel dev-libs/flixel + + + + + + cd dev-libs + git clone https://github.com/FNF-CNE-Devs/flixel-addons flixel-addons + cd .. + haxelib dev flixel-addons dev-libs/flixel-addons + + + + + + cd dev-libs + git clone https://github.com/FNF-CNE-Devs/hscript-improved hscript-improved + cd .. + haxelib dev hscript-improved dev-libs/hscript-improved + + + + + + cd dev-libs + git clone https://github.com/FNF-CNE-Devs/flxanimate flxanimate + cd .. + haxelib dev flxanimate dev-libs/flxanimate + + + + + + cd dev-libs + git clone https://github.com/FNF-CNE-Devs/hxdiscord_rpc hxdiscord_rpc + cd .. + haxelib dev hxdiscord_rpc dev-libs/hxdiscord_rpc + + + + + + cd dev-libs + git clone https://github.com/FNF-CNE-Devs/away3d away3d + cd .. + haxelib dev away3d dev-libs/away3d + + + + Setup for dev libs complete! + diff --git a/source/funkin/backend/assets/ModsFolderLibrary.hx b/source/funkin/backend/assets/ModsFolderLibrary.hx index be052548..c30b7270 100644 --- a/source/funkin/backend/assets/ModsFolderLibrary.hx +++ b/source/funkin/backend/assets/ModsFolderLibrary.hx @@ -18,7 +18,7 @@ class ModsFolderLibrary extends AssetLibrary implements IModsAssetLibrary { public var folderPath:String; public var modName:String; public var libName:String; - public var useImageCache:Bool = true; + //public var useImageCache:Bool = true; public var prefix = 'assets/'; public function new(folderPath:String, libName:String, ?modName:String) { diff --git a/source/lime/system/System.hx b/source/lime/system/System.hx index 59b71a83..98efafe3 100644 --- a/source/lime/system/System.hx +++ b/source/lime/system/System.hx @@ -25,6 +25,9 @@ import js.Browser; import sys.io.Process; #end +/** + Access operating system level settings and operations. +**/ #if !lime_debug @:fileXml('tags="haxe,release"') @:noDebug @@ -44,21 +47,68 @@ extern "C" { #end class System { + /** + Determines if the screen saver is allowed to start or not. + **/ public static var allowScreenTimeout(get, set):Bool; + + /** + The path to the directory where the application is installed, along with + its supporting files. In many cases, this directory is read-only, and + attempts to write to files, create new files, or delete files in this + directory are likely fail. + **/ public static var applicationDirectory(get, never):String; + + /** + The application's dedicated storage directory, which unique to each + application and user. Useful for storing settings on a user-specific + and application-specific basis. + + This directory may or may not be removed when the application is + uninstalled, and it depends on the platform and installer technology + that is used. + **/ public static var applicationStorageDirectory(get, never):String; + + /** + The path to the directory containing the user's desktop. + **/ public static var desktopDirectory(get, never):String; + public static var deviceModel(get, never):String; public static var deviceVendor(get, never):String; public static var disableCFFI:Bool; + + /** + The path to the directory containing the user's documents. + **/ public static var documentsDirectory(get, never):String; + + /** + The platform's default endianness for bytes. + **/ public static var endianness(get, never):Endian; + + /** + The path to the directory where fonts are installed. + **/ public static var fontsDirectory(get, never):String; + + /** + The number of available video displays. + **/ public static var numDisplays(get, never):Int; + public static var platformLabel(get, never):String; public static var platformName(get, never):String; public static var platformVersion(get, never):String; + + /** + The path to the user's home directory. + **/ public static var userDirectory(get, never):String; + @:noCompletion private static var __applicationDirectory:String; @:noCompletion private static var __applicationEntryPoint:Map; @:noCompletion private static var __applicationStorageDirectory:String; @@ -84,7 +134,7 @@ class System { var htmlElement:Element = null; - if (Std.is(element, String)) + if ((element is String)) { htmlElement = cast Browser.document.getElementById(element); } @@ -115,7 +165,7 @@ class System if (config == null) config = {}; - if (Reflect.hasField(config, "background") && Std.is(config.background, String)) + if (Reflect.hasField(config, "background") && (config.background is String)) { var background = StringTools.replace(Std.string(config.background), "#", ""); @@ -139,6 +189,10 @@ class System #end #if (!lime_doc_gen || sys) + /** + Attempts to exit the application. Dispatches `onExit`, and will not + exit if the event is canceled. + **/ public static function exit(code:Int):Void { var currentApp = Application.current; @@ -167,6 +221,9 @@ class System } #end + /** + Returns information about the video display with the specified ID. + **/ public static function getDisplay(id:Int):Display { #if (lime_cffi && !macro) @@ -265,11 +322,12 @@ class System return null; } + /** + The number of milliseconds since the application was initialized. + **/ public static function getTimer():Int { - #if (kha && !macro) - return Std.int(kha.System.time * 1000); - #elseif flash + #if flash return flash.Lib.getTimer(); #elseif ((js && !nodejs) || electron) return Std.int(Browser.window.performance.now()); @@ -295,6 +353,11 @@ class System } #end + /** + Opens a file with the suste, default application. + + In a web browser, opens a URL with target `_blank`. + **/ public static function openFile(path:String):Void { if (path != null) @@ -304,7 +367,7 @@ class System #elseif mac Sys.command("/usr/bin/open", [path]); #elseif linux - Sys.command("/usr/bin/xdg-open", [path, "&"]); + Sys.command("/usr/bin/xdg-open", [path]); #elseif (js && html5) Browser.window.open(path, "_blank"); #elseif flash @@ -318,6 +381,9 @@ class System } } + /** + Opens a URL with the specified target web browser window. + **/ public static function openURL(url:String, target:String = "_blank"):Void { if (url != null) @@ -430,6 +496,8 @@ class System #if sys private static function __parseArguments(attributes:WindowAttributes):Void { + // TODO: Handle default arguments, like --window-fps=60 + var arguments = Sys.args(); var stripQuotes = ~/^['"](.*)['"]$/; var equals, argValue, parameters = null; @@ -825,7 +893,7 @@ class System } } -enum abstract SystemDirectory(Int) from Int to Int from UInt to UInt +#if (haxe_ver >= 4.0) enum #else @:enum #end abstract SystemDirectory(Int) from Int to Int from UInt to UInt { var APPLICATION = 0; var APPLICATION_STORAGE = 1; diff --git a/source/lime/utils/Log.hx b/source/lime/utils/Log.hx index 633cc71c..de13c040 100644 --- a/source/lime/utils/Log.hx +++ b/source/lime/utils/Log.hx @@ -12,17 +12,17 @@ import funkin.backend.system.Logs as FunkinLogs; class Log { public static var level:LogLevel; + public static var throwErrors:Bool = false; public static function debug(message:Dynamic, ?info:PosInfos):Void { if (level >= LogLevel.DEBUG) { #if js - untyped __js__("console").debug("[" + info.className + "] " + message); + untyped #if haxe4 js.Syntax.code #else __js__ #end ("console").debug("[" + info.className + "] " + message); #else println("[" + info.className + "] " + Std.string(message)); #end - } } @@ -30,23 +30,32 @@ class Log { if (level >= LogLevel.ERROR) { - var message = '[${info.className}] $message'; - - #if !macro - FunkinLogs.trace(message, ERROR, RED); - #else - trace(message); - #end + if (throwErrors) + { + #if webassembly + println(message); + #end + throw message; + } + else + { + #if !macro + FunkinLogs.trace('[${info.className}] $message', ERROR, RED); + #else + println("[" + info.className + "] ERROR: " + message); + #end + } } } public static function info(message:Dynamic, ?info:PosInfos):Void { - if (level >= LogLevel.INFO) { + if (level >= LogLevel.INFO) + { #if !macro FunkinLogs.trace('[${info.className}] $message', INFO, RED); #else - trace('[${info.className}] $message'); + println("[" + info.className + "] " + Std.string(message)); #end } } @@ -58,7 +67,7 @@ class Log #elseif flash untyped __global__["trace"](Std.string(message)); #elseif js - untyped __js__("console").log(message); + untyped #if haxe4 js.Syntax.code #else __js__ #end ("console").log(message); #else trace(message); #end @@ -71,7 +80,7 @@ class Log #elseif flash untyped __global__["trace"](Std.string(message)); #elseif js - untyped __js__("console").log(message); + untyped #if haxe4 js.Syntax.code #else __js__ #end ("console").log(message); #else trace(Std.string(message)); #end @@ -79,11 +88,12 @@ class Log public static function verbose(message:Dynamic, ?info:PosInfos):Void { - if (level >= LogLevel.VERBOSE) { + if (level >= LogLevel.VERBOSE) + { #if !macro FunkinLogs.trace('[${info.className}] $message', VERBOSE); #else - trace('[${info.className}] $message'); + println("[" + info.className + "] " + message); #end } } @@ -95,7 +105,7 @@ class Log #if !macro FunkinLogs.trace('[${info.className}] $message', WARNING, YELLOW); #else - trace('[${info.className}] $message'); + println("[" + info.className + "] WARNING: " + Std.string(message)); #end } } @@ -125,13 +135,13 @@ class Log #end #if js - if (untyped __js__("typeof console") == "undefined") + if (untyped #if haxe4 js.Syntax.code #else __js__ #end ("typeof console") == "undefined") { - untyped __js__("console = {}"); + untyped #if haxe4 js.Syntax.code #else __js__ #end ("console = {}"); } - if (untyped __js__("console").log == null) + if (untyped #if haxe4 js.Syntax.code #else __js__ #end ("console").log == null) { - untyped __js__("console").log = function() {}; + untyped #if haxe4 js.Syntax.code #else __js__ #end ("console").log = function() {}; } #end }