diff --git a/README.md b/README.md
index d09c559a..ac87a79c 100644
--- a/README.md
+++ b/README.md
@@ -97,6 +97,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/shaders/engine/editorWaveforms.frag b/assets/shaders/engine/editorWaveforms.frag
index 7a424adb..53fc9fdf 100644
--- a/assets/shaders/engine/editorWaveforms.frag
+++ b/assets/shaders/engine/editorWaveforms.frag
@@ -2,11 +2,11 @@
// Used in charter by waveforms
-const vec3 gradient1 = vec3(114./255., 81./255., 135./255);
-const vec3 gradient2 = vec3(144./255., 80./255., 186./255);
+const vec3 gradient1 = vec3(114.0/255.0, 81.0/255.0, 135.0/255.0);
+const vec3 gradient2 = vec3(144.0/255.0, 80.0/255.0, 186.0/255.0);
-const vec4 outlinecolor = vec4(vec3(.1), .1);
-const vec3 lowdetailcol = vec3(0., 0., 1.);
+const vec4 outlinecolor = vec4(0.1);
+const vec3 lowdetailcol = vec3(0.0, 0.0, 1.0);
uniform vec2 textureRes;
uniform float pixelOffset;
@@ -19,18 +19,17 @@ uniform ivec2 waveformSize;
uniform bool lowDetail;
float getAmplitude(vec2 pixel) {
- float pixelID = floor((pixel.y+pixelOffset)/3.);
-
+ float pixelID = floor((pixel.y+pixelOffset)/3.0);
+
// TODO: INVESTIGATE THE 1.+ AND WHY IT WORKS (SRSLY I GOT NO CLUE) -lunar
- vec2 wavePixel = vec2(mod(pixelID,waveformSize.x), 1.+floor(pixelID/waveformSize.x));
+ vec2 wavePixel = vec2(mod(pixelID,waveformSize.x), 1.0+floor(pixelID/waveformSize.x));
vec4 waveData = texture2D(waveformTexture, wavePixel / waveformSize);
- switch (int(mod(wavePixel.x, 3.))) {
- case 0: return waveData.r; break;
- case 1: return waveData.g; break;
- case 2: return waveData.b; break;
- }
- return 0.;
+ int id = int(mod(wavePixel.x, 3.0));
+ if(id == 0) return waveData.r;
+ if(id == 1) return waveData.g;
+ if(id == 2) return waveData.b;
+ return 0.0;
}
bool inWaveForm(vec2 pixel, float width) {
@@ -41,40 +40,40 @@ bool inWaveForm(vec2 pixel, float width) {
void highDetailWaveform(vec2 pixel, float amplitude, float ampwidth) {
if (inWaveForm(pixel, ampwidth)) {
vec3 gradientColor = mix(gradient1, gradient2, openfl_TextureCoordv.x);
- gradientColor *= pixel.y+pixelOffset>playerPosition ? .7 : 1.;
+ gradientColor *= pixel.y+pixelOffset>playerPosition ? 0.7 : 1.0;
- float remapCoord = (amplitude/textureRes.x)/2.;
+ float remapCoord = (amplitude/textureRes.x)/2.0;
- float mappedCoord = map(openfl_TextureCoordv.x, remapCoord, 1.-remapCoord, 0., 1.);
- float hightlightAmount = 1.-(abs(mappedCoord-0.5)*2.);
+ float mappedCoord = map(openfl_TextureCoordv.x, remapCoord, 1.0-remapCoord, 0.0, 1.0);
+ float hightlightAmount = 1.0-(abs(mappedCoord-0.5)*2.0);
- gradientColor = mix(gradientColor, gradientColor * vec3(1.8), map(hightlightAmount, 0., 1., .5, 1.));
+ gradientColor = mix(gradientColor, gradientColor * vec3(1.8), map(hightlightAmount, 0.0, 1.0, 0.5, 1.0));
- float ampwidthHighlight = (1.-(amplitude*(1./3.))) * textureRes.x;
+ float ampwidthHighlight = (1.0-(amplitude*(1.0/3.0))) * textureRes.x;
if (inWaveForm(pixel, ampwidthHighlight)) {
- float remapCoord = (ampwidthHighlight/textureRes.x)/2.;
+ float remapCoord = (ampwidthHighlight/textureRes.x)/2.0;
- float mappedCoord = map(openfl_TextureCoordv.x, remapCoord, 1.-remapCoord, 0., 1.);
- float hightlightAmount = 1.-(abs(mappedCoord-0.5)*2.);
+ float mappedCoord = map(openfl_TextureCoordv.x, remapCoord, 1.0-remapCoord, 0.0, 1.0);
+ float hightlightAmount = 1.0-(abs(mappedCoord-0.5)*2.0);
- gradientColor = mix(gradientColor, gradientColor * vec3(1.8), map(hightlightAmount, 0., 1., .5, 1.));
+ gradientColor = mix(gradientColor, gradientColor * vec3(1.8), map(hightlightAmount, 0.0, 1.0, 0.5, 1.0));
}
-
- gl_FragColor = vec4(vec3(gradientColor * mix(0.5, .8, amplitude))*openfl_Alphav, openfl_Alphav);
- float lastAmplitude = getAmplitude(pixel - vec2(0., -1.));
- float lastAmpwidth = (1.-lastAmplitude) * textureRes.x;
+ gl_FragColor = vec4(vec3(gradientColor * mix(0.5, 0.8, amplitude))*openfl_Alphav, openfl_Alphav);
+
+ float lastAmplitude = getAmplitude(pixel - vec2(0.0, -1.0));
+ float lastAmpwidth = (1.0-lastAmplitude) * textureRes.x;
if (!inWaveForm(pixel, lastAmpwidth))
- gl_FragColor -= outlinecolor*mix(0.5, .8, amplitude);
+ gl_FragColor -= outlinecolor*mix(0.5, 0.8, amplitude);
- float nextAmplitude = getAmplitude(pixel - vec2(0., 1.));
- float nextAmpwidth = (1.-nextAmplitude) * textureRes.x;
+ float nextAmplitude = getAmplitude(pixel - vec2(0.0, 1.0));
+ float nextAmpwidth = (1.0-nextAmplitude) * textureRes.x;
if (!inWaveForm(pixel, nextAmpwidth))
- gl_FragColor -= outlinecolor*mix(0.5, .8, amplitude);
+ gl_FragColor -= outlinecolor*mix(0.5, 0.8, amplitude);
- if (!inWaveForm(pixel, ampwidth+2.) && amplitude > 0.)
+ if (!inWaveForm(pixel, ampwidth+2.0) && amplitude > 0.0)
gl_FragColor -= outlinecolor;
}
}
@@ -82,9 +81,9 @@ void highDetailWaveform(vec2 pixel, float amplitude, float ampwidth) {
void lowDetailWaveform(vec2 pixel, float amplitude, float ampwidth) {
if (inWaveForm(pixel, ampwidth)) {
vec3 color = lowdetailcol;
- color *= pixel.y+pixelOffset>playerPosition ? .7 : 1.;
+ color *= pixel.y+pixelOffset>playerPosition ? 0.7 : 1.0;
- gl_FragColor = vec4(color, 1.);
+ gl_FragColor = vec4(color, 1.0);
}
}
@@ -93,10 +92,10 @@ void main()
vec2 pixel = openfl_TextureCoordv * textureRes;
float amplitude = getAmplitude(pixel);
- float ampwidth = (1.-amplitude) * textureRes.x;
+ float ampwidth = (1.0-amplitude) * textureRes.x;
if (lowDetail)
lowDetailWaveform(pixel, amplitude, ampwidth);
- else
+ else
highDetailWaveform(pixel, amplitude, ampwidth);
}
\ No newline at end of file
diff --git a/libs.xml b/libs.xml
index 81618ce1..5afacfc3 100644
--- a/libs.xml
+++ b/libs.xml
@@ -10,12 +10,12 @@
-
+
-
+
diff --git a/project.xml b/project.xml
index aee55825..6f26ce30 100644
--- a/project.xml
+++ b/project.xml
@@ -170,10 +170,11 @@
-
+
+
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/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/utils/DiscordUtil.hx b/source/funkin/backend/utils/DiscordUtil.hx
index cdd24b6c..733790fa 100644
--- a/source/funkin/backend/utils/DiscordUtil.hx
+++ b/source/funkin/backend/utils/DiscordUtil.hx
@@ -1,62 +1,77 @@
package funkin.backend.utils;
+import flixel.util.typeLimit.OneOfTwo;
+import openfl.display.BitmapData;
+import funkin.backend.system.macros.Utils;
import funkin.backend.scripting.events.DiscordPresenceUpdateEvent;
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 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 function init()
+ {
#if DISCORD_RPC
reloadJsonData();
- discordThread = Thread.create(function() {
+
+ discordThread = Thread.create(function()
+ {
while (true)
{
- while(!ready) {
- Sys.sleep(1/60);
+ while (ready)
+ {
+ #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'));
- 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 changePresence(details:String, state:String, ?smallImageKey:String)
+ {
#if DISCORD_RPC
changePresenceAdvanced({
state: state,
@@ -66,12 +81,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 +103,203 @@ class DiscordUtil {
#end
}
- public static function changePresenceAdvanced(data:#if DISCORD_RPC DiscordPresenceOptions #else Dynamic #end) {
- #if DISCORD_RPC
- if (data == null) return;
+ @: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 (data == null)
+ return;
+
+ // copy last presence
if (data.largeImageKey == null)
- data.largeImageKey = DiscordUtil.data.logoKey;
+ data.largeImageKey = config.logoKey;
if (data.largeImageText == null)
- data.largeImageText = DiscordUtil.data.logoText;
+ data.largeImageText = config.logoText;
#if GLOBAL_SCRIPT
var event = funkin.backend.scripting.GlobalScript.event("onDiscordPresenceUpdate", EventManager.get(DiscordPresenceUpdateEvent).recycle(data));
- if (event.cancelled) return;
+ if (event.cancelled)
+ return;
+ data = event.presence;
#end
+ lastPresence = data;
- DiscordRpc.presence(data);
+ var dp:DiscordRichPresence = DiscordRichPresence.create();
+ // TODO: make this use a reflection-like macro
+ // strings
+ /*if(data.state != null) dp.state = fixString(data.state);
+ if(data.details != null) dp.details = fixString(data.details);
+ if(data.largeImageKey != null) dp.largeImageKey = fixString(data.largeImageKey);
+ if(data.largeImageText != null) dp.largeImageText = fixString(data.largeImageText);
+ if(data.smallImageKey != null) dp.smallImageKey = fixString(data.smallImageKey);
+ if(data.smallImageText != null) dp.smallImageText = fixString(data.smallImageText);
+ if(data.partyId != null) dp.partyId = fixString(data.partyId);
+ if(data.matchSecret != null) dp.matchSecret = fixString(data.matchSecret);
+ if(data.joinSecret != null) dp.joinSecret = fixString(data.joinSecret);
+ if(data.spectateSecret != null) dp.spectateSecret = fixString(data.spectateSecret);
+
+ // other
+ if(data.startTimestamp != null) dp.startTimestamp = data.startTimestamp;
+ if(data.endTimestamp != null) dp.endTimestamp = data.endTimestamp;
+ if(data.partySize != null) dp.partySize = data.partySize;
+ if(data.partyMax != null) dp.partyMax = data.partyMax;
+ if(data.partyPrivacy != null) dp.partyPrivacy = data.partyPrivacy;
+ if(data.instance != null) dp.instance = data.instance; */
+
+ 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);
+
+ Discord.UpdatePresence(cpp.RawConstPointer.addressOf(dp));
#end
}
- public static function changeClientID(id:String) {
- #if DISCORD_RPC
- if (currentID != null) {
- DiscordRpc.shutdown();
- }
+ 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);
+ Discord.Initialize(id, cpp.RawPointer.addressOf(handlers), 1, null);
+ #end
+
+ return currentID = id;
+ }
+
+ public static function shutdown()
+ {
ready = false;
-
- DiscordRpc.start({
- clientID: id,
- onReady: function() {
- Logs.trace('Discord RPC started');
- ready = true;
- },
- onError: onError,
- onDisconnected: onDisconnected
- });
- currentID = id;
-
- #end
- }
-
- public static function shutdown() {
#if DISCORD_RPC
- DiscordRpc.shutdown();
+ Discord.Shutdown();
#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
+ {
+ var requestPtr:cpp.Star = cpp.ConstPointer.fromRaw(request).ptr;
+
+ user = new DUser();
+ user.init(requestPtr);
+
+ Logs.trace('(Discord) Connected to User (${user.tag})');
+
+ ready = true;
}
- 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
+ {
+ Sys.println('Discord: Disconnected ($errorCode: ${cast (message, String)})');
+ }
+
+ private static function onError(errorCode:Int, message:cpp.ConstCharStar):Void
+ {
+ Sys.println('Discord: Error ($errorCode: ${cast (message, String)})');
}
#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 tag: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;
+
+ public function new() {}
+ public function init(userData:cpp.Star)
+ {
+ userId = userData.userId;
+ username = userData.username;
+ discriminator = Std.parseInt(userData.discriminator);
+ avatar = userData.avatar;
+
+ if (discriminator != 0)
+ tag = '${username}#${discriminator}';
+ else
+ tag = '${username}';
+ }
+
+ /**
+ * 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'));
+}
+
+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;
+}
diff --git a/source/funkin/backend/utils/HttpUtil.hx b/source/funkin/backend/utils/HttpUtil.hx
new file mode 100644
index 00000000..1edbbfd2
--- /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:
+ trace("Redirected with status code: " + status);
+ return true;
+ }
+ return false;
+ }
+}
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/options/type/GithubIconOption.hx b/source/funkin/options/type/GithubIconOption.hx
index cbbef1ed..7f41b8d4 100644
--- a/source/funkin/options/type/GithubIconOption.hx
+++ b/source/funkin/options/type/GithubIconOption.hx
@@ -57,7 +57,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 +68,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);