Merge branch 'main' of https://github.com/FNF-CNE-Devs/CodenameEngine-Dev
This commit is contained in:
@@ -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)
|
||||
</details>
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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");
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<libraries>
|
||||
<!-- OpenFL & Lime (Required for Flixel) -->
|
||||
<lib name="openfl" version="9.2.2"/>
|
||||
<lib name="lime" version="8.1.2"/>
|
||||
<lib name="openfl" version="9.2.2" />
|
||||
<lib name="lime" version="8.1.2" />
|
||||
|
||||
<!-- Flixel -->
|
||||
<git name="flixel" url="https://github.com/FNF-CNE-Devs/flixel" />
|
||||
@@ -10,13 +10,14 @@
|
||||
|
||||
<!-- 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" />
|
||||
<git name="hxdiscord_rpc" url="https://github.com/NeeEoo/hxdiscord_rpc" /> <!-- Since original repo wants non fork of discord-rpc -->
|
||||
<!-- <lib name="hxdiscord_rpc" /> -->
|
||||
<lib name="hxvlc" />
|
||||
|
||||
<!-- Documentation and other features -->
|
||||
<lib name="away3d" />
|
||||
<git name="away3d" url="https://github.com/FNF-CNE-Devs/away3d" />
|
||||
<!-- <lib name="dox" /> -->
|
||||
<lib name="format" />
|
||||
<lib name="markdown" />
|
||||
</libraries>
|
||||
</libraries>
|
||||
|
||||
+8
-3
@@ -161,6 +161,13 @@
|
||||
|
||||
<!-- _______________________________ Libraries ______________________________ -->
|
||||
|
||||
<!-- KEEP BOTH OF THESE AS THERE ARE SOME PARTICULAR CASES! -->
|
||||
<define name="disable-version-check"/>
|
||||
<haxedef name="disable-version-check"/>
|
||||
|
||||
<haxedef name="no-deprecation-warnings"/>
|
||||
<haxedef name="DISCORD_DISABLE_IO_THREAD" if="DISCORD_RPC"/>
|
||||
|
||||
<haxelib name="flixel" />
|
||||
<haxelib name="flixel-addons" />
|
||||
|
||||
@@ -170,11 +177,9 @@
|
||||
<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"/>
|
||||
|
||||
<!-- _________________________________ Additional stuff _______________________________ -->
|
||||
|
||||
<section if="COMPILE_ALL_CLASSES">
|
||||
|
||||
@@ -79,12 +79,14 @@ class GlobalScript {
|
||||
}
|
||||
|
||||
public static function event<T:CancellableEvent>(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<Dynamic>) {
|
||||
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();
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -55,7 +55,7 @@ class MainState extends FlxState {
|
||||
|
||||
Main.refreshAssets();
|
||||
ModsFolder.onModSwitch.dispatch(ModsFolder.currentModFolder);
|
||||
DiscordUtil.reloadJsonData();
|
||||
DiscordUtil.init();
|
||||
EventsData.reloadEvents();
|
||||
TitleState.initialized = false;
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -92,6 +92,8 @@ class UpdateAvailableScreen extends MusicBeatState {
|
||||
add(skipButton);
|
||||
|
||||
oldPos = FlxG.mouse.getScreenPosition();
|
||||
|
||||
DiscordUtil.call("onMenuLoaded", ["Update Available Screen"]);
|
||||
}
|
||||
|
||||
var destY:Float = 0;
|
||||
|
||||
@@ -61,6 +61,8 @@ class UpdateScreen extends MusicBeatState {
|
||||
updater.execute();
|
||||
|
||||
FlxG.camera.addShader(rainbowShader = new CustomShader("engine/updaterShader"));
|
||||
|
||||
DiscordUtil.call("onMenuLoaded", ["Update Screen"]);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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<T:CancellableEvent>(name:String, event:T):T
|
||||
{
|
||||
if (script != null)
|
||||
script.call(name, [event]);
|
||||
return event;
|
||||
}
|
||||
|
||||
public static function call(name:String, ?args:Array<Dynamic>)
|
||||
{
|
||||
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<DiscordUser>):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<DiscordUser>):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;
|
||||
}
|
||||
}
|
||||
|
||||
@: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<DiscordUser>)
|
||||
{
|
||||
return init(cpp.ConstPointer.fromRaw(req).ptr);
|
||||
}
|
||||
|
||||
public static function init(userData:cpp.Star<DiscordUser>)
|
||||
{
|
||||
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<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>;
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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() {
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -116,7 +116,7 @@ class FreeplayState extends MusicBeatState
|
||||
}
|
||||
}
|
||||
|
||||
DiscordUtil.changePresence("In the Menus", null);
|
||||
DiscordUtil.call("onMenuLoaded", ["Freeplay"]);
|
||||
|
||||
super.create();
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ class MainMenuState extends MusicBeatState
|
||||
{
|
||||
super.create();
|
||||
|
||||
DiscordUtil.changePresence("In the Menus", null);
|
||||
DiscordUtil.call("onMenuLoaded", ["Main Menu"]);
|
||||
|
||||
CoolUtil.playMenuSong();
|
||||
|
||||
|
||||
@@ -116,7 +116,7 @@ class StoryMenuState extends MusicBeatState {
|
||||
|
||||
changeWeek(0, true);
|
||||
|
||||
DiscordUtil.changePresence("In the Menus", null);
|
||||
DiscordUtil.call("onMenuLoaded", ["Story Menu"]);
|
||||
CoolUtil.playMenuSong();
|
||||
}
|
||||
|
||||
|
||||
@@ -36,6 +36,8 @@ class TitleState extends MusicBeatState
|
||||
startIntro();
|
||||
|
||||
super.create();
|
||||
|
||||
DiscordUtil.call("onMenuLoaded", ["Title Screen"]);
|
||||
}
|
||||
|
||||
var logoBl:FlxSprite;
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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"]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -70,11 +70,8 @@ class OptionsScreen extends FlxTypedSpriteGroup<OptionType> {
|
||||
}
|
||||
|
||||
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) {}
|
||||
|
||||
@@ -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<Float>;
|
||||
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);
|
||||
|
||||
Reference in New Issue
Block a user