Skip to content

Commit

Permalink
Add setting deeplink launch data from BloxstrapRPC
Browse files Browse the repository at this point in the history
plus a bunch of tweaks to the bootstrapper
  • Loading branch information
pizzaboxer committed Aug 30, 2024
1 parent 719fbb8 commit f747f40
Show file tree
Hide file tree
Showing 4 changed files with 138 additions and 82 deletions.
23 changes: 12 additions & 11 deletions Bloxstrap/Bootstrapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -281,19 +281,21 @@ private void StartRoblox()

SetStatus(Strings.Bootstrapper_Status_Starting);

if (App.Settings.Prop.ForceRobloxLanguage)
if (_launchMode == LaunchMode.Player)
{
var match = Regex.Match(_launchCommandLine, "gameLocale:([a-z_]+)", RegexOptions.CultureInvariant);
if (App.Settings.Prop.ForceRobloxLanguage)
{
var match = Regex.Match(_launchCommandLine, "gameLocale:([a-z_]+)", RegexOptions.CultureInvariant);

if (match.Groups.Count == 2)
_launchCommandLine = _launchCommandLine.Replace("robloxLocale:en_us", $"robloxLocale:{match.Groups[1].Value}", StringComparison.InvariantCultureIgnoreCase);
}
if (match.Groups.Count == 2)
_launchCommandLine = _launchCommandLine.Replace("robloxLocale:en_us", $"robloxLocale:{match.Groups[1].Value}", StringComparison.InvariantCultureIgnoreCase);
}

// needed for the start event to fire
if (!String.IsNullOrEmpty(_launchCommandLine))
_launchCommandLine += " ";
if (!String.IsNullOrEmpty(_launchCommandLine))
_launchCommandLine += " ";

_launchCommandLine += "-isInstallerLaunch";
_launchCommandLine += "-isInstallerLaunch";
}

var startInfo = new ProcessStartInfo()
{
Expand All @@ -308,7 +310,7 @@ private void StartRoblox()
return;
}

using var startEvent = new EventWaitHandle(false, EventResetMode.ManualReset, "www.roblox.com/robloxStartedEvent");
using var startEvent = new EventWaitHandle(false, EventResetMode.ManualReset, AppData.StartEvent);

// v2.2.0 - byfron will trip if we keep a process handle open for over a minute, so we're doing this now
int gameClientPid;
Expand Down Expand Up @@ -357,7 +359,6 @@ private void StartRoblox()
autoclosePids.Add(pid);
}


string args = gameClientPid.ToString();

if (autoclosePids.Any())
Expand Down
45 changes: 44 additions & 1 deletion Bloxstrap/Integrations/ActivityWatcher.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
namespace Bloxstrap.Integrations
using System.Web;

namespace Bloxstrap.Integrations
{
public class ActivityWatcher : IDisposable
{
Expand Down Expand Up @@ -43,6 +45,7 @@ public class ActivityWatcher : IDisposable
public string ActivityMachineAddress = "";
public bool ActivityMachineUDMUX = false;
public bool ActivityIsTeleport = false;
public string ActivityLaunchData = "";
public ServerType ActivityServerType = ServerType.Public;

public bool IsDisposed = false;
Expand Down Expand Up @@ -119,6 +122,16 @@ public async void Start()
}
}

public string GetActivityDeeplink()
{
string deeplink = $"roblox://experiences/start?placeId={ActivityPlaceId}&gameInstanceId={ActivityJobId}";

if (!String.IsNullOrEmpty(ActivityLaunchData))
deeplink += "&launchData=" + HttpUtility.UrlEncode(ActivityLaunchData);

return deeplink;
}

private void ReadLogEntry(string entry)
{
const string LOG_IDENT = "ActivityWatcher::ReadLogEntry";
Expand Down Expand Up @@ -222,6 +235,7 @@ private void ReadLogEntry(string entry)
ActivityMachineAddress = "";
ActivityMachineUDMUX = false;
ActivityIsTeleport = false;
ActivityLaunchData = "";
ActivityServerType = ServerType.Public;

OnGameLeave?.Invoke(this, new EventArgs());
Expand Down Expand Up @@ -280,6 +294,35 @@ private void ReadLogEntry(string entry)
return;
}

