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 {