hxdiscord_rpc, away3D fork and much more

5H FOR COMPILING.

5
FUCKING
HOURS
FOR MACRO ERRORS.

Co-Authored-By: Ne_Eo <NeeEoo@users.noreply.github.com>
This commit is contained in:
⍚~Nex
2024-03-23 01:29:48 +01:00
co-authored by Ne_Eo
parent 6ae7ed7aad
commit 9a38232fd4
11 changed files with 355 additions and 171 deletions
+1 -2
View File
@@ -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)
</details>
+35 -36
View File
@@ -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);
}
+2 -2
View File
@@ -10,12 +10,12 @@
<!-- Other Libraries -->
<git name="hscript-improved" url="https://github.com/FNF-CNE-Devs/hscript-improved" ref="custom-classes" />
<git name="discord-rpc" url="https://github.com/Aidan63/linc_discord-rpc" />
<git name="flxanimate" url="https://github.com/FNF-CNE-Devs/flxanimate" />
<lib name="hxdiscord_rpc" />
<lib name="hxvlc" />
<!-- Documentation and other features -->
<lib name="away3d" />
<lib name="away3d" url="https://github.com/FNF-CNE-Devs/away3d" />
<!-- <lib name="dox" /> -->
<lib name="format" />
<lib name="markdown" />
+2 -1
View File
@@ -170,10 +170,11 @@
<haxelib name="flxanimate" />
<haxelib name="hscript-improved" />
<haxelib name="discord-rpc" if="DISCORD_RPC"/>
<haxelib name="hxdiscord_rpc" if="DISCORD_RPC"/>
<haxelib name="markdown" />
<haxedef name="no-deprecation-warnings"/>
<haxedef name="DISCORD_DISABLE_IO_THREAD" if="DISCORD_RPC"/>
<!-- _________________________________ Additional stuff _______________________________ -->
@@ -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;
}
+5 -59
View File
@@ -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<GitHubRelease> {
#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<GitHubContributor> {
#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<GitHubContributor> {
#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<GitHubRelease>, 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)";
@@ -37,4 +37,21 @@ class Utils {
return expr;
#end
}
public static macro function safeSet(variable:Null<Expr>, value:Null<Expr>):Null<Expr> {
#if macro
return macro if (${value} != null) ${variable} = ${value};
#end
}
public static macro function safeSetWrapper(variable:Null<Expr>, value:Null<Expr>, wrapper:Null<Expr>):Null<Expr> {
#if macro
return macro if (${value} != null) ${variable} = ${wrapper}(${value});
#end
}
public static macro function safeReflection(variable:Null<Expr>, value:Null<Expr>, field:Null<Expr>):Null<Expr> {
#if macro
return macro if (Reflect.hasField(${value}, ${field})) ${variable} = Reflect.field(${value}, ${field});
#end
}
}
+218 -64
View File
@@ -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<DiscordUser>):Void
{
var requestPtr:cpp.Star<DiscordUser> = 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;
}
}
@: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<DiscordUser>)
{
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<Int, haxe.Int64>;
var ?endTimestamp:OneOfTwo<Int, haxe.Int64>;
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<Int, cpp.Int8>;
}
+71
View File
@@ -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;
}
}
+1
View File
@@ -106,6 +106,7 @@ class NoteGroup extends FlxTypedGroup<Note> {
if (members == null)
return null;
// TODO: maybe lastIndexOf
var index:Int = members.indexOfFromLast(Object);
if (index < 0)
@@ -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);