if (message.Command == "SetLaunchData")
{
string? data;

try
{
data = message.Data.Deserialize<string>();
}
catch (Exception)
{
App.Logger.WriteLine(LOG_IDENT, "Failed to parse message! (JSON deserialization threw an exception)");
return;
}

if (data is null)
{
App.Logger.WriteLine(LOG_IDENT, "Failed to parse message! (JSON deserialization returned null)");
return;
}

if (data.Length > 200)
{
App.Logger.WriteLine(LOG_IDENT, "Data cannot be longer than 200 characters");
return;
}

ActivityLaunchData = data;
}

OnRPCMessage?.Invoke(this, message);

LastRPCRequest = DateTime.Now;
Expand Down
150 changes: 81 additions & 69 deletions Bloxstrap/Integrations/DiscordRichPresence.cs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ public void ProcessRPCMessage(Message message, bool implicitUpdate = true)
{
const string LOG_IDENT = "DiscordRichPresence::ProcessRPCMessage";

if (message.Command != "SetRichPresence")
if (message.Command != "SetRichPresence" && message.Command != "SetLaunchData")
return;

if (_currentPresence is null || _currentPresenceCopy is null)
Expand All @@ -61,95 +61,107 @@ public void ProcessRPCMessage(Message message, bool implicitUpdate = true)
return;
}

Models.BloxstrapRPC.RichPresence? presenceData;

// a lot of repeated code here, could this somehow be cleaned up?

try
{
presenceData = message.Data.Deserialize<Models.BloxstrapRPC.RichPresence>();
}
catch (Exception)
if (message.Command == "SetLaunchData")
{
App.Logger.WriteLine(LOG_IDENT, "Failed to parse message! (JSON deserialization threw an exception)");
return;
}
var buttonQuery = _currentPresence.Buttons.Where(x => x.Label == "Join server");

if (presenceData is null)
{
App.Logger.WriteLine(LOG_IDENT, "Failed to parse message! (JSON deserialization returned null)");
return;
}
if (!buttonQuery.Any())
return;

if (presenceData.Details is not null)
{
if (presenceData.Details.Length > 128)
App.Logger.WriteLine(LOG_IDENT, $"Details cannot be longer than 128 characters");
else if (presenceData.Details == "<reset>")
_currentPresence.Details = _currentPresenceCopy.Details;
else
_currentPresence.Details = presenceData.Details;
buttonQuery.First().Url = _activityWatcher.GetActivityDeeplink();
}

if (presenceData.State is not null)
else if (message.Command == "SetRichPresence")
{
if (presenceData.State.Length > 128)
App.Logger.WriteLine(LOG_IDENT, $"State cannot be longer than 128 characters");
else if (presenceData.State == "<reset>")
_currentPresence.State = _currentPresenceCopy.State;
else
_currentPresence.State = presenceData.State;
}

if (presenceData.TimestampStart == 0)
_currentPresence.Timestamps.Start = null;
else if (presenceData.TimestampStart is not null)
_currentPresence.Timestamps.StartUnixMilliseconds = presenceData.TimestampStart * 1000;
Models.BloxstrapRPC.RichPresence? presenceData;

if (presenceData.TimestampEnd == 0)
_currentPresence.Timestamps.End = null;
else if (presenceData.TimestampEnd is not null)
_currentPresence.Timestamps.EndUnixMilliseconds = presenceData.TimestampEnd * 1000;

