diff --git a/README.md b/README.md
index c4439c44..604cd9c2 100644
--- a/README.md
+++ b/README.md
@@ -85,6 +85,5 @@ In the future (when the engine won't be a WIP anymore) we're gonna also publish
- Credits to [Ne_Eo](https://twitter.com/Ne_Eo_Twitch) and the [3D-HaxeFlixel](https://github.com/lunarcleint/3D-HaxeFlixel) repository for Away3D Flixel support
- Credits to the [FlxAnimate](https://github.com/Dot-Stuff/flxanimate) team for the Animate Atlas support
- Credits to Smokey555 for the backup Animate Atlas to spritesheet code
-- Credits to MAJigsaw77 for [hxvlc](https://github.com/MAJigsaw77/hxvlc) for video cutscene/mp4 support
-- Credits to Aidan63 for [discord-rpc](https://github.com/Aidan63/linc_discord-rpc) for discord rpc integration
+- Credits to MAJigsaw77 for [hxvlc](https://github.com/MAJigsaw77/hxvlc) (video cutscene/mp4 support) and [hxdiscord_rpc](https://github.com/MAJigsaw77/hxdiscord_rpc) (discord rpc integration)
diff --git a/assets/data/discord.hx b/assets/data/discord.hx
new file mode 100644
index 00000000..9d5f0f6f
--- /dev/null
+++ b/assets/data/discord.hx
@@ -0,0 +1,50 @@
+import funkin.backend.utils.DiscordUtil;
+
+function onGameOver() {
+ DiscordUtil.changePresence('Game Over', PlayState.SONG.meta.displayName + " (" + PlayState.difficulty + ")");
+}
+
+function onDiscordPresenceUpdate(e) {
+ var data = e.presence;
+
+ if(data.button1Label == null)
+ data.button1Label = "Codename Engine Discord";
+ if(data.button1Url == null)
+ data.button1Url = "https://discord.gg/2NTCdsQvx4";
+}
+
+function onPlayStateUpdate() {
+ DiscordUtil.changeSongPresence(
+ PlayState.instance.detailsText,
+ (PlayState.instance.paused ? "Paused - " : "") + PlayState.SONG.meta.displayName + " (" + PlayState.difficulty + ")",
+ PlayState.instance.inst,
+ PlayState.instance.getIconRPC()
+ );
+}
+
+function onMenuLoaded(name:String) {
+ // Name is either "Main Menu", "Freeplay", "Title Screen", "Options Menu", "Credits Menu", "Beta Warning", "Update Available Screen", "Update Screen"
+ DiscordUtil.changePresenceSince("In the Menus", null);
+}
+
+function onEditorTreeLoaded(name:String) {
+ switch(name) {
+ case "Character Editor":
+ DiscordUtil.changePresenceSince("Choosing a Character", null);
+ case "Chart Editor":
+ DiscordUtil.changePresenceSince("Choosing a Chart", null);
+ case "Stage Editor":
+ DiscordUtil.changePresenceSince("Choosing a Stage", null);
+ }
+}
+
+function onEditorLoaded(name:String, editingThing:String) {
+ switch(name) {
+ case "Character Editor":
+ DiscordUtil.changePresenceSince("Editing a Character", editingThing);
+ case "Chart Editor":
+ DiscordUtil.changePresenceSince("Editing a Chart", editingThing);
+ case "Stage Editor":
+ DiscordUtil.changePresenceSince("Editing a Stage", editingThing);
+ }
+}
\ No newline at end of file
diff --git a/commandline/commands/Update.hx b/commandline/commands/Update.hx
index 92ae18c7..6ac0f0f3 100644
--- a/commandline/commands/Update.hx
+++ b/commandline/commands/Update.hx
@@ -75,10 +75,12 @@ class Update {
// 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 (Compiler.getBuildTarget().toLowerCase() == "windows" && new Process('"C:/Program Files (x86)/Microsoft Visual Studio/Installer/vswhere.exe" -property catalog_productDisplayVersion').exitCode(true) == 1) {
prettyPrint("Installing Microsoft Visual Studio Community (Dependency)");
+
+ // thanks to @crowplexus for these two lines! - Nex
Sys.command("curl -# -O https://download.visualstudio.microsoft.com/download/pr/3105fcfe-e771-41d6-9a1c-fc971e7d03a7/8eb13958dc429a6e6f7e0d6704d43a55f18d02a253608351b6bf6723ffdaf24e/vs_Community.exe");
Sys.command("vs_Community.exe --add Microsoft.VisualStudio.Component.VC.Tools.x86.x64 --add Microsoft.VisualStudio.Component.Windows10SDK.19041 -p");
- FileSystem.deleteFile("vs_Community.exe");
+ FileSystem.deleteFile("vs_Community.exe");
prettyPrint('If it didn\'t say it before: Because of this component if you want to compile you have to restart the device.');
Sys.print("Do you wish to do it now [y/n]? ");
if(Sys.stdin().readLine().toLowerCase() == "y") Sys.command("shutdown /r /t 0 /f");
diff --git a/libs.xml b/libs.xml
index 81618ce1..6463128d 100644
--- a/libs.xml
+++ b/libs.xml
@@ -1,8 +1,8 @@
-
-
+
+
@@ -10,13 +10,14 @@
-
+
+
-
+
-
\ No newline at end of file
+
diff --git a/project.xml b/project.xml
index aee55825..77ae6af6 100644
--- a/project.xml
+++ b/project.xml
@@ -161,6 +161,13 @@
+
+
+
+
+
+
+
@@ -170,11 +177,9 @@
-
+
-
-
diff --git a/source/funkin/backend/scripting/GlobalScript.hx b/source/funkin/backend/scripting/GlobalScript.hx
index 34da69b5..5c037aec 100644
--- a/source/funkin/backend/scripting/GlobalScript.hx
+++ b/source/funkin/backend/scripting/GlobalScript.hx
@@ -79,12 +79,14 @@ class GlobalScript {
}
public static function event(name:String, event:T):T {
- if (scripts != null) scripts.call(name, [event]);
+ if (scripts != null)
+ scripts.event(name, event);
return event;
}
public static function call(name:String, ?args:Array) {
- if (scripts != null) scripts.call(name, args);
+ if (scripts != null)
+ scripts.call(name, args);
}
public static function onModSwitch(newMod:String) {
call("destroy");
@@ -93,7 +95,8 @@ class GlobalScript {
for (i in funkin.backend.assets.ModsFolder.getLoadedMods()) {
var path = Paths.script('data/global/LIB_$i');
var script = Script.create(path);
- if (script is DummyScript) continue;
+ if (script is DummyScript)
+ continue;
script.remappedNames.set(script.fileName, '$i:${script.fileName}');
scripts.add(script);
script.load();
diff --git a/source/funkin/backend/scripting/events/DiscordPresenceUpdateEvent.hx b/source/funkin/backend/scripting/events/DiscordPresenceUpdateEvent.hx
index 782d70a0..c17cbb68 100644
--- a/source/funkin/backend/scripting/events/DiscordPresenceUpdateEvent.hx
+++ b/source/funkin/backend/scripting/events/DiscordPresenceUpdateEvent.hx
@@ -1,12 +1,8 @@
package funkin.backend.scripting.events;
-#if DISCORD_RPC
-import discord_rpc.DiscordRpc.DiscordPresenceOptions;
-#end
-
final class DiscordPresenceUpdateEvent extends CancellableEvent {
/**
* Object containing all of the data for the presence. Can be altered.
*/
- public var presenceData:#if DISCORD_RPC DiscordPresenceOptions #else Dynamic #end;
+ public var presence:funkin.backend.utils.DiscordUtil.DPresence;
}
\ No newline at end of file
diff --git a/source/funkin/backend/system/Main.hx b/source/funkin/backend/system/Main.hx
index d04d4f3d..cad2266e 100644
--- a/source/funkin/backend/system/Main.hx
+++ b/source/funkin/backend/system/Main.hx
@@ -120,7 +120,6 @@ class Main extends Sprite
ShaderResizeFix.init();
Logs.init();
Paths.init();
- DiscordUtil.init();
#if GLOBAL_SCRIPT
funkin.backend.scripting.GlobalScript.init();
#end
diff --git a/source/funkin/backend/system/MainState.hx b/source/funkin/backend/system/MainState.hx
index e8192fc1..885da7b0 100644
--- a/source/funkin/backend/system/MainState.hx
+++ b/source/funkin/backend/system/MainState.hx
@@ -55,7 +55,7 @@ class MainState extends FlxState {
Main.refreshAssets();
ModsFolder.onModSwitch.dispatch(ModsFolder.currentModFolder);
- DiscordUtil.reloadJsonData();
+ DiscordUtil.init();
EventsData.reloadEvents();
TitleState.initialized = false;
diff --git a/source/funkin/backend/system/github/GitHub.hx b/source/funkin/backend/system/github/GitHub.hx
index fa664112..27ba825b 100644
--- a/source/funkin/backend/system/github/GitHub.hx
+++ b/source/funkin/backend/system/github/GitHub.hx
@@ -3,7 +3,6 @@ package funkin.backend.system.github;
#if GITHUB_API
import haxe.Json;
import haxe.Exception;
-import haxe.Http;
#end
// TODO: Document further and perhaps make this a Haxelib.
@@ -18,7 +17,7 @@ class GitHub {
public static function getReleases(user:String, repository:String, ?onError:Exception->Void):Array {
#if GITHUB_API
try {
- var data = Json.parse(__requestOnGitHubServers('https://api.github.com/repos/${user}/${repository}/releases'));
+ var data = Json.parse(HttpUtil.requestText('https://api.github.com/repos/${user}/${repository}/releases'));
if (!(data is Array))
throw __parseGitHubException(data);
@@ -41,7 +40,7 @@ class GitHub {
public static function getContributors(user:String, repository:String, ?onError:Exception->Void):Array {
#if GITHUB_API
try {
- var data = Json.parse(__requestOnGitHubServers('https://api.github.com/repos/${user}/${repository}/contributors'));
+ var data = Json.parse(HttpUtil.requestText('https://api.github.com/repos/${user}/${repository}/contributors'));
if (!(data is Array))
throw __parseGitHubException(data);
@@ -63,7 +62,7 @@ class GitHub {
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'));
+ var data = Json.parse(HttpUtil.requestText('https://api.github.com/orgs/$org'));
if (Reflect.hasField(data, "documentation_url"))
throw __parseGitHubException(data);
@@ -86,7 +85,7 @@ class GitHub {
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'));
+ var data = Json.parse(HttpUtil.requestText('https://api.github.com/orgs/$org/members'));
if (Reflect.hasField(data, "documentation_url"))
throw __parseGitHubException(data);
@@ -111,7 +110,7 @@ class GitHub {
try {
var url = 'https://api.github.com/users/$user';
- var data = Json.parse(__requestOnGitHubServers(url));
+ var data = Json.parse(HttpUtil.requestText(url));
if (Reflect.hasField(data, "documentation_url"))
throw __parseGitHubException(data);
@@ -134,59 +133,6 @@ class GitHub {
public static inline function filterReleases(releases:Array, keepPrereleases:Bool = true, keepDrafts:Bool = false)
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");
-
- h.onStatus = function(s) {
- if(isRedirect(s))
- r = __requestOnGitHubServers(h.responseHeaders.get("Location"));
- };
-
- h.onData = function(d) {
- if(r == null) r = d;
- }
- h.onError = function(e) {
- throw e;
- }
-
- 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");
-
- h.onStatus = function(s) {
- if(isRedirect(s))
- r = __requestBytesOnGitHubServers(h.responseHeaders.get("Location"));
- };
-
- h.onBytes = function(d) {
- if(r == null) r = d;
- }
- h.onError = function(e) {
- throw e;
- }
-
- h.request(false);
- #end
- return r;
- }
- 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;
- }
private static function __parseGitHubException(obj:Dynamic):GitHubException {
#if GITHUB_API
var msg:String = "(No message)";
diff --git a/source/funkin/backend/system/macros/Utils.hx b/source/funkin/backend/system/macros/Utils.hx
index df25030c..1d4873f4 100644
--- a/source/funkin/backend/system/macros/Utils.hx
+++ b/source/funkin/backend/system/macros/Utils.hx
@@ -37,4 +37,21 @@ class Utils {
return expr;
#end
}
+
+ public static macro function safeSet(variable:Null, value:Null):Null {
+ #if macro
+ return macro if (${value} != null) ${variable} = ${value};
+ #end
+ }
+ public static macro function safeSetWrapper(variable:Null, value:Null, wrapper:Null):Null {
+ #if macro
+ return macro if (${value} != null) ${variable} = ${wrapper}(${value});
+ #end
+ }
+
+ public static macro function safeReflection(variable:Null, value:Null, field:Null):Null {
+ #if macro
+ return macro if (Reflect.hasField(${value}, ${field})) ${variable} = Reflect.field(${value}, ${field});
+ #end
+ }
}
\ No newline at end of file
diff --git a/source/funkin/backend/system/updating/UpdateAvailableScreen.hx b/source/funkin/backend/system/updating/UpdateAvailableScreen.hx
index 5b076058..d3a3869a 100644
--- a/source/funkin/backend/system/updating/UpdateAvailableScreen.hx
+++ b/source/funkin/backend/system/updating/UpdateAvailableScreen.hx
@@ -92,6 +92,8 @@ class UpdateAvailableScreen extends MusicBeatState {
add(skipButton);
oldPos = FlxG.mouse.getScreenPosition();
+
+ DiscordUtil.call("onMenuLoaded", ["Update Available Screen"]);
}
var destY:Float = 0;
diff --git a/source/funkin/backend/system/updating/UpdateScreen.hx b/source/funkin/backend/system/updating/UpdateScreen.hx
index 4fbe4cf8..323fda09 100644
--- a/source/funkin/backend/system/updating/UpdateScreen.hx
+++ b/source/funkin/backend/system/updating/UpdateScreen.hx
@@ -61,6 +61,8 @@ class UpdateScreen extends MusicBeatState {
updater.execute();
FlxG.camera.addShader(rainbowShader = new CustomShader("engine/updaterShader"));
+
+ DiscordUtil.call("onMenuLoaded", ["Update Screen"]);
}
diff --git a/source/funkin/backend/utils/DiscordUtil.hx b/source/funkin/backend/utils/DiscordUtil.hx
index cdd24b6c..9df88b3e 100644
--- a/source/funkin/backend/utils/DiscordUtil.hx
+++ b/source/funkin/backend/utils/DiscordUtil.hx
@@ -1,62 +1,122 @@
package funkin.backend.utils;
import funkin.backend.scripting.events.DiscordPresenceUpdateEvent;
+import funkin.backend.scripting.events.CancellableEvent;
+import funkin.backend.scripting.*; // lazy
+import flixel.util.typeLimit.OneOfTwo;
+import openfl.display.BitmapData;
+import funkin.backend.system.macros.Utils;
import haxe.Json;
import flixel.sound.FlxSound;
#if DISCORD_RPC
-import discord_rpc.DiscordRpc;
+import hxdiscord_rpc.Discord;
+import hxdiscord_rpc.Types;
import sys.thread.Thread;
import Sys;
import lime.app.Application;
#end
-class DiscordUtil {
- public static var currentID:String = null;
+class DiscordUtil
+{
+ public static var currentID(default, set):String = null;
public static var discordThread:#if DISCORD_RPC Thread #else Dynamic #end = null;
public static var ready:Bool = false;
- public static var data:DiscordJson = null;
+ public static var initialized:Bool = false;
+ private static var stopThread:Bool = false;
- public static function init() {
+ public static var user:#if DISCORD_RPC DUser #else Dynamic #end = null;
+ public static var lastPresence:#if DISCORD_RPC DPresence #else Dynamic #end = null;
+ public static var config:#if DISCORD_RPC DiscordJson #else Dynamic #end = null;
+
+ public static var script:Script;
+
+ // Constants
+ public static var REPLY_NO:Int = Discord.REPLY_NO;
+ public static var REPLY_YES:Int = Discord.REPLY_YES;
+ public static var REPLY_IGNORE:Int = Discord.REPLY_IGNORE;
+ public static var PARTY_PRIVATE:Int = Discord.PARTY_PRIVATE;
+ public static var PARTY_PUBLIC:Int = Discord.PARTY_PUBLIC;
+
+ public static function init()
+ {
#if DISCORD_RPC
reloadJsonData();
- discordThread = Thread.create(function() {
+ if (initialized)
+ return;
+ initialized = true;
+
+ discordThread = Thread.create(function()
+ {
while (true)
{
- while(!ready) {
- Sys.sleep(1/60);
+ while (!stopThread)
+ {
+ #if DISCORD_DISABLE_IO_THREAD
+ Discord.UpdateConnection();
+ #end
+ Discord.RunCallbacks();
+
+ Sys.sleep(2);
}
- trace("Processing Discord RPC...");
- DiscordRpc.process();
- Sys.sleep(2);
+
+ Sys.sleep(1); // to reduce cpu
}
});
- Application.current.onExit.add(function(exitCode) {
- shutdown();
- });
+ Application.current.onExit.add(function(_) shutdown());
#end
}
- public static function reloadJsonData() {
+ public static function reloadJsonData()
+ {
#if DISCORD_RPC
- data = {};
var jsonPath = Paths.json("config/discord");
- if (Assets.exists(jsonPath)) {
- try {
- data = Json.parse(Assets.getText(jsonPath));
- } catch(e) {
+ if (Assets.exists(jsonPath))
+ {
+ try
+ config = Json.parse(Assets.getText(jsonPath))
+ catch (e)
Logs.trace('Couldn\'t load Discord RPC configuration: ${e.toString()}', ERROR);
- }
}
- data.setFieldDefault("clientID", "1027994136193810442");
- data.setFieldDefault("logoKey", "icon");
- data.setFieldDefault("logoText", Application.current.meta.get('title'));
+ else
+ {
+ config = {};
+ }
- changeClientID(data.clientID);
+ config.logoKey = config.logoKey.getDefault("icon");
+ config.logoText = config.logoText.getDefault(Application.current.meta.get('title'));
+ config.clientID = config.clientID.getDefault("1027994136193810442");
+ currentID = config.clientID;
#end
}
- public static function changePresence(details:String, state:String, ?smallImageKey : String) {
+ public static function event(name:String, event:T):T
+ {
+ if (script != null)
+ script.call(name, [event]);
+ return event;
+ }
+
+ public static function call(name:String, ?args:Array)
+ {
+ if (script != null)
+ script.call(name, args);
+ }
+
+ public static function loadScript()
+ {
+ if (script != null)
+ {
+ call("destroy");
+ script = FlxDestroyUtil.destroy(script);
+ }
+ script = Script.create(Paths.script('data/discord'));
+ // script.setParent(DiscordUtil);
+ script.load();
+ }
+
+ public static function changePresence(details:String, state:String, ?smallImageKey:String)
+ {
#if DISCORD_RPC
changePresenceAdvanced({
state: state,
@@ -66,12 +126,14 @@ class DiscordUtil {
#end
}
- public static function changeSongPresence(details:String, state:String, audio:FlxSound, ?smallImageKey : String) {
+ public static function changeSongPresence(details:String, state:String, audio:FlxSound, ?smallImageKey:String)
+ {
#if DISCORD_RPC
var start:Float = 0;
var end:Float = 0;
- if (audio != null && audio.playing) {
+ if (audio != null && audio.playing)
+ {
start = Date.now().getTime();
end = start + (audio.length - audio.time);
}
@@ -86,66 +148,335 @@ class DiscordUtil {
#end
}
- public static function changePresenceAdvanced(data:#if DISCORD_RPC DiscordPresenceOptions #else Dynamic #end) {
+ public static function changePresenceSince(details:String, state:String, ?smallImageKey:String, ?time:Float)
+ {
#if DISCORD_RPC
- if (data == null) return;
+ if(time == null)
+ time = Date.now().getTime();
- if (data.largeImageKey == null)
- data.largeImageKey = DiscordUtil.data.logoKey;
- if (data.largeImageText == null)
- data.largeImageText = DiscordUtil.data.logoText;
-
- #if GLOBAL_SCRIPT
- var event = funkin.backend.scripting.GlobalScript.event("onDiscordPresenceUpdate", EventManager.get(DiscordPresenceUpdateEvent).recycle(data));
- if (event.cancelled) return;
- #end
-
- DiscordRpc.presence(data);
+ changePresenceAdvanced({
+ state: state,
+ details: details,
+ smallImageKey: smallImageKey,
+ startTimestamp: Std.int(time / 1000)
+ });
#end
}
- public static function changeClientID(id:String) {
+
+ @:noCompletion public static function fixString(str:String)
+ {
+ return new cpp.ConstCharStar(cast(str, String));
+ }
+
+ @:noCompletion public static function toString(str:cpp.ConstCharStar)
+ {
+ return cast(str, String);
+ }
+
+ public static function changePresenceAdvanced(data:DPresence)
+ {
#if DISCORD_RPC
- if (currentID != null) {
- DiscordRpc.shutdown();
+ if (data == null)
+ return;
+
+ // copy last presence
+ if (data.largeImageKey == null)
+ data.largeImageKey = config.logoKey;
+ if (data.largeImageText == null)
+ data.largeImageText = config.logoText;
+
+ var evt = EventManager.get(DiscordPresenceUpdateEvent).recycle(data);
+ #if GLOBAL_SCRIPT
+ // kept for "backwards compat"
+ funkin.backend.scripting.GlobalScript.event("onDiscordPresenceUpdate", evt);
+ #end
+ event("onDiscordPresenceUpdate", evt);
+ if (evt.cancelled)
+ return;
+ data = evt.presence;
+ lastPresence = data;
+
+ var dp:DiscordRichPresence = DiscordRichPresence.create();
+ // TODO: make this use a reflection-like macro
+ Utils.safeSetWrapper(dp.state, data.state, fixString);
+ Utils.safeSetWrapper(dp.details, data.details, fixString);
+ Utils.safeSet(dp.startTimestamp, data.startTimestamp);
+ Utils.safeSet(dp.endTimestamp, data.endTimestamp);
+ Utils.safeSetWrapper(dp.largeImageKey, data.largeImageKey, fixString);
+ Utils.safeSetWrapper(dp.largeImageText, data.largeImageText, fixString);
+ Utils.safeSetWrapper(dp.smallImageKey, data.smallImageKey, fixString);
+ Utils.safeSetWrapper(dp.smallImageText, data.smallImageText, fixString);
+ Utils.safeSetWrapper(dp.partyId, data.partyId, fixString);
+ Utils.safeSet(dp.partySize, data.partySize);
+ Utils.safeSet(dp.partyMax, data.partyMax);
+ Utils.safeSet(dp.partyPrivacy, data.partyPrivacy);
+ Utils.safeSetWrapper(dp.matchSecret, data.matchSecret, fixString);
+ Utils.safeSetWrapper(dp.joinSecret, data.joinSecret, fixString);
+ Utils.safeSetWrapper(dp.spectateSecret, data.spectateSecret, fixString);
+ Utils.safeSet(dp.instance, data.instance);
+ if (data.matchSecret == null && data.joinSecret == null && data.spectateSecret == null)
+ {
+ Utils.safeSetWrapper(dp.button1Label, data.button1Label, fixString);
+ Utils.safeSetWrapper(dp.button1Url, data.button1Url, fixString);
+ Utils.safeSetWrapper(dp.button2Label, data.button2Label, fixString);
+ Utils.safeSetWrapper(dp.button2Url, data.button2Url, fixString);
}
- ready = false;
-
- DiscordRpc.start({
- clientID: id,
- onReady: function() {
- Logs.trace('Discord RPC started');
- ready = true;
- },
- onError: onError,
- onDisconnected: onDisconnected
- });
- currentID = id;
-
+ Discord.UpdatePresence(cpp.RawConstPointer.addressOf(dp));
#end
}
- public static function shutdown() {
+ public static function clearPresence() {
#if DISCORD_RPC
- DiscordRpc.shutdown();
+ Discord.ClearPresence();
#end
}
+ private static function set_currentID(id:String):String
+ {
+ if (currentID == id)
+ return id;
+ #if DISCORD_RPC
+ if (currentID != null)
+ shutdown();
+
+ var handlers:DiscordEventHandlers = DiscordEventHandlers.create();
+ handlers.ready = cpp.Function.fromStaticFunction(onReady);
+ handlers.disconnected = cpp.Function.fromStaticFunction(onDisconnected);
+ handlers.errored = cpp.Function.fromStaticFunction(onError);
+ handlers.joinGame = cpp.Function.fromStaticFunction(onJoin);
+ handlers.joinRequest = cpp.Function.fromStaticFunction(onJoinReq);
+ handlers.spectateGame = cpp.Function.fromStaticFunction(onSpectate);
+ Discord.Initialize(id, cpp.RawPointer.addressOf(handlers), 1, null);
+ stopThread = false;
+
+ loadScript();
+ #end
+
+ return currentID = id;
+ }
+
+ public static function shutdown()
+ {
+ ready = false;
+ stopThread = true;
+ #if DISCORD_RPC
+ Discord.Shutdown();
+ #end
+
+ call("destroy");
+ script = FlxDestroyUtil.destroy(script);
+ }
+
+ public static function respond(userId:String, reply:Int)
+ {
+ #if DISCORD_RPC
+ Discord.Respond(fixString(userId), reply);
+ #end
+ }
// HANDLERS
#if DISCORD_RPC
- static function onError(_code:Int, _message:String) {
- Logs.trace('Discord RPC Error: ${_message} (Code: $_code)', ERROR);
+ private static function onReady(request:cpp.RawConstPointer):Void
+ {
+ user = DUser.initRaw(request);
+
+ Logs.traceColored([
+ Logs.logText("[Discord] ", BLUE),
+ Logs.logText("Connected to User " + user.globalName + " ("),
+ Logs.logText(user.handle, GRAY),
+ Logs.logText(")")
+ ], INFO);
+
+ ready = true;
+
+ call("onReady", [user]);
}
- static function onDisconnected(_code:Int, _message:String) {
- Logs.trace('Discord RPC Disconnected: ${_message} (Code: $_code)', WARNING);
+ private static function onDisconnected(errorCode:Int, message:cpp.ConstCharStar):Void
+ {
+ var finalMsg:String = cast(message, String);
+
+ Logs.traceColored([
+ Logs.logText("[Discord] ", BLUE),
+ Logs.logText("Disconnected ("),
+ Logs.logText('$errorCode: $finalMsg', RED),
+ Logs.logText(")")
+ ], INFO);
+
+ call("onReady", [errorCode, cast(finalMsg, String)]);
+ }
+
+ private static function onError(errorCode:Int, message:cpp.ConstCharStar):Void
+ {
+ var finalMsg:String = cast(message, String);
+
+ Logs.traceColored([
+ Logs.logText("[Discord] ", BLUE),
+ Logs.logText('Error ($errorCode: $finalMsg)', RED)
+ ], ERROR);
+
+ call("onError", [errorCode, cast(finalMsg, String)]);
+ }
+
+ private static function onJoin(joinSecret:cpp.ConstCharStar):Void
+ {
+ Logs.traceColored([Logs.logText("[Discord] ", BLUE), Logs.logText("Someone has just joined", GREEN)], INFO);
+
+ call("onJoinGame", [cast(joinSecret, String)]);
+ }
+
+ private static function onSpectate(spectateSecret:cpp.ConstCharStar):Void
+ {
+ Logs.traceColored([
+ Logs.logText("[Discord] ", BLUE),
+ Logs.logText("Someone started spectating your game", YELLOW)
+ ], INFO);
+
+ call("onSpectateGame", [cast(spectateSecret, String)]);
+ }
+
+ private static function onJoinReq(request:cpp.RawConstPointer):Void
+ {
+ Logs.traceColored([
+ Logs.logText("[Discord] ", BLUE),
+ Logs.logText("Someone has just requested to join", YELLOW)
+ ], WARNING);
+
+ var req:DUser = DUser.initRaw(request);
+ call("onJoinRequest", [req]);
}
#end
}
-typedef DiscordJson = {
+typedef DiscordJson =
+{
var ?clientID:String;
var ?logoKey:String;
var ?logoText:String;
-}
\ No newline at end of file
+}
+
+@:noCustomClass
+final class DUser
+{
+ /**
+ * The username + discriminator if they have it
+ **/
+ public var handle:String;
+
+ /**
+ * The user id, aka 860561967383445535
+ **/
+ public var userId:String;
+
+ /**
+ * The user's username
+ **/
+ public var username:String;
+
+ /**
+ * The #number from before discord changed to usernames only, if the user has changed to a username them its just a 0
+ **/
+ public var discriminator:Int;
+
+ /**
+ * The user's avatar filename
+ **/
+ public var avatar:String;
+
+ /**
+ * The user's display name
+ **/
+ public var globalName:String;
+
+ /**
+ * If the user is a bot or not
+ **/
+ public var bot:Bool;
+
+ /**
+ * Idk check discord docs
+ **/
+ public var flags:Int;
+
+ /**
+ * If the user has nitro
+ **/
+ public var premiumType:NitroType;
+
+ private function new()
+ {
+ }
+
+ public static function initRaw(req:cpp.RawConstPointer)
+ {
+ return init(cpp.ConstPointer.fromRaw(req).ptr);
+ }
+
+ public static function init(userData:cpp.Star)
+ {
+ var d = new DUser();
+ d.userId = userData.userId;
+ d.username = userData.username;
+ d.discriminator = Std.parseInt(userData.discriminator);
+ d.avatar = userData.avatar;
+ d.globalName = userData.globalName;
+ d.bot = userData.bot;
+ d.flags = userData.flags;
+ d.premiumType = userData.premiumType;
+
+ if (d.discriminator != 0)
+ d.handle = '${d.username}#${d.discriminator}';
+ else
+ d.handle = '${d.username}';
+ return d;
+ }
+
+ /**
+ * Calling this function gets the BitmapData of the user
+ **/
+ public function getAvatar(size:Int = 256):BitmapData
+ return BitmapData.fromBytes(HttpUtil.requestBytes('https://cdn.discordapp.com/avatars/$userId/$avatar.png?size=$size'));
+}
+
+enum abstract NitroType(Int) to Int from Int
+{
+ var NONE = 0;
+ var NITRO_CLASSIC = 1;
+ var NITRO = 2;
+ var NITRO_BASIC = 3;
+}
+
+typedef DPresence =
+{
+ var ?state:String; /* max 128 bytes */
+ var ?details:String; /* max 128 bytes */
+ var ?startTimestamp:OneOfTwo;
+ var ?endTimestamp:OneOfTwo;
+ var ?largeImageKey:String; /* max 32 bytes */
+ var ?largeImageText:String; /* max 128 bytes */
+ var ?smallImageKey:String; /* max 32 bytes */
+ var ?smallImageText:String; /* max 128 bytes */
+ var ?partyId:String; /* max 128 bytes */
+ var ?partySize:Int;
+ var ?partyMax:Int;
+ var ?partyPrivacy:Int;
+ var ?matchSecret:String; /* max 128 bytes */
+ var ?joinSecret:String; /* max 128 bytes */
+ var ?spectateSecret:String; /* max 128 bytes */
+ var ?instance:OneOfTwo;
+ var ?button1Label:String; /* max 32 bytes */
+ var ?button1Url:String; /* max 512 bytes */
+ var ?button2Label:String; /* max 32 bytes */
+ var ?button2Url:String; /* max 512 bytes */
+}
+
+typedef DEvents =
+{
+ var ?ready:DUser->Void;
+ var ?disconnected:(errorCode:Int, message:String) -> Void;
+ var ?errored:(errorCode:Int, message:String) -> Void;
+ var ?joinGame:String->Void;
+ var ?spectateGame:String->Void;
+ var ?joinRequest:DUser->Void;
+}
diff --git a/source/funkin/backend/utils/HttpUtil.hx b/source/funkin/backend/utils/HttpUtil.hx
new file mode 100644
index 00000000..f2d3caf8
--- /dev/null
+++ b/source/funkin/backend/utils/HttpUtil.hx
@@ -0,0 +1,71 @@
+package funkin.backend.utils;
+
+import haxe.Http;
+
+class HttpUtil
+{
+ public static var userAgent:String = "request";
+ public static function requestText(url:String)
+ {
+ var r = null;
+ var h = new Http(url);
+ h.setHeader("User-Agent", userAgent);
+
+ h.onStatus = function(s)
+ {
+ if (isRedirect(s))
+ r = requestText(h.responseHeaders.get("Location"));
+ };
+
+ h.onData = function(d)
+ {
+ if (r == null)
+ r = d;
+ }
+ h.onError = function(e)
+ {
+ throw e;
+ }
+
+ h.request(false);
+ return r;
+ }
+
+ public static function requestBytes(url:String)
+ {
+ var r = null;
+ var h = new Http(url);
+ h.setHeader("User-Agent", userAgent);
+
+ h.onStatus = function(s)
+ {
+ if (isRedirect(s))
+ r = requestBytes(h.responseHeaders.get("Location"));
+ };
+
+ h.onBytes = function(d)
+ {
+ if (r == null)
+ r = d;
+ }
+ h.onError = function(e)
+ {
+ throw e;
+ }
+
+ h.request(false);
+ return r;
+ }
+
+ 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:
+ Logs.traceColored([Logs.logText('[Connection Status] ', BLUE), Logs.logText('Redirected with status code: ', YELLOW), Logs.logText('$status', GREEN)], WARNING);
+ return true;
+ }
+ return false;
+ }
+}
diff --git a/source/funkin/editors/character/CharacterEditor.hx b/source/funkin/editors/character/CharacterEditor.hx
index 8c5cf9c7..359ef24d 100644
--- a/source/funkin/editors/character/CharacterEditor.hx
+++ b/source/funkin/editors/character/CharacterEditor.hx
@@ -224,7 +224,7 @@ class CharacterEditor extends UIState {
FlxG.cameras.add(uiCamera);
FlxG.cameras.add(animsCamera);
- character = new Character(0,0,__character, false, false);
+ character = new Character(0,0, __character, false, false);
character.debugMode = true;
character.cameras = [charCamera];
@@ -257,6 +257,8 @@ class CharacterEditor extends UIState {
Framerate.memoryCounter.alpha = 0.4;
Framerate.codenameBuildField.alpha = 0.4;
}
+
+ DiscordUtil.call("onEditorLoaded", ["Character Editor", __character]);
}
override function destroy() {
diff --git a/source/funkin/editors/character/CharacterSelection.hx b/source/funkin/editors/character/CharacterSelection.hx
index 9d1a60ed..817acf29 100644
--- a/source/funkin/editors/character/CharacterSelection.hx
+++ b/source/funkin/editors/character/CharacterSelection.hx
@@ -33,6 +33,8 @@ class CharacterSelection extends EditorTreeMenu
}));
main = new OptionsScreen("Character Editor", "Select a character to edit", list);
+
+ DiscordUtil.call("onEditorTreeLoaded", ["Character Editor"]);
}
override function createPost() {
diff --git a/source/funkin/editors/charter/Charter.hx b/source/funkin/editors/charter/Charter.hx
index 926e12b8..a26c55c0 100644
--- a/source/funkin/editors/charter/Charter.hx
+++ b/source/funkin/editors/charter/Charter.hx
@@ -510,6 +510,8 @@ class Charter extends UIState {
dataDisplay.updateHitbox();
dataDisplay.screenCenter(Y);
dataDisplay.cameras = [charterCamera]; dataDisplay.x = -dataDisplay.width; add(dataDisplay);*/
+
+ DiscordUtil.call("onEditorLoaded", ["Chart Editor", __song + " (" + __diff + ")"]);
}
override function destroy() {
@@ -548,7 +550,7 @@ class Charter extends UIState {
notesGroup.autoSort = false;
var noteCount:Int = 0;
for (strL in PlayState.SONG.strumLines)
- for (note in strL.notes) noteCount++;
+ noteCount += strL.notes.length;
notesGroup.preallocate(noteCount);
var notesCreated:Int = 0;
diff --git a/source/funkin/editors/charter/CharterSelection.hx b/source/funkin/editors/charter/CharterSelection.hx
index b0957997..6fd97bdc 100644
--- a/source/funkin/editors/charter/CharterSelection.hx
+++ b/source/funkin/editors/charter/CharterSelection.hx
@@ -46,6 +46,8 @@ class CharterSelection extends EditorTreeMenu {
}));
main = new OptionsScreen("Chart Editor", "Select a song to modify the charts from.", list);
+
+ DiscordUtil.call("onEditorTreeLoaded", ["Chart Editor"]);
}
override function createPost() {
diff --git a/source/funkin/game/GameOverSubstate.hx b/source/funkin/game/GameOverSubstate.hx
index 3d119f02..4868b130 100644
--- a/source/funkin/game/GameOverSubstate.hx
+++ b/source/funkin/game/GameOverSubstate.hx
@@ -87,8 +87,7 @@ class GameOverSubstate extends MusicBeatSubstate
lossSFX = FlxG.sound.play(Paths.sound(lossSFXName));
Conductor.changeBPM(gameOverSongBPM);
- DiscordUtil.changePresence('Game Over', PlayState.SONG.meta.displayName + " (" + PlayState.difficulty + ")");
-
+ DiscordUtil.call("onGameOver", []);
gameoverScript.call("postCreate");
}
diff --git a/source/funkin/game/NoteGroup.hx b/source/funkin/game/NoteGroup.hx
index 97b34da6..0d45a41f 100644
--- a/source/funkin/game/NoteGroup.hx
+++ b/source/funkin/game/NoteGroup.hx
@@ -106,6 +106,7 @@ class NoteGroup extends FlxTypedGroup {
if (members == null)
return null;
+ // TODO: maybe lastIndexOf
var index:Int = members.indexOfFromLast(Object);
if (index < 0)
diff --git a/source/funkin/game/PlayState.hx b/source/funkin/game/PlayState.hx
index 9a46aeb9..2ae26370 100644
--- a/source/funkin/game/PlayState.hx
+++ b/source/funkin/game/PlayState.hx
@@ -784,7 +784,7 @@ class PlayState extends MusicBeatState
* This function is dynamic, which means you can do `updateDiscordPresence = function() {}` in scripts.
*/
public dynamic function updateDiscordPresence()
- DiscordUtil.changeSongPresence(detailsText, (paused ? "Paused - " : "") + SONG.meta.displayName + " (" + difficulty + ")", inst, getIconRPC());
+ DiscordUtil.call("onPlayStateUpdate", []);
/**
* Starts a cutscene.
diff --git a/source/funkin/menus/BetaWarningState.hx b/source/funkin/menus/BetaWarningState.hx
index 08d60f39..16201454 100644
--- a/source/funkin/menus/BetaWarningState.hx
+++ b/source/funkin/menus/BetaWarningState.hx
@@ -29,6 +29,8 @@ class BetaWarningState extends MusicBeatState {
var off = Std.int((FlxG.height - (disclaimer.y + disclaimer.height)) / 2);
disclaimer.y += off;
titleAlphabet.y += off;
+
+ DiscordUtil.call("onMenuLoaded", ["Beta Warning"]);
}
public override function update(elapsed:Float) {
diff --git a/source/funkin/menus/FreeplayState.hx b/source/funkin/menus/FreeplayState.hx
index 0a6f3493..7ca66b02 100644
--- a/source/funkin/menus/FreeplayState.hx
+++ b/source/funkin/menus/FreeplayState.hx
@@ -116,7 +116,7 @@ class FreeplayState extends MusicBeatState
}
}
- DiscordUtil.changePresence("In the Menus", null);
+ DiscordUtil.call("onMenuLoaded", ["Freeplay"]);
super.create();
diff --git a/source/funkin/menus/MainMenuState.hx b/source/funkin/menus/MainMenuState.hx
index 03e3bd8b..b17e9db6 100644
--- a/source/funkin/menus/MainMenuState.hx
+++ b/source/funkin/menus/MainMenuState.hx
@@ -32,7 +32,7 @@ class MainMenuState extends MusicBeatState
{
super.create();
- DiscordUtil.changePresence("In the Menus", null);
+ DiscordUtil.call("onMenuLoaded", ["Main Menu"]);
CoolUtil.playMenuSong();
diff --git a/source/funkin/menus/StoryMenuState.hx b/source/funkin/menus/StoryMenuState.hx
index 6d9e27f2..384118e5 100644
--- a/source/funkin/menus/StoryMenuState.hx
+++ b/source/funkin/menus/StoryMenuState.hx
@@ -116,7 +116,7 @@ class StoryMenuState extends MusicBeatState {
changeWeek(0, true);
- DiscordUtil.changePresence("In the Menus", null);
+ DiscordUtil.call("onMenuLoaded", ["Story Menu"]);
CoolUtil.playMenuSong();
}
diff --git a/source/funkin/menus/TitleState.hx b/source/funkin/menus/TitleState.hx
index 491bc65a..4aca30db 100644
--- a/source/funkin/menus/TitleState.hx
+++ b/source/funkin/menus/TitleState.hx
@@ -36,6 +36,8 @@ class TitleState extends MusicBeatState
startIntro();
super.create();
+
+ DiscordUtil.call("onMenuLoaded", ["Title Screen"]);
}
var logoBl:FlxSprite;
diff --git a/source/funkin/menus/credits/CreditsCodename.hx b/source/funkin/menus/credits/CreditsCodename.hx
index 2a9dd42b..579360ed 100644
--- a/source/funkin/menus/credits/CreditsCodename.hx
+++ b/source/funkin/menus/credits/CreditsCodename.hx
@@ -1,5 +1,7 @@
package funkin.menus.credits;
+import funkin.options.PlayerSettings;
+import flixel.util.FlxColor;
import funkin.backend.system.github.GitHub;
import funkin.options.type.GithubIconOption;
import flixel.text.FlxText;
@@ -9,44 +11,74 @@ using StringTools;
class CreditsCodename extends funkin.options.OptionsScreen {
public var error:Bool = false;
public var author:String = "FNF-CNE-Devs";
+ public var mainDevCol:FlxColor = 0xFF9C35D5;
+ public var minContrCol:FlxColor = 0xFFB4A7DA;
+ public var totalContributions:Int = 0;
public override function new()
{
super("Codename Engine", "All the contributors of the engine! - Press RESET to update the list (One reset per 2 minutes).");
- checkUpdate();
- displayList();
+ tryUpdating(true);
}
+ // blame the secondary threads if the code has to look this bad - Nex
+ private var _canReset:Bool = true;
+ private var _downloadingSteps:Int = 0;
public override function update(elapsed:Float) {
- if (funkin.options.PlayerSettings.solo.controls.RESET && checkUpdate()) {
+ super.update(elapsed);
+
+ if (_downloadingSteps == 2) {
+ _downloadingSteps = 0;
+ _canReset = true;
displayList();
+ } else if (_downloadingSteps == 1) {
+ _downloadingSteps = 0;
+ _canReset = true;
updateMenuDesc();
}
- super.update(elapsed);
+ else if(_canReset && PlayerSettings.solo.controls.RESET) tryUpdating();
+ }
+
+ public function tryUpdating(forceDisplaying:Bool = false) {
+ updateMenuDesc("Downloading List...");
+ _canReset = false;
+ Main.execAsync(function() {
+ if(checkUpdate() || forceDisplaying) _downloadingSteps = 2;
+ else _downloadingSteps = 1;
+ });
}
public override function updateMenuDesc(?txt:String) {
+ if(!_canReset) return;
super.updateMenuDesc(txt);
- parent.treeParent.pathDesc.applyMarkup(parent.treeParent.pathDesc.text, [new FlxTextFormatMarkerPair(new FlxTextFormat(0xFF9C35D5), "*")]);
+ updateMarkup();
+ }
+
+ public function updateMarkup() {
+ if(parent == null || parent.treeParent == null) return;
+ var text:String = parent.treeParent.pathDesc.text;
+ parent.treeParent.pathDesc.text = "";
+ parent.treeParent.pathDesc.applyMarkup(text, [
+ new FlxTextFormatMarkerPair(new FlxTextFormat(mainDevCol), '*'),
+ new FlxTextFormatMarkerPair(new FlxTextFormat(FlxColor.interpolate(minContrCol, mainDevCol, Options.contributors[curSelected].contributions / totalContributions)), '~')
+ ]);
}
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
+ if(Options.lastUpdated != null && curTime < Options.lastUpdated + 120000) return false; // Fuck you Github rate limits - Nex
Options.lastUpdated = curTime;
error = false;
- //Main.execAsync(function() {
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);
funkin.backend.utils.NativeAPI.showMessageBox("Codename Engine Warning", errMsg, MSG_WARNING);
});
- //});
if(error) return false;
Options.contributors = idk;
- trace('List Updated!');
+ trace('Contributors list Updated!');
var errorOnMain:Bool = false;
var idk2 = GitHub.getOrganizationMembers(author, function(e) {
@@ -55,7 +87,10 @@ class CreditsCodename extends funkin.options.OptionsScreen {
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];
+ if(!errorOnMain) {
+ Options.mainDevs = [for(m in idk2) m.id];
+ trace('Main Devs list Updated!');
+ }
return true;
}
@@ -70,13 +105,17 @@ class CreditsCodename extends funkin.options.OptionsScreen {
remove(members[0], true);
}
- var totalContributions = 0;
+ totalContributions = 0;
for(c in Options.contributors) totalContributions += c.contributions;
for(c in Options.contributors) {
- 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);
+ var opt:GithubIconOption = new GithubIconOption(c, 'Total Contributions: ~${c.contributions}~ / *${totalContributions}* (~${FlxMath.roundDecimal(c.contributions / totalContributions * 100, 2)}%~) - Select to open GitHub account');
+ if(Options.mainDevs.contains(c.id)) {
+ opt.desc += " *- Public member of the main Devs!*";
+ @:privateAccess opt.__text.color = mainDevCol;
+ }
add(opt);
}
+
+ updateMenuDesc();
}
}
\ No newline at end of file
diff --git a/source/funkin/menus/credits/CreditsMain.hx b/source/funkin/menus/credits/CreditsMain.hx
index 5dd16aff..56507274 100644
--- a/source/funkin/menus/credits/CreditsMain.hx
+++ b/source/funkin/menus/credits/CreditsMain.hx
@@ -43,6 +43,8 @@ class CreditsMain extends TreeMenu {
main = new OptionsScreen('Credits', 'The people who made this possible!', selectables);
super.create();
+
+ DiscordUtil.call("onMenuLoaded", ["Credits Menu"]);
}
/**
diff --git a/source/funkin/options/OptionsMenu.hx b/source/funkin/options/OptionsMenu.hx
index 5b786e10..f9232e13 100644
--- a/source/funkin/options/OptionsMenu.hx
+++ b/source/funkin/options/OptionsMenu.hx
@@ -37,6 +37,8 @@ class OptionsMenu extends TreeMenu {
CoolUtil.playMenuSong();
+ DiscordUtil.call("onMenuLoaded", ["Options Menu"]);
+
var bg:FlxSprite = new FlxSprite(-80).loadAnimatedGraphic(Paths.image('menus/menuBGBlue'));
// bg.scrollFactor.set();
bg.scale.set(1.15, 1.15);
diff --git a/source/funkin/options/OptionsScreen.hx b/source/funkin/options/OptionsScreen.hx
index f21bdaaf..45580821 100644
--- a/source/funkin/options/OptionsScreen.hx
+++ b/source/funkin/options/OptionsScreen.hx
@@ -70,11 +70,8 @@ class OptionsScreen extends FlxTypedSpriteGroup {
}
public function updateMenuDesc(?customTxt:String) {
- if (parent.treeParent == null) return;
-
- var text:String = members[curSelected].desc;
- if (customTxt != null) text = customTxt;
- parent.treeParent.updateDesc(text);
+ if (parent == null || parent.treeParent == null) return;
+ parent.treeParent.updateDesc(customTxt != null ? customTxt : members[curSelected].desc);
}
public dynamic function onClose(o:OptionsScreen) {}
diff --git a/source/funkin/options/type/GithubIconOption.hx b/source/funkin/options/type/GithubIconOption.hx
index cbbef1ed..5c780165 100644
--- a/source/funkin/options/type/GithubIconOption.hx
+++ b/source/funkin/options/type/GithubIconOption.hx
@@ -19,10 +19,10 @@ class GithubIconOption extends TextOption
return usePortrait = value;
}
- public function new(user:Dynamic, desc:String, ?callback:Void->Void, ?customName:String, size:Int = 96, usePortrait:Bool = true) {
+ public function new(user:Dynamic, desc:String, ?callback:Void->Void, ?customName:String, size:Int = 96, usePortrait:Bool = true, waitUntilLoad:Float = 0.25) {
super(customName == null ? user.login : customName, desc, callback == null ? function() CoolUtil.openURL(user.html_url) : callback);
this.user = user;
- this.icon = new GithubUserIcon(user, size);
+ this.icon = new GithubUserIcon(user, size, waitUntilLoad);
this.usePortrait = usePortrait;
add(icon);
}
@@ -30,22 +30,28 @@ class GithubIconOption extends TextOption
class GithubUserIcon extends FlxSprite
{
- private var loading:Bool = false;
+ public var waitUntilLoad:Null;
private var user:Dynamic;
private var size:Int;
- public override function new(user:Dynamic, size:Int = 96) {
+ public override function new(user:Dynamic, size:Int = 96, waitUntilLoad:Float = 0.25) {
this.user = user;
this.size = size;
+ this.waitUntilLoad = waitUntilLoad;
super();
makeGraphic(size, size, FlxColor.TRANSPARENT);
antialiasing = true;
}
+ override function update(elapsed:Float) {
+ if(waitUntilLoad > 0) waitUntilLoad -= elapsed;
+ super.update(elapsed);
+ }
+
final mutex = new sys.thread.Mutex();
override function drawComplex(camera:FlxCamera):Void { // Making the image downlaod only if the player actually sees it on the screeeeen - Nex
- if(!loading) {
- loading = true;
+ if(waitUntilLoad <= 0) {
+ waitUntilLoad = null;
Main.execAsync(function() {
var key:String = 'GITHUB-USER:${user.login}';
var bmap:Dynamic = FlxG.bitmap.get(key);
@@ -57,7 +63,7 @@ class GithubUserIcon extends FlxSprite
var bytes = null;
if(unfLink) {
- try bytes = GitHub.__requestBytesOnGitHubServers('${user.avatar_url}?size=$size')
+ try bytes = HttpUtil.requestBytes('${user.avatar_url}?size=$size')
catch(e) Logs.traceColored([Logs.logText('Failed to download github pfp for ${user.login}: ${CoolUtil.removeIP(e.message)} - (Retrying using the api..)', RED)], ERROR);
if(bytes != null) {
@@ -68,7 +74,7 @@ class GithubUserIcon extends FlxSprite
if(planB) {
if(unfLink) user = GitHub.getUser(user.login, function(e) Logs.traceColored([Logs.logText('Failed to download github user info for ${user.login}: ${CoolUtil.removeIP(e.message)}', RED)], ERROR)); // Api part - Nex
- try bytes = GitHub.__requestBytesOnGitHubServers('${user.avatar_url}&size=$size')
+ try bytes = HttpUtil.requestBytes('${user.avatar_url}&size=$size')
catch(e) Logs.traceColored([Logs.logText('Failed to download github pfp for ${user.login}: ${CoolUtil.removeIP(e.message)}', RED)], ERROR);
if(bytes != null) bmap = BitmapData.fromBytes(bytes);