Add setting deeplink launch data from BloxstrapRPC

plus a bunch of tweaks to the bootstrapper
This commit is contained in:
pizzaboxer 2024-08-30 01:40:32 +01:00
parent 719fbb898e
commit f747f40ca5
No known key found for this signature in database
GPG Key ID: 59D4A1DBAD0F2BA8
4 changed files with 144 additions and 88 deletions

View File

@ -281,20 +281,22 @@ namespace Bloxstrap
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);
}
if (!String.IsNullOrEmpty(_launchCommandLine))
_launchCommandLine += " ";
_launchCommandLine += "-isInstallerLaunch";
}
// needed for the start event to fire
if (!String.IsNullOrEmpty(_launchCommandLine))
_launchCommandLine += " ";
_launchCommandLine += "-isInstallerLaunch";
var startInfo = new ProcessStartInfo()
{
FileName = _playerLocation,
@ -308,7 +310,7 @@ namespace Bloxstrap
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;
@ -357,7 +359,6 @@ namespace Bloxstrap
autoclosePids.Add(pid);
}
string args = gameClientPid.ToString();
if (autoclosePids.Any())

View File

@ -1,4 +1,6 @@
namespace Bloxstrap.Integrations
using System.Web;
namespace Bloxstrap.Integrations
{
public class ActivityWatcher : IDisposable
{
@ -43,6 +45,7 @@
public string ActivityMachineAddress = "";
public bool ActivityMachineUDMUX = false;
public bool ActivityIsTeleport = false;
public string ActivityLaunchData = "";
public ServerType ActivityServerType = ServerType.Public;
public bool IsDisposed = false;
@ -119,6 +122,16 @@
}
}
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";
@ -222,6 +235,7 @@
ActivityMachineAddress = "";
ActivityMachineUDMUX = false;
ActivityIsTeleport = false;
ActivityLaunchData = "";
ActivityServerType = ServerType.Public;
OnGameLeave?.Invoke(this, new EventArgs());
@ -280,6 +294,35 @@
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;

View File

@ -51,7 +51,7 @@ namespace Bloxstrap.Integrations
{
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)
@ -61,95 +61,107 @@ namespace Bloxstrap.Integrations
return;
}
Models.BloxstrapRPC.RichPresence? presenceData;
// a lot of repeated code here, could this somehow be cleaned up?
try
if (message.Command == "SetLaunchData")
{
presenceData = message.Data.Deserialize<Models.BloxstrapRPC.RichPresence>();
var buttonQuery = _currentPresence.Buttons.Where(x => x.Label == "Join server");
if (!buttonQuery.Any())
return;
buttonQuery.First().Url = _activityWatcher.GetActivityDeeplink();
}
catch (Exception)
else if (message.Command == "SetRichPresence")
{
App.Logger.WriteLine(LOG_IDENT, "Failed to parse message! (JSON deserialization threw an exception)");
return;
}
Models.BloxstrapRPC.RichPresence? presenceData;
if (presenceData is null)
{
App.Logger.WriteLine(LOG_IDENT, "Failed to parse message! (JSON deserialization returned null)");
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;
}
if (presenceData.State is not null)
{
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;
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)
{
_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;
if (presenceData.State is not null)
{
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;
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)
{
_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 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;
}
}
}

View File

@ -104,7 +104,7 @@ namespace Bloxstrap.UI.Elements.ContextMenu
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();