diff --git a/Project.xml b/Project.xml
index 029d6c890..3572496c2 100644
--- a/Project.xml
+++ b/Project.xml
@@ -125,6 +125,7 @@
+
diff --git a/source/Discord.hx b/source/Discord.hx
new file mode 100644
index 000000000..253a4f59a
--- /dev/null
+++ b/source/Discord.hx
@@ -0,0 +1,82 @@
+package;
+
+import Sys.sleep;
+import discord_rpc.DiscordRpc;
+
+using StringTools;
+
+class DiscordClient
+{
+ 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();
+ }
+
+ 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:Null, ?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');
+ }
+}
diff --git a/source/FreeplayState.hx b/source/FreeplayState.hx
index bfd67d31c..802f557f3 100644
--- a/source/FreeplayState.hx
+++ b/source/FreeplayState.hx
@@ -1,5 +1,8 @@
package;
+#if desktop
+import Discord.DiscordClient;
+#end
import flash.text.TextField;
import flixel.FlxG;
import flixel.FlxSprite;
@@ -49,6 +52,11 @@ class FreeplayState extends MusicBeatState
FlxG.sound.playMusic(Paths.music('freakyMenu'));
}
+ #if desktop
+ // Updating Discord Rich Presence
+ DiscordClient.changePresence("In the Menus", null);
+ #end
+
var isDebug:Bool = false;
#if debug
diff --git a/source/MainMenuState.hx b/source/MainMenuState.hx
index 369af2e87..a4c45ee1a 100644
--- a/source/MainMenuState.hx
+++ b/source/MainMenuState.hx
@@ -1,5 +1,8 @@
package;
+#if desktop
+import Discord.DiscordClient;
+#end
import flixel.FlxG;
import flixel.FlxObject;
import flixel.FlxSprite;
@@ -33,6 +36,11 @@ class MainMenuState extends MusicBeatState
override function create()
{
+ #if desktop
+ // Updating Discord Rich Presence
+ DiscordClient.changePresence("In the Menus", null);
+ #end
+
transIn = FlxTransitionableState.defaultTransIn;
transOut = FlxTransitionableState.defaultTransOut;
diff --git a/source/PlayState.hx b/source/PlayState.hx
index 3f20c552d..8d489bcfe 100644
--- a/source/PlayState.hx
+++ b/source/PlayState.hx
@@ -1,5 +1,8 @@
package;
+#if desktop
+import Discord.DiscordClient;
+#end
import Section.SwagSection;
import Song.SwagSong;
import WiggleEffect.WiggleEffectType;
@@ -128,6 +131,15 @@ class PlayState extends MusicBeatState
var inCutscene:Bool = false;
+ #if desktop
+ // Discord RPC variables
+ var storyDifficultyText:String = "";
+ var iconRPC:String = "";
+ var songLength:Float = 0;
+ var detailsText:String = "";
+ var detailsPausedText:String = "";
+ #end
+
override public function create()
{
if (FlxG.sound.music != null)
@@ -181,6 +193,48 @@ class PlayState extends MusicBeatState
dialogue = CoolUtil.coolTextFile(Paths.txt('thorns/thornsDialogue'));
}
+ #if desktop
+ // Making difficulty text for Discord Rich Presence.
+ switch (storyDifficulty)
+ {
+ case 0:
+ storyDifficultyText = "Easy";
+ case 1:
+ storyDifficultyText = "Normal";
+ case 2:
+ storyDifficultyText = "Hard";
+ }
+
+ iconRPC = SONG.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
+ if (isStoryMode)
+ {
+ detailsText = "Story Mode: Week " + storyWeek;
+ }
+ else
+ {
+ detailsText = "Freeplay";
+ }
+
+ // String for when the game is paused
+ detailsPausedText = "Paused - " + detailsText;
+
+ // Updating Discord Rich Presence.
+ DiscordClient.changePresence(detailsText, SONG.song + " (" + storyDifficultyText + ")", iconRPC);
+ #end
+
switch (SONG.song.toLowerCase())
{
case 'spookeez' | 'monster' | 'south':
@@ -1031,6 +1085,14 @@ class PlayState extends MusicBeatState
FlxG.sound.playMusic(Paths.inst(PlayState.SONG.song), 1, false);
FlxG.sound.music.onComplete = endSong;
vocals.play();
+
+ #if desktop
+ // Song duration in a float, useful for the time left feature
+ songLength = FlxG.sound.music.length;
+
+ // Updating Discord Rich Presence (with Time Left)
+ DiscordClient.changePresence(detailsText, SONG.song + " (" + storyDifficultyText + ")", iconRPC, true, songLength);
+ #end
}
var debugNum:Int = 0;
@@ -1273,11 +1335,53 @@ class PlayState extends MusicBeatState
if (!startTimer.finished)
startTimer.active = true;
paused = false;
+
+ #if desktop
+ if (startTimer.finished)
+ {
+ DiscordClient.changePresence(detailsText, SONG.song + " (" + storyDifficultyText + ")", iconRPC, true, songLength - Conductor.songPosition);
+ }
+ else
+ {
+ DiscordClient.changePresence(detailsText, SONG.song + " (" + storyDifficultyText + ")", iconRPC);
+ }
+ #end
}
super.closeSubState();
}
+ override public function onFocus():Void
+ {
+ #if desktop
+ if (health > 0 && !paused)
+ {
+ if (Conductor.songPosition > 0.0)
+ {
+ DiscordClient.changePresence(detailsText, SONG.song + " (" + storyDifficultyText + ")", iconRPC, true, songLength - Conductor.songPosition);
+ }
+ else
+ {
+ DiscordClient.changePresence(detailsText, SONG.song + " (" + storyDifficultyText + ")", iconRPC);
+ }
+ }
+ #end
+
+ super.onFocus();
+ }
+
+ override public function onFocusLost():Void
+ {
+ #if desktop
+ if (health > 0 && !paused)
+ {
+ DiscordClient.changePresence(detailsPausedText, SONG.song + " (" + storyDifficultyText + ")", iconRPC);
+ }
+ #end
+
+ super.onFocusLost();
+ }
+
function resyncVocals():Void
{
vocals.pause();
@@ -1373,11 +1477,19 @@ class PlayState extends MusicBeatState
}
else
openSubState(new PauseSubState(boyfriend.getScreenPosition().x, boyfriend.getScreenPosition().y));
+
+ #if desktop
+ DiscordClient.changePresence(detailsPausedText, SONG.song + " (" + storyDifficultyText + ")", iconRPC);
+ #end
}
if (FlxG.keys.justPressed.SEVEN)
{
FlxG.switchState(new ChartingState());
+
+ #if desktop
+ DiscordClient.changePresence("Chart Editor", null, null, true);
+ #end
}
// FlxG.watch.addQuick('VOL', vocals.amplitudeLeft);
@@ -1543,6 +1655,11 @@ class PlayState extends MusicBeatState
openSubState(new GameOverSubstate(boyfriend.getScreenPosition().x, boyfriend.getScreenPosition().y));
// FlxG.switchState(new GameOverState(boyfriend.getScreenPosition().x, boyfriend.getScreenPosition().y));
+
+ #if desktop
+ // Game Over doesn't get his own variable because it's only used here
+ DiscordClient.changePresence("Game Over - " + detailsText, SONG.song + " (" + storyDifficultyText + ")", iconRPC);
+ #end
}
if (unspawnNotes[0] != null)
diff --git a/source/StoryMenuState.hx b/source/StoryMenuState.hx
index 1e27eed7c..1c2dc8783 100644
--- a/source/StoryMenuState.hx
+++ b/source/StoryMenuState.hx
@@ -1,5 +1,8 @@
package;
+#if desktop
+import Discord.DiscordClient;
+#end
import flixel.FlxG;
import flixel.FlxSprite;
import flixel.addons.transition.FlxTransitionableState;
@@ -109,6 +112,11 @@ class StoryMenuState extends MusicBeatState
add(grpLocks);
trace("Line 70");
+
+ #if desktop
+ // Updating Discord Rich Presence
+ DiscordClient.changePresence("In the Menus", null);
+ #end
for (i in 0...weekData.length)
{
diff --git a/source/TitleState.hx b/source/TitleState.hx
index 8685b9560..e8a1990e8 100644
--- a/source/TitleState.hx
+++ b/source/TitleState.hx
@@ -1,5 +1,9 @@
package;
+#if desktop
+import Discord.DiscordClient;
+import sys.thread.Thread;
+#end
import flixel.FlxG;
import flixel.FlxSprite;
import flixel.addons.transition.FlxTransitionSprite.GraphicTransTileDiamond;
@@ -87,6 +91,10 @@ class TitleState extends MusicBeatState
startIntro();
});
#end
+
+ #if desktop
+ DiscordClient.initialize();
+ #end
}
var logoBl:FlxSprite;
@@ -291,12 +299,12 @@ class TitleState extends MusicBeatState
if (version.trim() != NGio.GAME_VER_NUMS.trim() && !OutdatedSubState.leftState)
{
+ FlxG.switchState(new OutdatedSubState());
trace('OLD VERSION!');
trace('old ver');
trace(version.trim());
trace('cur ver');
trace(NGio.GAME_VER_NUMS.trim());
- FlxG.switchState(new OutdatedSubState());
}
else
{