first commit
This commit is contained in:
194
NitroxClient/MonoBehaviours/Discord/DiscordClient.cs
Normal file
194
NitroxClient/MonoBehaviours/Discord/DiscordClient.cs
Normal file
@@ -0,0 +1,194 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using DiscordGameSDKWrapper;
|
||||
using NitroxClient.Communication.Abstract;
|
||||
using NitroxClient.MonoBehaviours.Gui.MainMenu.ServersList;
|
||||
using NitroxModel;
|
||||
using NitroxModel.Core;
|
||||
using NitroxModel.Packets;
|
||||
using UnityEngine;
|
||||
using UnityEngine.SceneManagement;
|
||||
|
||||
namespace NitroxClient.MonoBehaviours.Discord;
|
||||
|
||||
public class DiscordClient : MonoBehaviour
|
||||
{
|
||||
private const long CLIENT_ID = 405122994348752896;
|
||||
private const int RETRY_INTERVAL = 60;
|
||||
|
||||
private static DiscordClient main;
|
||||
private static DiscordGameSDKWrapper.Discord discord;
|
||||
private static ActivityManager activityManager;
|
||||
private static Activity activity;
|
||||
private static bool showingWindow;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
if (main)
|
||||
{
|
||||
Log.Error($"[Discord] Tried to instantiate a second {nameof(DiscordClient)}");
|
||||
return;
|
||||
}
|
||||
activity = new();
|
||||
main = this;
|
||||
DontDestroyOnLoad(gameObject);
|
||||
Log.Info("[Discord] Starting Discord client");
|
||||
StartDiscordHook();
|
||||
}
|
||||
|
||||
private void StartDiscordHook()
|
||||
{
|
||||
try
|
||||
{
|
||||
discord = new DiscordGameSDKWrapper.Discord(CLIENT_ID, (ulong)CreateFlags.NoRequireDiscord);
|
||||
discord.SetLogHook(DiscordGameSDKWrapper.LogLevel.Debug, (level, message) => Log.Write((NitroxModel.Logger.LogLevel)level, $"[Discord] {message}"));
|
||||
activityManager = discord.GetActivityManager();
|
||||
|
||||
activityManager.RegisterSteam((uint)GameInfo.Subnautica.SteamAppId);
|
||||
activityManager.OnActivityJoinRequest += ActivityJoinRequest;
|
||||
activityManager.OnActivityJoin += ActivityJoin;
|
||||
if (!string.IsNullOrEmpty(activity.State))
|
||||
{
|
||||
UpdateActivity();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
DisposeAndScheduleHookRestart();
|
||||
Log.ErrorOnce($"Encountered an error while starting Discord hook, will retry every {RETRY_INTERVAL} seconds: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
Log.Info("[Discord] Shutdown client");
|
||||
discord?.Dispose();
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
if (main == this)
|
||||
{
|
||||
main = null;
|
||||
activity = default;
|
||||
}
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
try
|
||||
{
|
||||
discord?.RunCallbacks();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// Happens when Discord is closed while Nitrox has its Discord hook running (and for other reason)
|
||||
DisposeAndScheduleHookRestart();
|
||||
Log.ErrorOnce($"An error occured while running callbacks for Discord, will retry every {RETRY_INTERVAL} seconds: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
private void DisposeAndScheduleHookRestart()
|
||||
{
|
||||
discord?.Dispose();
|
||||
discord = null;
|
||||
Invoke(nameof(StartDiscordHook), RETRY_INTERVAL);
|
||||
}
|
||||
|
||||
private void ActivityJoin(string secret)
|
||||
{
|
||||
Log.Info("[Discord] Joining Server");
|
||||
|
||||
if (SceneManager.GetActiveScene().name != "StartScreen" || !MainMenuServerListPanel.Main)
|
||||
{
|
||||
Log.InGame(Language.main.Get("Nitrox_DiscordMultiplayerMenu"));
|
||||
Log.Warn("[Discord] Can't join a server outside of the main-menu.");
|
||||
return;
|
||||
}
|
||||
|
||||
string[] splitSecret = secret.Split(':');
|
||||
string ip = string.Join(":", splitSecret.Take(splitSecret.Length - 1));
|
||||
string port = splitSecret.Last();
|
||||
|
||||
if(int.TryParse(port, out int portInt))
|
||||
{
|
||||
Log.Error($"[Discord] Port from received secret can't be parsed as int: {port}");
|
||||
return;
|
||||
}
|
||||
MainMenuServerButton.OpenJoinServerMenuAsync(ip, portInt).ContinueWithHandleError(true);
|
||||
}
|
||||
|
||||
private void ActivityJoinRequest(ref User user)
|
||||
{
|
||||
if (!showingWindow && Multiplayer.Active)
|
||||
{
|
||||
Log.Info($"[Discord] JoinRequest: Name:{user.Username}#{user.Discriminator} UserID:{user.Id}");
|
||||
StartCoroutine(DiscordJoinRequestGui.SpawnGui(user));
|
||||
showingWindow = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.Warn("[Discord] Request window is already active.");
|
||||
}
|
||||
}
|
||||
|
||||
public static void InitializeRPMenu()
|
||||
{
|
||||
activity.State = Language.main.Get("Nitrox_DiscordMainMenuState");
|
||||
activity.Assets.LargeImage = "icon";
|
||||
UpdateActivity();
|
||||
}
|
||||
|
||||
public static void InitializeRPInGame(string username, int playerCount, int maxConnections)
|
||||
{
|
||||
activity.State = Language.main.Get("Nitrox_DiscordInGameState");
|
||||
activity.Details = Language.main.Get("Nitrox_DiscordInGame").Replace("{PLAYER}", username);
|
||||
activity.Timestamps.Start = 0;
|
||||
activity.Party.Size.CurrentSize = playerCount;
|
||||
activity.Party.Size.MaxSize = maxConnections;
|
||||
UpdateActivity();
|
||||
|
||||
NitroxServiceLocator.LocateService<IPacketSender>().Send(new DiscordRequestIP(string.Empty));
|
||||
}
|
||||
|
||||
public static void UpdateIpPort(string ipPort)
|
||||
{
|
||||
activity.Party.Id = $"NitroxPartyID:{ipPort}";
|
||||
activity.Secrets.Join = ipPort;
|
||||
UpdateActivity();
|
||||
}
|
||||
|
||||
public static void UpdatePartySize(int size)
|
||||
{
|
||||
activity.Party.Size.CurrentSize = size;
|
||||
UpdateActivity();
|
||||
}
|
||||
|
||||
private static void UpdateActivity()
|
||||
{
|
||||
activityManager?.UpdateActivity(activity, (result) =>
|
||||
{
|
||||
if (result != Result.Ok)
|
||||
{
|
||||
Log.Error($"[Discord] {result}: Updating Activity failed");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static void RespondJoinRequest(long userID, ActivityJoinRequestReply reply)
|
||||
{
|
||||
showingWindow = false;
|
||||
activityManager?.SendRequestReply(userID, reply, (result) =>
|
||||
{
|
||||
if (result == Result.Ok)
|
||||
{
|
||||
Log.Info($"[Discord] Responded successfully {reply} to {userID}");
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.InGame($"[Discord] {Language.main.Get("Nitrox_Failure")}");
|
||||
Log.Error($"[Discord] {result}: Failed to send join response");
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
104
NitroxClient/MonoBehaviours/Discord/DiscordJoinRequestGui.cs
Normal file
104
NitroxClient/MonoBehaviours/Discord/DiscordJoinRequestGui.cs
Normal file
@@ -0,0 +1,104 @@
|
||||
using System.Collections;
|
||||
using DiscordGameSDKWrapper;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Networking;
|
||||
using UnityEngine.UI;
|
||||
using static NitroxClient.Unity.Helper.AssetBundleLoader;
|
||||
|
||||
namespace NitroxClient.MonoBehaviours.Discord;
|
||||
|
||||
public class DiscordJoinRequestGui : uGUI_InputGroup
|
||||
{
|
||||
private readonly WaitForSeconds expireTimeYielder = new(45);
|
||||
|
||||
private static DiscordJoinRequestGui instance;
|
||||
private static User user;
|
||||
|
||||
private static Image profilePicture;
|
||||
private static GameObject pressToFocus;
|
||||
private static GameObject pressButtons;
|
||||
|
||||
public static IEnumerator SpawnGui(User requestingUser)
|
||||
{
|
||||
user = requestingUser;
|
||||
|
||||
yield return LoadUIAsset(NitroxAssetBundle.DISCORD_JOIN_REQUEST, false);
|
||||
|
||||
GameObject guiGameObject = (GameObject)NitroxAssetBundle.DISCORD_JOIN_REQUEST.LoadedAssets[0];
|
||||
|
||||
instance = guiGameObject.AddComponent<DiscordJoinRequestGui>();
|
||||
|
||||
profilePicture = guiGameObject.FindChild("ProfilePicture").GetComponent<Image>();
|
||||
|
||||
pressToFocus = guiGameObject.FindChild("PressToFocus");
|
||||
Text[] texts = pressToFocus.GetComponentsInChildren<Text>();
|
||||
texts[0].text = Language.main.Get("Nitrox_DiscordPressToFocus");
|
||||
texts[3].text = GameInput.GetBinding(GameInput.Device.Keyboard, (GameInput.Button)46, GameInput.BindingSet.Primary);
|
||||
pressToFocus.SetActive(true);
|
||||
|
||||
pressButtons = guiGameObject.FindChild("PressButtons");
|
||||
pressButtons.SetActive(false);
|
||||
|
||||
Text[] buttonTexts = pressButtons.GetComponentsInChildren<Text>(true);
|
||||
buttonTexts[0].text = Language.main.Get("Nitrox_DiscordAccept");
|
||||
buttonTexts[1].text = Language.main.Get("Nitrox_DiscordDecline");
|
||||
|
||||
Button[] buttons = pressButtons.GetComponentsInChildren<Button>(true);
|
||||
buttons[0].onClick.AddListener(instance.AcceptInvite);
|
||||
buttons[1].onClick.AddListener(instance.DeclineInvite);
|
||||
|
||||
Text[] userTexts = guiGameObject.FindChild("UpperText").GetComponentsInChildren<Text>();
|
||||
userTexts[0].text = $"{user.Username}#{user.Discriminator}";
|
||||
userTexts[1].text = Language.main.Get("Nitrox_DiscordRequestText");
|
||||
|
||||
yield return LoadAvatar(user.Id, user.Avatar);
|
||||
}
|
||||
|
||||
private void Start()
|
||||
{
|
||||
StartCoroutine(OnRequestExpired());
|
||||
}
|
||||
|
||||
private void AcceptInvite() => CloseWindow(ActivityJoinRequestReply.Yes);
|
||||
private void DeclineInvite() => CloseWindow(ActivityJoinRequestReply.No);
|
||||
|
||||
private void CloseWindow(ActivityJoinRequestReply reply)
|
||||
{
|
||||
DiscordClient.RespondJoinRequest(user.Id, reply);
|
||||
DestroyImmediate(gameObject);
|
||||
}
|
||||
|
||||
public static void Select()
|
||||
{
|
||||
if (instance)
|
||||
{
|
||||
pressToFocus.SetActive(false);
|
||||
pressButtons.SetActive(true);
|
||||
instance.Select(false);
|
||||
}
|
||||
}
|
||||
|
||||
private static IEnumerator LoadAvatar(long id, string avatarID)
|
||||
{
|
||||
UnityWebRequest avatarUrl = UnityWebRequestTexture.GetTexture($"https://cdn.discordapp.com/avatars/{id}/{avatarID}.png");
|
||||
yield return avatarUrl.SendWebRequest();
|
||||
|
||||
Texture2D avatar = ((DownloadHandlerTexture)avatarUrl.downloadHandler).texture;
|
||||
|
||||
if (!avatar || avatar.height < 64)
|
||||
{
|
||||
UnityWebRequest standardAvatarUrl = UnityWebRequestTexture.GetTexture("https://discordapp.com/assets/6debd47ed13483642cf09e832ed0bc1b.png");
|
||||
yield return standardAvatarUrl.SendWebRequest();
|
||||
|
||||
avatar = ((DownloadHandlerTexture)standardAvatarUrl.downloadHandler).texture;
|
||||
}
|
||||
|
||||
profilePicture.sprite = Sprite.Create(avatar, new UnityEngine.Rect(0, 0, 128, 128), new Vector2(0.5f, 0.5f));
|
||||
}
|
||||
|
||||
private IEnumerator OnRequestExpired()
|
||||
{
|
||||
yield return expireTimeYielder;
|
||||
CloseWindow(ActivityJoinRequestReply.Ignore);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user