if (presenceData.SmallImage is not null)
{
if (presenceData.SmallImage.Clear)
try
{
_currentPresence.Assets.SmallImageKey = "";
presenceData = message.Data.Deserialize<Models.BloxstrapRPC.RichPresence>();
}
else if (presenceData.SmallImage.Reset)
catch (Exception)
{
_currentPresence.Assets.SmallImageText = _currentPresenceCopy.Assets.SmallImageText;
_currentPresence.Assets.SmallImageKey = _currentPresenceCopy.Assets.SmallImageKey;
App.Logger.WriteLine(LOG_IDENT, "Failed to parse message! (JSON deserialization threw an exception)");
return;
}
else
{
if (presenceData.SmallImage.AssetId is not null)
_currentPresence.Assets.SmallImageKey = $"https://assetdelivery.roblox.com/v1/asset/?id={presenceData.SmallImage.AssetId}";

if (presenceData.SmallImage.HoverText is not null)
_currentPresence.Assets.SmallImageText = presenceData.SmallImage.HoverText;
if (presenceData is null)
{
App.Logger.WriteLine(LOG_IDENT, "Failed to parse message! (JSON deserialization returned null)");
return;
}
}

if (presenceData.LargeImage is not null)
{
if (presenceData.LargeImage.Clear)
if (presenceData.Details is not null)
{
_currentPresence.Assets.LargeImageKey = "";
if (presenceData.Details.Length > 128)
App.Logger.WriteLine(LOG_IDENT, $"Details cannot be longer than 128 characters");
else if (presenceData.Details == "<reset>")
_currentPresence.Details = _currentPresenceCopy.Details;
else
_currentPresence.Details = presenceData.Details;
}
else if (presenceData.LargeImage.Reset)

if (presenceData.State is not null)
{
_currentPresence.Assets.LargeImageText = _currentPresenceCopy.Assets.LargeImageText;
_currentPresence.Assets.LargeImageKey = _currentPresenceCopy.Assets.LargeImageKey;
if (presenceData.State.Length > 128)
App.Logger.WriteLine(LOG_IDENT, $"State cannot be longer than 128 characters");
else if (presenceData.State == "<reset>")
_currentPresence.State = _currentPresenceCopy.State;
else
_currentPresence.State = presenceData.State;
}
else

if (presenceData.TimestampStart == 0)
_currentPresence.Timestamps.Start = null;
else if (presenceData.TimestampStart is not null)
_currentPresence.Timestamps.StartUnixMilliseconds = presenceData.TimestampStart * 1000;

if (presenceData.TimestampEnd == 0)
_currentPresence.Timestamps.End = null;
else if (presenceData.TimestampEnd is not null)
_currentPresence.Timestamps.EndUnixMilliseconds = presenceData.TimestampEnd * 1000;

if (presenceData.SmallImage is not null)
{
if (presenceData.LargeImage.AssetId is not null)
_currentPresence.Assets.LargeImageKey = $"https://assetdelivery.roblox.com/v1/asset/?id={presenceData.LargeImage.AssetId}";
if (presenceData.SmallImage.Clear)
{
_currentPresence.Assets.SmallImageKey = "";
}
else if (presenceData.SmallImage.Reset)
{
_currentPresence.Assets.SmallImageText = _currentPresenceCopy.Assets.SmallImageText;
_currentPresence.Assets.SmallImageKey = _currentPresenceCopy.Assets.SmallImageKey;
}
else
{
if (presenceData.SmallImage.AssetId is not null)
_currentPresence.Assets.SmallImageKey = $"https://assetdelivery.roblox.com/v1/asset/?id={presenceData.SmallImage.AssetId}";

if (presenceData.SmallImage.HoverText is not null)
_currentPresence.Assets.SmallImageText = presenceData.SmallImage.HoverText;
}
}

if (presenceData.LargeImage.HoverText is not null)
_currentPresence.Assets.LargeImageText = presenceData.LargeImage.HoverText;
if (presenceData.LargeImage is not null)
{
if (presenceData.LargeImage.Clear)
{
_currentPresence.Assets.LargeImageKey = "";
}
else if (presenceData.LargeImage.Reset)
{
_currentPresence.Assets.LargeImageText = _currentPresenceCopy.Assets.LargeImageText;
_currentPresence.Assets.LargeImageKey = _currentPresenceCopy.Assets.LargeImageKey;
}
else
{
if (presenceData.LargeImage.AssetId is not null)
_currentPresence.Assets.LargeImageKey = $"https://assetdelivery.roblox.com/v1/asset/?id={presenceData.LargeImage.AssetId}";

if (presenceData.LargeImage.HoverText is not null)
_currentPresence.Assets.LargeImageText = presenceData.LargeImage.HoverText;
}
}
}

Expand Down
2 changes: 1 addition & 1 deletion Bloxstrap/UI/Elements/ContextMenu/MenuContainer.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ private void Window_Loaded(object? sender, RoutedEventArgs e)

private void RichPresenceMenuItem_Click(object sender, RoutedEventArgs e) => _watcher.RichPresence?.SetVisibility(((MenuItem)sender).IsChecked);

private void InviteDeeplinkMenuItem_Click(object sender, RoutedEventArgs e) => Clipboard.SetDataObject($"roblox://experiences/start?placeId={_activityWatcher?.ActivityPlaceId}&gameInstanceId={_activityWatcher?.ActivityJobId}");
private void InviteDeeplinkMenuItem_Click(object sender, RoutedEventArgs e) => Clipboard.SetDataObject(_activityWatcher?.GetActivityDeeplink());

private void ServerDetailsMenuItem_Click(object sender, RoutedEventArgs e) => ShowServerInformationWindow();

Expand Down

0 comments on commit f747f40

Please sign in to comment.