diff --git a/source/funkin/backend/assets/AssetsLibraryList.hx b/source/funkin/backend/assets/AssetsLibraryList.hx index 096c82dc9..744feed29 100644 --- a/source/funkin/backend/assets/AssetsLibraryList.hx +++ b/source/funkin/backend/assets/AssetsLibraryList.hx @@ -100,15 +100,11 @@ class AssetsLibraryList extends AssetLibrary { public function getSpecificAsset(id:String, type:String, source:AssetSource = BOTH, ?avoidRoot:Bool = false):Dynamic { try { - var fileFromAssets:Bool = id.startsWith("assets/"); - - if (!fileFromAssets) { + if (!id.startsWith("assets/")) { var ass = getSpecificAsset('assets/$id', type, source); if (ass != null) return ass; - } - - if (fileFromAssets) { + } else { for (lib in assetsLibs) { if (shouldSkipLib(libraries.indexOf(lib), source)) continue; @@ -116,7 +112,9 @@ class AssetsLibraryList extends AssetLibrary { if (asset != null) return asset; } - } else if (!avoidRoot) { + } + + if (!avoidRoot) { for (lib in rootLibs) { if (shouldSkipLib(libraries.indexOf(lib), source)) continue; @@ -182,7 +180,7 @@ class AssetsLibraryList extends AssetLibrary { if (finalLib is IModsAssetLibrary) assetsLibs.insert(0, finalLib); - else + else rootLibs.insert(0, finalLib); return lib; } diff --git a/source/funkin/backend/system/github/GitHub.hx b/source/funkin/backend/system/github/GitHub.hx index 13e1d9441..eeb535c56 100644 --- a/source/funkin/backend/system/github/GitHub.hx +++ b/source/funkin/backend/system/github/GitHub.hx @@ -4,71 +4,123 @@ package funkin.backend.system.github; import haxe.Json; import haxe.Exception; import haxe.Http; +#end // TODO: Document further and perhaps make this a Haxelib. class GitHub { /** * Gets all the releases from a specific GitHub repository using the GitHub API. - * @param user The user/group that owns the repository + * @param user The user/organization that owns the repository * @param repository The repository name + * @param onError Error Callback * @return Releases */ public static function getReleases(user:String, repository:String, ?onError:Exception->Void):Array { + #if GITHUB_API try { - var url = 'https://api.github.com/repos/${user}/${repository}/releases'; - - var data = Json.parse(__requestOnGitHubServers(url)); + var data = Json.parse(__requestOnGitHubServers('https://api.github.com/repos/${user}/${repository}/releases')); if (!(data is Array)) throw __parseGitHubException(data); - + return data; } catch(e) { if (onError != null) onError(e); } + #end return []; } /** * Gets the contributors list from a specific GitHub repository using the GitHub API. - * @param user The user/group that owns the repository + * @param user The user/organization that owns the repository * @param repository The repository name + * @param onError Error Callback * @return Contributors List */ public static function getContributors(user:String, repository:String, ?onError:Exception->Void):Array { + #if GITHUB_API try { - var url = 'https://api.github.com/repos/${user}/${repository}/contributors'; - - var data = Json.parse(__requestOnGitHubServers(url)); + var data = Json.parse(__requestOnGitHubServers('https://api.github.com/repos/${user}/${repository}/contributors')); if (!(data is Array)) throw __parseGitHubException(data); - + return data; } catch(e) { if (onError != null) onError(e); } + #end return []; } /** - * Gets a specific GitHub user/group using the GitHub API. - * @param user The user/group to get - * @return User/Group + * Gets a specific GitHub organization using the GitHub API. + * @param org The organization to get + * @param onError Error Callback + * @return Organization + */ + public static function getOrganization(org:String, ?onError:Exception->Void):GitHubOrganization { + #if GITHUB_API + try { + var data = Json.parse(__requestOnGitHubServers('https://api.github.com/orgs/$org')); + if (Reflect.hasField(data, "documentation_url")) + throw __parseGitHubException(data); + + return data; + } catch(e) { + if (onError != null) + onError(e); + } + #end + return null; + } + + /** + * Gets the members list from a specific GitHub organization using the GitHub API. + * NOTE: Members use Contributors' structure! + * @param org The organization to get the members from + * @param onError Error Callback + * @return Members List */ - public static function getUser(user:String, ?onError:Exception->Void):GitHubUser { + public static function getOrganizationMembers(org:String, ?onError:Exception->Void):Array { + #if GITHUB_API + try { + var data = Json.parse(__requestOnGitHubServers('https://api.github.com/orgs/$org/members')); + if (Reflect.hasField(data, "documentation_url")) + throw __parseGitHubException(data); + + return data; + } catch(e) { + if (onError != null) + onError(e); + } + #end + return []; + } + + /** + * Gets a specific GitHub user/organization using the GitHub API. + * NOTE: If organization, it will be returned with the structure of a normal user; use `getOrganization` if you specifically want an organization! + * @param user The user/organization to get + * @param onError Error Callback + * @return User/Organization + */ + public static function getUser(user:String, ?onError:Exception->Void):GitHubUser { + #if GITHUB_API try { var url = 'https://api.github.com/users/$user'; var data = Json.parse(__requestOnGitHubServers(url)); if (Reflect.hasField(data, "documentation_url")) throw __parseGitHubException(data); - + return data; } catch(e) { if (onError != null) onError(e); } + #end return null; } @@ -80,13 +132,14 @@ class GitHub { * @return Filtered releases. */ public static inline function filterReleases(releases:Array, keepPrereleases:Bool = true, keepDrafts:Bool = false) - return [for(release in releases) if (release != null && (!release.prerelease || (release.prerelease && keepPrereleases)) && (!release.draft || (release.draft && keepDrafts))) release]; + return #if GITHUB_API [for(release in releases) if (release != null && (!release.prerelease || (release.prerelease && keepPrereleases)) && (!release.draft || (release.draft && keepDrafts))) release] #else releases #end; public static function __requestOnGitHubServers(url:String) { + var r = null; + #if GITHUB_API var h = new Http(url); h.setHeader("User-Agent", "request"); - var r = null; h.onStatus = function(s) { if(isRedirect(s)) r = __requestOnGitHubServers(h.responseHeaders.get("Location")); @@ -100,13 +153,15 @@ class GitHub { } h.request(false); + #end return r; } public static function __requestBytesOnGitHubServers(url:String) { + var r = null; + #if GITHUB_API var h = new Http(url); h.setHeader("User-Agent", "request"); - var r = null; h.onStatus = function(s) { if(isRedirect(s)) r = __requestBytesOnGitHubServers(h.responseHeaders.get("Location")); @@ -120,6 +175,7 @@ class GitHub { } h.request(false); + #end return r; } private static function isRedirect(status:Int):Bool { @@ -132,6 +188,7 @@ class GitHub { return false; } private static function __parseGitHubException(obj:Dynamic):GitHubException { + #if GITHUB_API var msg:String = "(No message)"; var url:String = "(No API url)"; if (Reflect.hasField(obj, "message")) @@ -139,70 +196,8 @@ class GitHub { if (Reflect.hasField(obj, "documentation_url")) url = Reflect.field(obj, "documentation_url"); return new GitHubException(msg, url); - } -} - -#else -import haxe.Json; -import haxe.Exception; - -class GitHub { - /** - * Gets all the releases from a specific GitHub repository using the GitHub API. - * @param user The user/group that owns the repository - * @param repository The repository name - * @return Releases - */ - public static function getReleases(user:String, repository:String, ?onError:Exception->Void):Array { - return []; - } - - /** - * Gets the contributors list from a specific GitHub repository using the GitHub API. - * @param user The user/group that owns the repository - * @param repository The repository name - * @return Contributors List - */ - public static function getContributors(user:String, repository:String, ?onError:Exception->Void):Array { - return []; - } - - /** - * Gets a specific GitHub user/group using the GitHub API. - * @param user The user/group to get - * @return User/Group - */ - public static function getUser(user:String, ?onError:Exception->Void):GitHubUser { - return null; - } - - /** - * Filters all releases gotten by `getReleases` - * @param releases Releases - * @param keepPrereleases Whenever to keep Pre-Releases. - * @param keepDrafts Whenever to keep Drafts. - * @return Filtered releases. - */ - public static inline function filterReleases(releases:Array, keepPrereleases:Bool = true, keepDrafts:Bool = false) - return releases; - - public static function __requestOnGitHubServers(url:String) { - return null; - } - public static function __requestBytesOnGitHubServers(url:String) { + #else return null; + #end } - private static function __parseGitHubException(obj:Dynamic):GitHubException { - return null; - } - private static function isRedirect(status:Int):Bool { - switch (status) { - // 301: Moved Permanently, 302: Found (Moved Temporarily), 307: Temporary Redirect, 308: Permanent Redirect - Nex - case 301 | 302 | 307 | 308 : - trace("Redirected with status code: " + status); - return true; - } - return false; - } -} -#end \ No newline at end of file +} \ No newline at end of file diff --git a/source/funkin/backend/system/github/GitHubContributor.hx b/source/funkin/backend/system/github/GitHubContributor.hx index 85576935c..1b454e29c 100644 --- a/source/funkin/backend/system/github/GitHubContributor.hx +++ b/source/funkin/backend/system/github/GitHubContributor.hx @@ -1,5 +1,6 @@ package funkin.backend.system.github; +// Also used by Organizations for members! typedef GitHubContributor = { var login:String; var id:Int; diff --git a/source/funkin/backend/system/github/GitHubOrganization.hx b/source/funkin/backend/system/github/GitHubOrganization.hx new file mode 100644 index 000000000..529285790 --- /dev/null +++ b/source/funkin/backend/system/github/GitHubOrganization.hx @@ -0,0 +1,36 @@ +package funkin.backend.system.github; + +import funkin.backend.system.github.GitHubUser.GitHubUserType; + +typedef GitHubOrganization = { + var login:String; + var id:Int; + var node_id:String; + var url:String; + var repos_url:String; + var events_url:String; + var hooks_url:String; + var issues_url:String; + var members_url:String; + var public_members_url:String; + var avatar_url:String; + var description:String; + var name:String; + var company:String; + var blog:String; + var location:String; + var email:String; + var twitter_username:String; + var is_verified:Bool; + var has_organization_projects:Bool; + var has_repository_projects:Bool; + var public_repos:Int; + var public_gists:Int; + var followers:Int; + var following:Int; + var html_url:String; + var created_at:String; + var updated_at:String; + var archived_at:String; + var type:GitHubUserType; +} \ No newline at end of file diff --git a/source/funkin/menus/BetaWarningState.hx b/source/funkin/menus/BetaWarningState.hx index e374dda76..2f234f5a9 100644 --- a/source/funkin/menus/BetaWarningState.hx +++ b/source/funkin/menus/BetaWarningState.hx @@ -20,7 +20,7 @@ class BetaWarningState extends MusicBeatState { disclaimer = new FunkinText(16, titleAlphabet.y + titleAlphabet.height + 10, FlxG.width - 32, "", 32); disclaimer.alignment = CENTER; - disclaimer.applyMarkup("This engine is still in a alpha state. That means *majority of the features* are either *buggy* or *non finished*. If you find any bugs, please report them to the Codename Engine GitHub.\n\nPress ENTER to continue", + disclaimer.applyMarkup("This engine is still in a beta state. That means *majority of the features* are either *buggy* or *non finished*. If you find any bugs, please report them to the Codename Engine GitHub.\n\nPress ENTER to continue", [ new FlxTextFormatMarkerPair(new FlxTextFormat(0xFFFF4444), "*") ] diff --git a/source/funkin/menus/credits/CreditsCodename.hx b/source/funkin/menus/credits/CreditsCodename.hx index ab434d4f0..2a9dd42bc 100644 --- a/source/funkin/menus/credits/CreditsCodename.hx +++ b/source/funkin/menus/credits/CreditsCodename.hx @@ -2,11 +2,13 @@ package funkin.menus.credits; import funkin.backend.system.github.GitHub; import funkin.options.type.GithubIconOption; +import flixel.text.FlxText; using StringTools; class CreditsCodename extends funkin.options.OptionsScreen { public var error:Bool = false; + public var author:String = "FNF-CNE-Devs"; public override function new() { @@ -23,6 +25,11 @@ class CreditsCodename extends funkin.options.OptionsScreen { super.update(elapsed); } + public override function updateMenuDesc(?txt:String) { + super.updateMenuDesc(txt); + parent.treeParent.pathDesc.applyMarkup(parent.treeParent.pathDesc.text, [new FlxTextFormatMarkerPair(new FlxTextFormat(0xFF9C35D5), "*")]); + } + public function checkUpdate():Bool { var curTime:Float = Date.now().getTime(); if(Options.lastUpdated != null && curTime < Options.lastUpdated + 120000) return false; // Fuck you Github rate limits @@ -30,7 +37,7 @@ class CreditsCodename extends funkin.options.OptionsScreen { error = false; //Main.execAsync(function() { - var idk = GitHub.getContributors("FNF-CNE-Devs", "CodenameEngine", function(e) { + var idk = GitHub.getContributors(author, "CodenameEngine", function(e) { error = true; var errMsg:String = 'Error while trying to download contributors list:\n${CoolUtil.removeIP(e.message)}'; Logs.traceColored([Logs.logText(errMsg.replace('\n', ' '), RED)], ERROR); @@ -38,9 +45,18 @@ class CreditsCodename extends funkin.options.OptionsScreen { }); //}); if(error) return false; - Options.contributors = idk; trace('List Updated!'); + + var errorOnMain:Bool = false; + var idk2 = GitHub.getOrganizationMembers(author, function(e) { + errorOnMain = true; + var errMsg:String = 'Error while trying to download $author members list:\n${CoolUtil.removeIP(e.message)}'; + Logs.traceColored([Logs.logText(errMsg.replace('\n', ' '), RED)], ERROR); + funkin.backend.utils.NativeAPI.showMessageBox("Codename Engine Warning", errMsg, MSG_WARNING); + }); + if(!errorOnMain) Options.mainDevs = [for(m in idk2) m.id]; + return true; } @@ -57,10 +73,9 @@ class CreditsCodename extends funkin.options.OptionsScreen { var totalContributions = 0; for(c in Options.contributors) totalContributions += c.contributions; for(c in Options.contributors) { - var opt:GithubIconOption = new GithubIconOption( - c, - 'Total Contributions: ${c.contributions} / ${totalContributions} (${FlxMath.roundDecimal(c.contributions / totalContributions * 100, 2)}%) - Select to open GitHub account' - ); + var desc:String = 'Total Contributions: ${c.contributions} / ${totalContributions} (${FlxMath.roundDecimal(c.contributions / totalContributions * 100, 2)}%) - Select to open GitHub account'; + if(Options.mainDevs.contains(c.id)) desc += " *- Public member of the main Devs!*"; + var opt:GithubIconOption = new GithubIconOption(c, desc); add(opt); } } diff --git a/source/funkin/menus/credits/CreditsMain.hx b/source/funkin/menus/credits/CreditsMain.hx index a7edeb689..af62af374 100644 --- a/source/funkin/menus/credits/CreditsMain.hx +++ b/source/funkin/menus/credits/CreditsMain.hx @@ -20,11 +20,12 @@ class CreditsMain extends TreeMenu { add(bg); var selectables:Array = []; + var xmlPath = Paths.xml('config/credits'); for(source in [funkin.backend.assets.AssetsLibraryList.AssetSource.SOURCE, funkin.backend.assets.AssetsLibraryList.AssetSource.MODS]) { - if (Paths.assetsTree.existsSpecific(Paths.xml('config/credits'), "TEXT", source)) { + if (Paths.assetsTree.existsSpecific(xmlPath, "TEXT", source)) { var access:Access = null; try { - access = new Access(Xml.parse(Paths.assetsTree.getSpecificAsset(Paths.xml('config/credits'), "TEXT", source))); + access = new Access(Xml.parse(Paths.assetsTree.getSpecificAsset(xmlPath, "TEXT", source))); } catch(e) { Logs.trace('Error while parsing credits.xml: ${Std.string(e)}', ERROR); } diff --git a/source/funkin/options/Options.hx b/source/funkin/options/Options.hx index ccfb498c5..1104bae71 100644 --- a/source/funkin/options/Options.hx +++ b/source/funkin/options/Options.hx @@ -53,6 +53,7 @@ class Options public static var freeplayLastSong:String = null; public static var freeplayLastDifficulty:String = "normal"; public static var contributors:Array = []; + public static var mainDevs:Array = []; // IDs public static var lastUpdated:Null; /**