mirror of
https://github.com/FunkinCrew/Funkin.git
synced 2024-11-21 10:48:21 -05:00
Merge branch 'feature/discord-rpc-resurrected' into rewrite/master
This commit is contained in:
commit
7a3d983bba
14 changed files with 412 additions and 173 deletions
5
.vscode/settings.json
vendored
5
.vscode/settings.json
vendored
|
@ -111,6 +111,11 @@
|
|||
"target": "hl",
|
||||
"args": ["-debug"]
|
||||
},
|
||||
{
|
||||
"label": "Windows / Debug (Discord)",
|
||||
"target": "windows",
|
||||
"args": ["-debug", "-DFEATURE_DEBUG_FUNCTIONS", "-DFEATURE_DISCORD_RPC"]
|
||||
},
|
||||
{
|
||||
"label": "Windows / Debug (FlxAnimate Test)",
|
||||
"target": "windows",
|
||||
|
|
2
art
2
art
|
@ -1 +1 @@
|
|||
Subproject commit 1f64f3e7403a090b164f4442d10152b2be5d3d0a
|
||||
Subproject commit fbd3e3df77734606d88516770b71b56e6fa04bce
|
14
hmm.json
14
hmm.json
|
@ -7,13 +7,6 @@
|
|||
"ref": "a1eab7b9bf507b87200a3341719054fe427f3b15",
|
||||
"url": "https://github.com/FunkinCrew/FlxPartialSound.git"
|
||||
},
|
||||
{
|
||||
"name": "discord_rpc",
|
||||
"type": "git",
|
||||
"dir": null,
|
||||
"ref": "2d83fa863ef0c1eace5f1cf67c3ac315d1a3a8a5",
|
||||
"url": "https://github.com/FunkinCrew/linc_discord-rpc"
|
||||
},
|
||||
{
|
||||
"name": "flixel",
|
||||
"type": "git",
|
||||
|
@ -108,6 +101,13 @@
|
|||
"ref": "147294123f983e35f50a966741474438069a7a8f",
|
||||
"url": "https://github.com/FunkinCrew/hxcpp-debugger"
|
||||
},
|
||||
{
|
||||
"name": "hxdiscord_rpc",
|
||||
"type": "git",
|
||||
"dir": null,
|
||||
"ref": "82c47ecc1a454b7dd644e4fcac7e91155f176dec",
|
||||
"url": "https://github.com/FunkinCrew/hxdiscord_rpc"
|
||||
},
|
||||
{
|
||||
"name": "hxjsonast",
|
||||
"type": "git",
|
||||
|
|
|
@ -479,10 +479,9 @@ class Project extends HXProject {
|
|||
// Should default to true on workspace builds and false on release builds.
|
||||
REDIRECT_ASSETS_FOLDER.apply(this, isDebug() && isDesktop());
|
||||
|
||||
// Should be true on release, non-tester builds.
|
||||
// Should be true on desktop, release, non-tester builds.
|
||||
// We don't want testers to accidentally leak songs to their Discord friends!
|
||||
// TODO: Re-enable this.
|
||||
FEATURE_DISCORD_RPC.apply(this, false && !FEATURE_DEBUG_FUNCTIONS.isEnabled(this));
|
||||
FEATURE_DISCORD_RPC.apply(this, isDesktop() && !FEATURE_DEBUG_FUNCTIONS.isEnabled(this));
|
||||
|
||||
// Should be true only on web builds.
|
||||
// Audio context issues only exist there.
|
||||
|
@ -654,7 +653,7 @@ class Project extends HXProject {
|
|||
}
|
||||
|
||||
if (FEATURE_DISCORD_RPC.isEnabled(this)) {
|
||||
addHaxelib('discord_rpc'); // Discord API
|
||||
addHaxelib('hxdiscord_rpc'); // Discord API
|
||||
}
|
||||
|
||||
if (FEATURE_NEWGROUNDS.isEnabled(this)) {
|
||||
|
|
|
@ -1,42 +1,42 @@
|
|||
package funkin;
|
||||
|
||||
import funkin.data.freeplay.player.PlayerRegistry;
|
||||
import funkin.ui.debug.charting.ChartEditorState;
|
||||
import funkin.ui.transition.LoadingState;
|
||||
import flixel.FlxState;
|
||||
import flixel.addons.transition.FlxTransitionableState;
|
||||
import flixel.addons.transition.FlxTransitionSprite.GraphicTransTileDiamond;
|
||||
import flixel.addons.transition.TransitionData;
|
||||
import flixel.FlxSprite;
|
||||
import flixel.FlxState;
|
||||
import flixel.graphics.FlxGraphic;
|
||||
import flixel.math.FlxPoint;
|
||||
import flixel.math.FlxRect;
|
||||
import flixel.FlxSprite;
|
||||
import flixel.system.debug.log.LogStyle;
|
||||
import flixel.util.FlxColor;
|
||||
import funkin.util.macro.MacroUtil;
|
||||
import funkin.util.WindowUtil;
|
||||
import funkin.play.PlayStatePlaylist;
|
||||
import openfl.display.BitmapData;
|
||||
import funkin.data.story.level.LevelRegistry;
|
||||
import funkin.data.notestyle.NoteStyleRegistry;
|
||||
import funkin.data.freeplay.style.FreeplayStyleRegistry;
|
||||
import funkin.data.event.SongEventRegistry;
|
||||
import funkin.data.stage.StageRegistry;
|
||||
import funkin.data.dialogue.conversation.ConversationRegistry;
|
||||
import funkin.data.dialogue.dialoguebox.DialogueBoxRegistry;
|
||||
import funkin.data.dialogue.speaker.SpeakerRegistry;
|
||||
import funkin.data.freeplay.album.AlbumRegistry;
|
||||
import funkin.data.freeplay.player.PlayerRegistry;
|
||||
import funkin.data.freeplay.style.FreeplayStyleRegistry;
|
||||
import funkin.data.notestyle.NoteStyleRegistry;
|
||||
import funkin.data.song.SongRegistry;
|
||||
import funkin.data.event.SongEventRegistry;
|
||||
import funkin.data.stage.StageRegistry;
|
||||
import funkin.data.story.level.LevelRegistry;
|
||||
import funkin.modding.module.ModuleHandler;
|
||||
import funkin.play.character.CharacterData.CharacterDataParser;
|
||||
import funkin.play.notes.notekind.NoteKindManager;
|
||||
import funkin.modding.module.ModuleHandler;
|
||||
import funkin.play.PlayStatePlaylist;
|
||||
import funkin.ui.debug.charting.ChartEditorState;
|
||||
import funkin.ui.title.TitleState;
|
||||
import funkin.ui.transition.LoadingState;
|
||||
import funkin.util.CLIUtil;
|
||||
import funkin.util.CLIUtil.CLIParams;
|
||||
import funkin.util.macro.MacroUtil;
|
||||
import funkin.util.TimerUtil;
|
||||
import funkin.util.TrackerUtil;
|
||||
import funkin.util.WindowUtil;
|
||||
import openfl.display.BitmapData;
|
||||
#if FEATURE_DISCORD_RPC
|
||||
import Discord.DiscordClient;
|
||||
import funkin.api.discord.DiscordClient;
|
||||
#end
|
||||
|
||||
/**
|
||||
|
@ -125,10 +125,10 @@ class InitState extends FlxState
|
|||
// DISCORD API SETUP
|
||||
//
|
||||
#if FEATURE_DISCORD_RPC
|
||||
DiscordClient.initialize();
|
||||
DiscordClient.instance.init();
|
||||
|
||||
Application.current.onExit.add(function(exitCode) {
|
||||
DiscordClient.shutdown();
|
||||
lime.app.Application.current.onExit.add(function(exitCode) {
|
||||
DiscordClient.instance.shutdown();
|
||||
});
|
||||
#end
|
||||
|
||||
|
|
|
@ -1,91 +0,0 @@
|
|||
package funkin.api.discord;
|
||||
|
||||
import Sys.sleep;
|
||||
#if FEATURE_DISCORD_RPC
|
||||
import discord_rpc.DiscordRpc;
|
||||
#end
|
||||
|
||||
class DiscordClient
|
||||
{
|
||||
#if FEATURE_DISCORD_RPC
|
||||
public function new()
|
||||
{
|
||||
trace("Discord Client starting...");
|
||||
DiscordRpc.start(
|
||||
{
|
||||
clientID: "814588678700924999",
|
||||
onReady: onReady,
|
||||
onError: onError,
|
||||
onDisconnected: onDisconnected
|
||||
});
|
||||
trace("Discord Client started.");
|
||||
|
||||
while (true)
|
||||
{
|
||||
DiscordRpc.process();
|
||||
sleep(2);
|
||||
// trace("Discord Client Update");
|
||||
}
|
||||
|
||||
DiscordRpc.shutdown();
|
||||
}
|
||||
|
||||
public static function shutdown()
|
||||
{
|
||||
DiscordRpc.shutdown();
|
||||
}
|
||||
|
||||
static function onReady()
|
||||
{
|
||||
DiscordRpc.presence(
|
||||
{
|
||||
details: "In the Menus",
|
||||
state: null,
|
||||
largeImageKey: 'icon',
|
||||
largeImageText: "Friday Night Funkin'"
|
||||
});
|
||||
}
|
||||
|
||||
static function onError(_code:Int, _message:String)
|
||||
{
|
||||
trace('Error! $_code : $_message');
|
||||
}
|
||||
|
||||
static function onDisconnected(_code:Int, _message:String)
|
||||
{
|
||||
trace('Disconnected! $_code : $_message');
|
||||
}
|
||||
|
||||
public static function initialize()
|
||||
{
|
||||
var DiscordDaemon = sys.thread.Thread.create(() -> {
|
||||
new DiscordClient();
|
||||
});
|
||||
trace("Discord Client initialized");
|
||||
}
|
||||
|
||||
public static function changePresence(details:String, ?state:String, ?smallImageKey:String, ?hasStartTimestamp:Bool, ?endTimestamp:Float)
|
||||
{
|
||||
var startTimestamp:Float = if (hasStartTimestamp) Date.now().getTime() else 0;
|
||||
|
||||
if (endTimestamp > 0)
|
||||
{
|
||||
endTimestamp = startTimestamp + endTimestamp;
|
||||
}
|
||||
|
||||
DiscordRpc.presence(
|
||||
{
|
||||
details: details,
|
||||
state: state,
|
||||
largeImageKey: 'icon',
|
||||
largeImageText: "Friday Night Funkin'",
|
||||
smallImageKey: smallImageKey,
|
||||
// Obtained times are in milliseconds so they are divided so Discord can use it
|
||||
startTimestamp: Std.int(startTimestamp / 1000),
|
||||
endTimestamp: Std.int(endTimestamp / 1000)
|
||||
});
|
||||
|
||||
// trace('Discord RPC Updated. Arguments: $details, $state, $smallImageKey, $hasStartTimestamp, $endTimestamp');
|
||||
}
|
||||
#end
|
||||
}
|
204
source/funkin/api/discord/DiscordClient.hx
Normal file
204
source/funkin/api/discord/DiscordClient.hx
Normal file
|
@ -0,0 +1,204 @@
|
|||
package funkin.api.discord;
|
||||
|
||||
#if FEATURE_DISCORD_RPC
|
||||
import hxdiscord_rpc.Discord;
|
||||
import hxdiscord_rpc.Types;
|
||||
import sys.thread.Thread;
|
||||
|
||||
class DiscordClient
|
||||
{
|
||||
static final CLIENT_ID:String = "816168432860790794";
|
||||
|
||||
public static var instance(get, never):DiscordClient;
|
||||
static var _instance:Null<DiscordClient> = null;
|
||||
|
||||
static function get_instance():DiscordClient
|
||||
{
|
||||
if (DiscordClient._instance == null) _instance = new DiscordClient();
|
||||
if (DiscordClient._instance == null) throw "Could not initialize singleton DiscordClient!";
|
||||
return DiscordClient._instance;
|
||||
}
|
||||
|
||||
var handlers:DiscordEventHandlers;
|
||||
|
||||
private function new()
|
||||
{
|
||||
trace('[DISCORD] Initializing event handlers...');
|
||||
|
||||
handlers = DiscordEventHandlers.create();
|
||||
|
||||
handlers.ready = cpp.Function.fromStaticFunction(onReady);
|
||||
handlers.disconnected = cpp.Function.fromStaticFunction(onDisconnected);
|
||||
handlers.errored = cpp.Function.fromStaticFunction(onError);
|
||||
}
|
||||
|
||||
public function init():Void
|
||||
{
|
||||
trace('[DISCORD] Initializing connection...');
|
||||
|
||||
// Discord.initialize(CLIENT_ID, handlers, true, null);
|
||||
Discord.Initialize(CLIENT_ID, cpp.RawPointer.addressOf(handlers), 1, null);
|
||||
|
||||
createDaemon();
|
||||
}
|
||||
|
||||
var daemon:Thread = null;
|
||||
|
||||
function createDaemon():Void
|
||||
{
|
||||
daemon = Thread.create(doDaemonWork);
|
||||
}
|
||||
|
||||
function doDaemonWork():Void
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
trace('[DISCORD] Performing client update...');
|
||||
|
||||
#if DISCORD_DISABLE_IO_THREAD
|
||||
Discord.updateConnection();
|
||||
#end
|
||||
|
||||
Discord.runCallbacks();
|
||||
Sys.sleep(2);
|
||||
}
|
||||
}
|
||||
|
||||
public function shutdown():Void
|
||||
{
|
||||
trace('[DISCORD] Shutting down...');
|
||||
|
||||
Discord.shutdown();
|
||||
}
|
||||
|
||||
public function setPresence(params:DiscordClientPresenceParams):Void
|
||||
{
|
||||
trace('[DISCORD] Updating presence... (${params})');
|
||||
|
||||
Discord.updatePresence(buildPresence(params));
|
||||
}
|
||||
|
||||
function buildPresence(params:DiscordClientPresenceParams):DiscordRichPresence
|
||||
{
|
||||
var presence = DiscordRichPresence.create();
|
||||
|
||||
// Presence should always be playing the game.
|
||||
presence.type = DiscordActivityType_Playing;
|
||||
|
||||
// Text when hovering over the large image. We just leave this as the game name.
|
||||
presence.largeImageText = "Friday Night Funkin'";
|
||||
|
||||
// State should be generally what the person is doing, like "In the Menus" or "Pico (Pico Mix) [Freeplay Hard]"
|
||||
presence.state = cast(params.state, Null<String>);
|
||||
// Details should be what the person is specifically doing, including stuff like timestamps (maybe something like "03:24 elapsed").
|
||||
presence.details = cast(params.details, Null<String>);
|
||||
|
||||
// The large image displaying what the user is doing.
|
||||
// This should probably be album art.
|
||||
// IMPORTANT NOTE: This can be an asset key uploaded to Discord's developer panel OR any URL you like.
|
||||
presence.largeImageKey = cast(params.largeImageKey, Null<String>) ?? "album-volume1";
|
||||
|
||||
trace('[DISCORD] largeImageKey: ${presence.largeImageKey}');
|
||||
|
||||
// TODO: Make this use the song's album art.
|
||||
// presence.largeImageKey = "icon";
|
||||
// presence.largeImageKey = "https://f4.bcbits.com/img/a0746694746_16.jpg";
|
||||
|
||||
// The small inset image for what the user is doing.
|
||||
// This can be the opponent's health icon?
|
||||
// NOTE: Like largeImageKey, this can be a URL, or an asset key.
|
||||
presence.smallImageKey = cast(params.smallImageKey, Null<String>);
|
||||
|
||||
// NOTE: In previous versions, this showed as "Elapsed", but now shows as playtime and doesn't look good
|
||||
// presence.startTimestamp = time - 10;
|
||||
// presence.endTimestamp = time + 30;
|
||||
|
||||
final button1:DiscordButton = DiscordButton.create();
|
||||
button1.label = "Play on Web";
|
||||
button1.url = Constants.URL_NEWGROUNDS;
|
||||
presence.buttons[0] = button1;
|
||||
|
||||
final button2:DiscordButton = DiscordButton.create();
|
||||
button2.label = "Download";
|
||||
button2.url = Constants.URL_ITCH;
|
||||
presence.buttons[1] = button2;
|
||||
|
||||
return presence;
|
||||
}
|
||||
|
||||
// TODO: WHAT THE FUCK get this pointer bullfuckery out of here
|
||||
private static function onReady(request:cpp.RawConstPointer<DiscordUser>):Void
|
||||
{
|
||||
trace('[DISCORD] Client has connected!');
|
||||
|
||||
final username:String = request[0].username;
|
||||
final globalName:String = request[0].username;
|
||||
final discriminator:Int = Std.parseInt(request[0].discriminator);
|
||||
|
||||
if (discriminator != 0)
|
||||
{
|
||||
trace('[DISCORD] User: ${username}#${discriminator} (${globalName})');
|
||||
}
|
||||
else
|
||||
{
|
||||
trace('[DISCORD] User: @${username} (${globalName})');
|
||||
}
|
||||
}
|
||||
|
||||
private static function onDisconnected(errorCode:Int, message:cpp.ConstCharStar):Void
|
||||
{
|
||||
trace('[DISCORD] Client has disconnected! ($errorCode) "${cast (message, String)}"');
|
||||
}
|
||||
|
||||
private static function onError(errorCode:Int, message:cpp.ConstCharStar):Void
|
||||
{
|
||||
trace('[DISCORD] Client has received an error! ($errorCode) "${cast (message, String)}"');
|
||||
}
|
||||
|
||||
// public var type(get, set):DiscordActivityType;
|
||||
// public var state(get, set):String;
|
||||
// public var details(get, set):String;
|
||||
// public var startTimestamp(get, set):Int;
|
||||
// public var endTimestamp(get, set):Int;
|
||||
// public var largeImageKey(get, set):String;
|
||||
// public var largeImageText(get, set):String;
|
||||
// public var smallImageKey(get, set):String;
|
||||
// public var smallImageText(get, set):String;
|
||||
//
|
||||
//
|
||||
// public var partyId(get, set)
|
||||
// public var partySize(get, set)
|
||||
// public var partyMax(get, set)
|
||||
// public var partyPrivacy(get, set)
|
||||
//
|
||||
// public var buttons(get, set)
|
||||
//
|
||||
// public var matchSecret(get, set)
|
||||
// public var joinSecret(get, set)
|
||||
// public var spectateSecret(get, set)
|
||||
}
|
||||
|
||||
typedef DiscordClientPresenceParams =
|
||||
{
|
||||
/**
|
||||
* The first row of text below the game title.
|
||||
*/
|
||||
var state:String;
|
||||
|
||||
/**
|
||||
* The second row of text below the game title.
|
||||
* Use `null` to display no text.
|
||||
*/
|
||||
var details:Null<String>;
|
||||
|
||||
/**
|
||||
* A large, 4-row high image to the left of the content.
|
||||
*/
|
||||
var ?largeImageKey:String;
|
||||
|
||||
/**
|
||||
* A small, inset image to the bottom right of `largeImageKey`.
|
||||
*/
|
||||
var ?smallImageKey:String;
|
||||
}
|
||||
#end
|
|
@ -15,8 +15,8 @@ import flixel.tweens.FlxEase;
|
|||
import flixel.tweens.FlxTween;
|
||||
import flixel.ui.FlxBar;
|
||||
import flixel.util.FlxColor;
|
||||
import flixel.util.FlxTimer;
|
||||
import flixel.util.FlxStringUtil;
|
||||
import flixel.util.FlxTimer;
|
||||
import funkin.api.newgrounds.NGio;
|
||||
import funkin.audio.FunkinSound;
|
||||
import funkin.audio.VoicesGroup;
|
||||
|
@ -44,12 +44,12 @@ import funkin.play.cutscene.dialogue.Conversation;
|
|||
import funkin.play.cutscene.VanillaCutscenes;
|
||||
import funkin.play.cutscene.VideoCutscene;
|
||||
import funkin.play.notes.NoteDirection;
|
||||
import funkin.play.notes.notekind.NoteKindManager;
|
||||
import funkin.play.notes.NoteSplash;
|
||||
import funkin.play.notes.NoteSprite;
|
||||
import funkin.play.notes.notestyle.NoteStyle;
|
||||
import funkin.play.notes.Strumline;
|
||||
import funkin.play.notes.SustainTrail;
|
||||
import funkin.play.notes.notekind.NoteKindManager;
|
||||
import funkin.play.scoring.Scoring;
|
||||
import funkin.play.song.Song;
|
||||
import funkin.play.stage.Stage;
|
||||
|
@ -68,7 +68,7 @@ import openfl.display.BitmapData;
|
|||
import openfl.geom.Rectangle;
|
||||
import openfl.Lib;
|
||||
#if FEATURE_DISCORD_RPC
|
||||
import Discord.DiscordClient;
|
||||
import funkin.api.discord.DiscordClient;
|
||||
#end
|
||||
|
||||
/**
|
||||
|
@ -447,10 +447,8 @@ class PlayState extends MusicBeatSubState
|
|||
|
||||
#if FEATURE_DISCORD_RPC
|
||||
// Discord RPC variables
|
||||
var storyDifficultyText:String = '';
|
||||
var iconRPC:String = '';
|
||||
var detailsText:String = '';
|
||||
var detailsPausedText:String = '';
|
||||
var discordRPCAlbum:String = '';
|
||||
var discordRPCIcon:String = '';
|
||||
#end
|
||||
|
||||
/**
|
||||
|
@ -994,7 +992,15 @@ class PlayState extends MusicBeatSubState
|
|||
}
|
||||
|
||||
#if FEATURE_DISCORD_RPC
|
||||
DiscordClient.changePresence(detailsPausedText, currentSong.song + ' (' + storyDifficultyText + ')', iconRPC);
|
||||
DiscordClient.instance.setPresence(
|
||||
{
|
||||
details: 'Paused - ${buildDiscordRPCDetails()}',
|
||||
|
||||
state: buildDiscordRPCState(),
|
||||
|
||||
largeImageKey: discordRPCAlbum,
|
||||
smallImageKey: discordRPCIcon
|
||||
});
|
||||
#end
|
||||
}
|
||||
}
|
||||
|
@ -1083,8 +1089,14 @@ class PlayState extends MusicBeatSubState
|
|||
}
|
||||
|
||||
#if FEATURE_DISCORD_RPC
|
||||
// Game Over doesn't get his own variable because it's only used here
|
||||
DiscordClient.changePresence('Game Over - ' + detailsText, currentSong.song + ' (' + storyDifficultyText + ')', iconRPC);
|
||||
DiscordClient.instance.setPresence(
|
||||
{
|
||||
details: 'Game Over - ${buildDiscordRPCDetails()}',
|
||||
state: buildDiscordRPCState(),
|
||||
|
||||
largeImageKey: discordRPCAlbum,
|
||||
smallImageKey: discordRPCIcon
|
||||
});
|
||||
#end
|
||||
}
|
||||
else if (isPlayerDying)
|
||||
|
@ -1295,14 +1307,29 @@ class PlayState extends MusicBeatSubState
|
|||
Countdown.resumeCountdown();
|
||||
|
||||
#if FEATURE_DISCORD_RPC
|
||||
if (startTimer.finished)
|
||||
if (Conductor.instance.songPosition > 0)
|
||||
{
|
||||
DiscordClient.changePresence(detailsText, '${currentChart.songName} ($storyDifficultyText)', iconRPC, true,
|
||||
currentSongLengthMs - Conductor.instance.songPosition);
|
||||
// DiscordClient.changePresence(detailsText, '${currentChart.songName} ($discordRPCDifficulty)', discordRPCIcon, true,
|
||||
// currentSongLengthMs - Conductor.instance.songPosition);
|
||||
DiscordClient.instance.setPresence(
|
||||
{
|
||||
state: buildDiscordRPCState(),
|
||||
details: buildDiscordRPCDetails(),
|
||||
|
||||
largeImageKey: discordRPCAlbum,
|
||||
smallImageKey: discordRPCIcon
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
DiscordClient.changePresence(detailsText, '${currentChart.songName} ($storyDifficultyText)', iconRPC);
|
||||
DiscordClient.instance.setPresence(
|
||||
{
|
||||
state: buildDiscordRPCState(),
|
||||
details: buildDiscordRPCDetails(),
|
||||
|
||||
largeImageKey: discordRPCAlbum,
|
||||
smallImageKey: discordRPCIcon
|
||||
});
|
||||
}
|
||||
#end
|
||||
|
||||
|
@ -1328,16 +1355,32 @@ class PlayState extends MusicBeatSubState
|
|||
#end
|
||||
|
||||
#if FEATURE_DISCORD_RPC
|
||||
if (health > Constants.HEALTH_MIN && !paused && FlxG.autoPause)
|
||||
if (health > Constants.HEALTH_MIN && !isGamePaused && FlxG.autoPause)
|
||||
{
|
||||
if (Conductor.instance.songPosition > 0.0) DiscordClient.changePresence(detailsText, currentSong.song
|
||||
+ ' ('
|
||||
+ storyDifficultyText
|
||||
+ ')', iconRPC, true,
|
||||
currentSongLengthMs
|
||||
- Conductor.instance.songPosition);
|
||||
if (Conductor.instance.songPosition > 0.0)
|
||||
{
|
||||
DiscordClient.instance.setPresence(
|
||||
{
|
||||
state: buildDiscordRPCState(),
|
||||
details: buildDiscordRPCDetails(),
|
||||
|
||||
largeImageKey: discordRPCAlbum,
|
||||
smallImageKey: discordRPCIcon
|
||||
});
|
||||
}
|
||||
else
|
||||
DiscordClient.changePresence(detailsText, currentSong.song + ' (' + storyDifficultyText + ')', iconRPC);
|
||||
{
|
||||
DiscordClient.instance.setPresence(
|
||||
{
|
||||
state: buildDiscordRPCState(),
|
||||
details: buildDiscordRPCDetails(),
|
||||
|
||||
largeImageKey: discordRPCAlbum,
|
||||
smallImageKey: discordRPCIcon
|
||||
});
|
||||
// DiscordClient.changePresence(detailsText, '${currentChart.songName} ($discordRPCDifficulty)', discordRPCIcon, true,
|
||||
// currentSongLengthMs - Conductor.instance.songPosition);
|
||||
}
|
||||
}
|
||||
#end
|
||||
|
||||
|
@ -1354,8 +1397,17 @@ class PlayState extends MusicBeatSubState
|
|||
#end
|
||||
|
||||
#if FEATURE_DISCORD_RPC
|
||||
if (health > Constants.HEALTH_MIN && !paused && FlxG.autoPause) DiscordClient.changePresence(detailsPausedText,
|
||||
currentSong.song + ' (' + storyDifficultyText + ')', iconRPC);
|
||||
if (health > Constants.HEALTH_MIN && !isGamePaused && FlxG.autoPause)
|
||||
{
|
||||
DiscordClient.instance.setPresence(
|
||||
{
|
||||
state: buildDiscordRPCState(),
|
||||
details: buildDiscordRPCDetails(),
|
||||
|
||||
largeImageKey: discordRPCAlbum,
|
||||
smallImageKey: discordRPCIcon
|
||||
});
|
||||
}
|
||||
#end
|
||||
|
||||
super.onFocusLost();
|
||||
|
@ -1653,6 +1705,11 @@ class PlayState extends MusicBeatSubState
|
|||
iconP2.zIndex = 850;
|
||||
add(iconP2);
|
||||
iconP2.cameras = [camHUD];
|
||||
|
||||
#if FEATURE_DISCORD_RPC
|
||||
discordRPCAlbum = 'album-${currentChart.album}';
|
||||
discordRPCIcon = 'icon-${currentCharacterData.opponent}';
|
||||
#end
|
||||
}
|
||||
|
||||
//
|
||||
|
@ -1768,29 +1825,53 @@ class PlayState extends MusicBeatSubState
|
|||
function initDiscord():Void
|
||||
{
|
||||
#if FEATURE_DISCORD_RPC
|
||||
storyDifficultyText = difficultyString();
|
||||
iconRPC = currentSong.player2;
|
||||
|
||||
// To avoid having duplicate images in Discord assets
|
||||
switch (iconRPC)
|
||||
{
|
||||
case 'senpai-angry':
|
||||
iconRPC = 'senpai';
|
||||
case 'monster-christmas':
|
||||
iconRPC = 'monster';
|
||||
case 'mom-car':
|
||||
iconRPC = 'mom';
|
||||
}
|
||||
|
||||
// String that contains the mode defined here so it isn't necessary to call changePresence for each mode
|
||||
detailsText = isStoryMode ? 'Story Mode: Week $storyWeek' : 'Freeplay';
|
||||
detailsPausedText = 'Paused - $detailsText';
|
||||
// Determine the details strings once and reuse them.
|
||||
|
||||
// Updating Discord Rich Presence.
|
||||
DiscordClient.changePresence(detailsText, '${currentChart.songName} ($storyDifficultyText)', iconRPC);
|
||||
DiscordClient.instance.setPresence(
|
||||
{
|
||||
state: buildDiscordRPCState(),
|
||||
details: buildDiscordRPCDetails(),
|
||||
|
||||
largeImageKey: discordRPCAlbum,
|
||||
smallImageKey: discordRPCIcon
|
||||
});
|
||||
#end
|
||||
}
|
||||
|
||||
function buildDiscordRPCDetails():String
|
||||
{
|
||||
if (PlayStatePlaylist.isStoryMode)
|
||||
{
|
||||
return 'Story Mode: ${PlayStatePlaylist.campaignTitle}';
|
||||
}
|
||||
else
|
||||
{
|
||||
if (isChartingMode)
|
||||
{
|
||||
return 'Chart Editor [Playtest]';
|
||||
}
|
||||
else if (isPracticeMode)
|
||||
{
|
||||
return 'Freeplay [Practice]';
|
||||
}
|
||||
else if (isBotPlayMode)
|
||||
{
|
||||
return 'Freeplay [Bot Play]';
|
||||
}
|
||||
else
|
||||
{
|
||||
return 'Freeplay';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function buildDiscordRPCState():String
|
||||
{
|
||||
var discordRPCDifficulty = PlayState.instance.currentDifficulty.replace('-', ' ').toTitleCase();
|
||||
return '${currentChart.songName} [${discordRPCDifficulty}]';
|
||||
}
|
||||
|
||||
function initPreciseInputs():Void
|
||||
{
|
||||
PreciseInputManager.instance.onInputPressed.add(onKeyPress);
|
||||
|
@ -1985,7 +2066,15 @@ class PlayState extends MusicBeatSubState
|
|||
|
||||
#if FEATURE_DISCORD_RPC
|
||||
// Updating Discord Rich Presence (with Time Left)
|
||||
DiscordClient.changePresence(detailsText, '${currentChart.songName} ($storyDifficultyText)', iconRPC, true, currentSongLengthMs);
|
||||
DiscordClient.instance.setPresence(
|
||||
{
|
||||
state: buildDiscordRPCState(),
|
||||
details: buildDiscordRPCDetails(),
|
||||
|
||||
largeImageKey: discordRPCAlbum,
|
||||
smallImageKey: discordRPCIcon
|
||||
});
|
||||
// DiscordClient.changePresence(detailsText, '${currentChart.songName} ($discordRPCDifficulty)', discordRPCIcon, true, currentSongLengthMs);
|
||||
#end
|
||||
|
||||
if (startTimestamp > 0)
|
||||
|
|
|
@ -323,6 +323,11 @@ class BaseCharacter extends Bopper
|
|||
this.cameraFocusPoint = new FlxPoint(charCenterX + _data.cameraOffsets[0], charCenterY + _data.cameraOffsets[1]);
|
||||
}
|
||||
|
||||
public function getHealthIconId():String
|
||||
{
|
||||
return _data?.healthIcon?.id ?? Constants.DEFAULT_HEALTH_ICON;
|
||||
}
|
||||
|
||||
public function initHealthIcon(isOpponent:Bool):Void
|
||||
{
|
||||
if (!isOpponent)
|
||||
|
@ -332,7 +337,7 @@ class BaseCharacter extends Bopper
|
|||
trace('[WARN] Player 1 health icon not found!');
|
||||
return;
|
||||
}
|
||||
PlayState.instance.iconP1.configure(_data.healthIcon);
|
||||
PlayState.instance.iconP1.configure(_data?.healthIcon);
|
||||
PlayState.instance.iconP1.flipX = !PlayState.instance.iconP1.flipX; // BF is looking the other way.
|
||||
}
|
||||
else
|
||||
|
@ -342,7 +347,7 @@ class BaseCharacter extends Bopper
|
|||
trace('[WARN] Player 2 health icon not found!');
|
||||
return;
|
||||
}
|
||||
PlayState.instance.iconP2.configure(_data.healthIcon);
|
||||
PlayState.instance.iconP2.configure(_data?.healthIcon);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2274,8 +2274,25 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
|||
this.openBackupAvailableDialog(welcomeDialog);
|
||||
}
|
||||
}
|
||||
|
||||
#if FEATURE_DISCORD_RPC
|
||||
updateDiscordRPC();
|
||||
#end
|
||||
}
|
||||
|
||||
#if FEATURE_DISCORD_RPC
|
||||
function updateDiscordRPC():Void
|
||||
{
|
||||
funkin.api.discord.DiscordClient.instance.setPresence(
|
||||
{
|
||||
// TODO: Make this display the song name and update when it changes.
|
||||
// state: '${currentSongName} [${selectedDifficulty}]',
|
||||
state: null,
|
||||
details: 'Chart Editor [Charting]'
|
||||
});
|
||||
}
|
||||
#end
|
||||
|
||||
function setupWelcomeMusic()
|
||||
{
|
||||
this.welcomeMusic.loadEmbedded(Paths.music('chartEditorLoop/chartEditorLoop'));
|
||||
|
|
|
@ -54,6 +54,9 @@ import funkin.util.SortUtil;
|
|||
import openfl.display.BlendMode;
|
||||
import funkin.data.freeplay.style.FreeplayStyleRegistry;
|
||||
import funkin.data.song.SongData.SongMusicData;
|
||||
#if FEATURE_DISCORD_RPC
|
||||
import funkin.api.discord.DiscordClient;
|
||||
#end
|
||||
|
||||
/**
|
||||
* Parameters used to initialize the FreeplayState.
|
||||
|
@ -338,7 +341,7 @@ class FreeplayState extends MusicBeatSubState
|
|||
|
||||
#if FEATURE_DISCORD_RPC
|
||||
// Updating Discord Rich Presence
|
||||
DiscordClient.changePresence('In the Menus', null);
|
||||
DiscordClient.instance.setPresence({state: 'In the Menus', details: null});
|
||||
#end
|
||||
|
||||
var isDebug:Bool = false;
|
||||
|
|
|
@ -28,7 +28,7 @@ import funkin.ui.story.StoryMenuState;
|
|||
import funkin.ui.Prompt;
|
||||
import funkin.util.WindowUtil;
|
||||
#if FEATURE_DISCORD_RPC
|
||||
import Discord.DiscordClient;
|
||||
import funkin.api.discord.DiscordClient;
|
||||
#end
|
||||
#if newgrounds
|
||||
import funkin.ui.NgPrompt;
|
||||
|
@ -55,8 +55,7 @@ class MainMenuState extends MusicBeatState
|
|||
override function create():Void
|
||||
{
|
||||
#if FEATURE_DISCORD_RPC
|
||||
// Updating Discord Rich Presence
|
||||
DiscordClient.changePresence("In the Menus", null);
|
||||
DiscordClient.instance.setPresence({state: "In the Menus", details: null});
|
||||
#end
|
||||
|
||||
FlxG.cameras.reset(new FunkinCamera('mainMenu'));
|
||||
|
|
|
@ -23,6 +23,10 @@ import funkin.ui.MusicBeatState;
|
|||
import funkin.ui.transition.LoadingState;
|
||||
import funkin.ui.transition.StickerSubState;
|
||||
import funkin.util.MathUtil;
|
||||
import openfl.utils.Assets;
|
||||
#if FEATURE_DISCORD_RPC
|
||||
import funkin.api.discord.DiscordClient;
|
||||
#end
|
||||
|
||||
class StoryMenuState extends MusicBeatState
|
||||
{
|
||||
|
@ -217,7 +221,7 @@ class StoryMenuState extends MusicBeatState
|
|||
|
||||
#if FEATURE_DISCORD_RPC
|
||||
// Updating Discord Rich Presence
|
||||
DiscordClient.changePresence('In the Menus', null);
|
||||
DiscordClient.instance.setPresence({state: 'In the Menus', details: null});
|
||||
#end
|
||||
}
|
||||
|
||||
|
|
|
@ -78,7 +78,12 @@ class Constants
|
|||
/**
|
||||
* Link to download the game on Itch.io.
|
||||
*/
|
||||
public static final URL_ITCH:String = 'https://ninja-muffin24.itch.io/funkin/purchase';
|
||||
public static final URL_ITCH:String = 'https://ninja-muffin24.itch.io/funkin';
|
||||
|
||||
/**
|
||||
* Link to play the game on Newgrounds.
|
||||
*/
|
||||
public static final URL_NEWGROUNDS:String = 'https://www.newgrounds.com/portal/view/770371';
|
||||
|
||||
/**
|
||||
* Link to the game's page on Kickstarter.
|
||||
|
|
Loading…
Reference in a new issue