400 lines
20 KiB
C#
400 lines
20 KiB
C#
using Dalamud.Interface;
|
|
using Dalamud.Interface.Colors;
|
|
using Dalamud.Interface.Utility;
|
|
using Dalamud.Utility;
|
|
using ImGuiNET;
|
|
using MareSynchronos.FileCache;
|
|
using MareSynchronos.Localization;
|
|
using MareSynchronos.MareConfiguration;
|
|
using MareSynchronos.MareConfiguration.Models;
|
|
using MareSynchronos.Services;
|
|
using MareSynchronos.Services.Mediator;
|
|
using MareSynchronos.Services.ServerConfiguration;
|
|
using MareSynchronos.WebAPI;
|
|
using MareSynchronos.API.Dto.Account;
|
|
using MareSynchronos.API.Routes;
|
|
using Microsoft.Extensions.Logging;
|
|
using System.Net.Http.Headers;
|
|
using System.Net.Http.Json;
|
|
using System.Numerics;
|
|
using System.Reflection;
|
|
using System.Text.RegularExpressions;
|
|
using MareSynchronos.WebAPI.SignalR.Utils;
|
|
using Dalamud.Interface.Utility.Raii;
|
|
|
|
namespace MareSynchronos.UI;
|
|
|
|
public partial class IntroUi : WindowMediatorSubscriberBase
|
|
{
|
|
private readonly MareConfigService _configService;
|
|
private readonly CacheMonitor _cacheMonitor;
|
|
private readonly Dictionary<string, string> _languages = new(StringComparer.Ordinal) { { "English", "en" }, { "Deutsch", "de" }, { "Français", "fr" } };
|
|
private readonly ServerConfigurationManager _serverConfigurationManager;
|
|
private readonly DalamudUtilService _dalamudUtilService;
|
|
private readonly UiSharedService _uiShared;
|
|
private int _currentLanguage;
|
|
private bool _readFirstPage;
|
|
|
|
private string _secretKey = string.Empty;
|
|
private string _timeoutLabel = string.Empty;
|
|
private Task? _timeoutTask;
|
|
private string[]? _tosParagraphs;
|
|
private bool _registrationInProgress = false;
|
|
private bool _registrationSuccess = false;
|
|
private string? _registrationMessage;
|
|
private RegisterReplyDto? _registrationReply;
|
|
|
|
public IntroUi(ILogger<IntroUi> logger, UiSharedService uiShared, MareConfigService configService,
|
|
CacheMonitor fileCacheManager, ServerConfigurationManager serverConfigurationManager, MareMediator mareMediator,
|
|
PerformanceCollectorService performanceCollectorService, DalamudUtilService dalamudUtilService) : base(logger, mareMediator, "Loporrit Setup", performanceCollectorService)
|
|
{
|
|
_uiShared = uiShared;
|
|
_configService = configService;
|
|
_cacheMonitor = fileCacheManager;
|
|
_serverConfigurationManager = serverConfigurationManager;
|
|
_dalamudUtilService = dalamudUtilService;
|
|
IsOpen = false;
|
|
ShowCloseButton = false;
|
|
RespectCloseHotkey = false;
|
|
|
|
SizeConstraints = new WindowSizeConstraints()
|
|
{
|
|
MinimumSize = new Vector2(650, 500),
|
|
MaximumSize = new Vector2(650, 2000),
|
|
};
|
|
|
|
GetToSLocalization();
|
|
|
|
Mediator.Subscribe<SwitchToMainUiMessage>(this, (_) => IsOpen = false);
|
|
Mediator.Subscribe<SwitchToIntroUiMessage>(this, (_) =>
|
|
{
|
|
_configService.Current.UseCompactor = !dalamudUtilService.IsWine;
|
|
IsOpen = true;
|
|
});
|
|
}
|
|
|
|
private Vector4 GetConnectionColor()
|
|
{
|
|
return _uiShared.ApiController.ServerState switch
|
|
{
|
|
ServerState.Connecting => ImGuiColors.DalamudYellow,
|
|
ServerState.Reconnecting => ImGuiColors.DalamudRed,
|
|
ServerState.Connected => ImGuiColors.HealerGreen,
|
|
ServerState.Disconnected => ImGuiColors.DalamudYellow,
|
|
ServerState.Disconnecting => ImGuiColors.DalamudYellow,
|
|
ServerState.Unauthorized => ImGuiColors.DalamudRed,
|
|
ServerState.VersionMisMatch => ImGuiColors.DalamudRed,
|
|
ServerState.Offline => ImGuiColors.DalamudRed,
|
|
ServerState.RateLimited => ImGuiColors.DalamudYellow,
|
|
ServerState.NoSecretKey => ImGuiColors.DalamudYellow,
|
|
ServerState.MultiChara => ImGuiColors.DalamudYellow,
|
|
_ => ImGuiColors.DalamudRed
|
|
};
|
|
}
|
|
|
|
private string GetConnectionStatus()
|
|
{
|
|
return _uiShared.ApiController.ServerState switch
|
|
{
|
|
ServerState.Reconnecting => "Reconnecting",
|
|
ServerState.Connecting => "Connecting",
|
|
ServerState.Disconnected => "Disconnected",
|
|
ServerState.Disconnecting => "Disconnecting",
|
|
ServerState.Unauthorized => "Unauthorized",
|
|
ServerState.VersionMisMatch => "Version mismatch",
|
|
ServerState.Offline => "Unavailable",
|
|
ServerState.RateLimited => "Rate Limited",
|
|
ServerState.NoSecretKey => "No Secret Key",
|
|
ServerState.MultiChara => "Duplicate Characters",
|
|
ServerState.Connected => "Connected",
|
|
_ => string.Empty
|
|
};
|
|
}
|
|
|
|
protected override void DrawInternal()
|
|
{
|
|
if (_uiShared.IsInGpose) return;
|
|
|
|
if (!_configService.Current.AcceptedAgreement && !_readFirstPage)
|
|
{
|
|
_uiShared.BigText("Welcome to Loporrit");
|
|
ImGui.Separator();
|
|
UiSharedService.TextWrapped("Loporrit is a plugin that will replicate your full current character state including all Penumbra mods to other paired users. " +
|
|
"Note that you will have to have Penumbra as well as Glamourer installed to use this plugin.");
|
|
UiSharedService.TextWrapped("We will have to setup a few things first before you can start using this plugin. Click on next to continue.");
|
|
|
|
UiSharedService.ColorTextWrapped("Note: Any modifications you have applied through anything but Penumbra cannot be shared and your character state on other clients " +
|
|
"might look broken because of this or others players mods might not apply on your end altogether. " +
|
|
"If you want to use this plugin you will have to move your mods to Penumbra.", ImGuiColors.DalamudYellow);
|
|
if (!_uiShared.DrawOtherPluginState(intro: true)) return;
|
|
ImGui.Separator();
|
|
if (ImGui.Button("Next##toAgreement"))
|
|
{
|
|
_readFirstPage = true;
|
|
#if !DEBUG
|
|
_timeoutTask = Task.Run(async () =>
|
|
{
|
|
for (int i = 10; i > 0; i--)
|
|
{
|
|
_timeoutLabel = $"{Strings.ToS.ButtonWillBeAvailableIn} {i}s";
|
|
await Task.Delay(TimeSpan.FromSeconds(1)).ConfigureAwait(false);
|
|
}
|
|
});
|
|
#else
|
|
_timeoutTask = Task.CompletedTask;
|
|
#endif
|
|
}
|
|
}
|
|
else if (!_configService.Current.AcceptedAgreement && _readFirstPage)
|
|
{
|
|
Vector2 textSize;
|
|
using (_uiShared.UidFont.Push())
|
|
{
|
|
textSize = ImGui.CalcTextSize(Strings.ToS.LanguageLabel);
|
|
ImGui.TextUnformatted(Strings.ToS.AgreementLabel);
|
|
}
|
|
|
|
ImGui.SameLine();
|
|
var languageSize = ImGui.CalcTextSize(Strings.ToS.LanguageLabel);
|
|
ImGui.SetCursorPosX(ImGui.GetWindowContentRegionMax().X - ImGui.GetWindowContentRegionMin().X - languageSize.X - 80);
|
|
ImGui.SetCursorPosY(ImGui.GetCursorPosY() + textSize.Y / 2 - languageSize.Y / 2);
|
|
|
|
ImGui.TextUnformatted(Strings.ToS.LanguageLabel);
|
|
ImGui.SameLine();
|
|
ImGui.SetCursorPosY(ImGui.GetCursorPosY() + textSize.Y / 2 - (languageSize.Y + ImGui.GetStyle().FramePadding.Y) / 2);
|
|
ImGui.SetNextItemWidth(80 * ImGuiHelpers.GlobalScale);
|
|
if (ImGui.Combo("", ref _currentLanguage, _languages.Keys.ToArray(), _languages.Count))
|
|
{
|
|
GetToSLocalization(_currentLanguage);
|
|
}
|
|
|
|
ImGui.Separator();
|
|
ImGui.SetWindowFontScale(1.5f);
|
|
string readThis = Strings.ToS.ReadLabel;
|
|
textSize = ImGui.CalcTextSize(readThis);
|
|
ImGui.SetCursorPosX(ImGui.GetWindowSize().X / 2 - textSize.X / 2);
|
|
UiSharedService.ColorText(readThis, ImGuiColors.DalamudRed);
|
|
ImGui.SetWindowFontScale(1.0f);
|
|
ImGui.Separator();
|
|
|
|
UiSharedService.TextWrapped(_tosParagraphs![0]);
|
|
UiSharedService.TextWrapped(_tosParagraphs![1]);
|
|
UiSharedService.TextWrapped(_tosParagraphs![2]);
|
|
UiSharedService.TextWrapped(_tosParagraphs![3]);
|
|
UiSharedService.TextWrapped(_tosParagraphs![4]);
|
|
UiSharedService.TextWrapped(_tosParagraphs![5]);
|
|
|
|
ImGui.Separator();
|
|
if (_timeoutTask?.IsCompleted ?? true)
|
|
{
|
|
if (ImGui.Button(Strings.ToS.AgreeLabel + "##toSetup"))
|
|
{
|
|
_configService.Current.AcceptedAgreement = true;
|
|
_configService.Save();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
UiSharedService.TextWrapped(_timeoutLabel);
|
|
}
|
|
}
|
|
else if (_configService.Current.AcceptedAgreement
|
|
&& (string.IsNullOrEmpty(_configService.Current.CacheFolder)
|
|
|| !_configService.Current.InitialScanComplete
|
|
|| !Directory.Exists(_configService.Current.CacheFolder)))
|
|
{
|
|
using (_uiShared.UidFont.Push())
|
|
ImGui.TextUnformatted("File Storage Setup");
|
|
|
|
ImGui.Separator();
|
|
|
|
if (!_uiShared.HasValidPenumbraModPath)
|
|
{
|
|
UiSharedService.ColorTextWrapped("You do not have a valid Penumbra path set. Open Penumbra and set up a valid path for the mod directory.", ImGuiColors.DalamudRed);
|
|
}
|
|
else
|
|
{
|
|
UiSharedService.TextWrapped("To not unnecessary download files already present on your computer, Loporrit will have to scan your Penumbra mod directory. " +
|
|
"Additionally, a local storage folder must be set where Loporrit will download other character files to. " +
|
|
"Once the storage folder is set and the scan complete, this page will automatically forward to registration at a service.");
|
|
UiSharedService.TextWrapped("Note: The initial scan, depending on the amount of mods you have, might take a while. Please wait until it is completed.");
|
|
UiSharedService.ColorTextWrapped("Warning: once past this step you should not delete the FileCache.csv of Loporrit in the Plugin Configurations folder of Dalamud. " +
|
|
"Otherwise on the next launch a full re-scan of the file cache database will be initiated.", ImGuiColors.DalamudYellow);
|
|
UiSharedService.ColorTextWrapped("Warning: if the scan is hanging and does nothing for a long time, chances are high your Penumbra folder is not set up properly.", ImGuiColors.DalamudYellow);
|
|
_uiShared.DrawCacheDirectorySetting();
|
|
}
|
|
|
|
if (!_cacheMonitor.IsScanRunning && !string.IsNullOrEmpty(_configService.Current.CacheFolder) && _uiShared.HasValidPenumbraModPath && Directory.Exists(_configService.Current.CacheFolder))
|
|
{
|
|
if (ImGui.Button("Start Scan##startScan"))
|
|
{
|
|
_cacheMonitor.InvokeScan();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
_uiShared.DrawFileScanState();
|
|
}
|
|
if (!_dalamudUtilService.IsWine)
|
|
{
|
|
var useFileCompactor = _configService.Current.UseCompactor;
|
|
if (ImGui.Checkbox("Use File Compactor", ref useFileCompactor))
|
|
{
|
|
_configService.Current.UseCompactor = useFileCompactor;
|
|
_configService.Save();
|
|
}
|
|
UiSharedService.ColorTextWrapped("The File Compactor can save a tremendeous amount of space on the hard disk for downloads through Loporrit. It will incur a minor CPU penalty on download but can speed up " +
|
|
"loading of other characters. It is recommended to keep it enabled. You can change this setting later anytime in the Loporrit settings.", ImGuiColors.DalamudYellow);
|
|
}
|
|
}
|
|
else if (!_uiShared.ApiController.IsConnected)
|
|
{
|
|
using (_uiShared.UidFont.Push())
|
|
ImGui.TextUnformatted("Service Registration");
|
|
ImGui.Separator();
|
|
UiSharedService.TextWrapped("To be able to use Loporrit you will have to register an account.");
|
|
UiSharedService.TextWrapped("Refer to the instructions at the location you obtained this plugin for more information or support.");
|
|
|
|
ImGui.Separator();
|
|
|
|
ImGui.BeginDisabled(_registrationInProgress || _uiShared.ApiController.ServerState == ServerState.Connecting || _uiShared.ApiController.ServerState == ServerState.Reconnecting);
|
|
_ = _uiShared.DrawServiceSelection(selectOnChange: true, intro: true);
|
|
|
|
if (true) // Enable registration button for all servers
|
|
{
|
|
ImGui.BeginDisabled(_registrationInProgress || _registrationSuccess || _secretKey.Length > 0);
|
|
ImGui.Separator();
|
|
ImGui.TextUnformatted("If you have not used Loporrit before, click below to register a new account.");
|
|
if (_uiShared.IconTextButton(FontAwesomeIcon.Plus, "Register a new Loporrit account"))
|
|
{
|
|
_registrationInProgress = true;
|
|
_ = Task.Run(async () => {
|
|
try
|
|
{
|
|
using HttpClient httpClient = new();
|
|
var ver = Assembly.GetExecutingAssembly().GetName().Version;
|
|
httpClient.DefaultRequestHeaders.UserAgent.Add(new ProductInfoHeaderValue("MareSynchronos", ver!.Major + "." + ver!.Minor + "." + ver!.Build));
|
|
var postUri = MareAuth.AuthRegisterFullPath(new Uri(_serverConfigurationManager.CurrentApiUrl
|
|
.Replace("wss://", "https://", StringComparison.OrdinalIgnoreCase)
|
|
.Replace("ws://", "http://", StringComparison.OrdinalIgnoreCase)));
|
|
_logger.LogInformation("Registering new account: {uri}", postUri.ToString());
|
|
var result = await httpClient.PostAsync(postUri, null).ConfigureAwait(false);
|
|
result.EnsureSuccessStatusCode();
|
|
var reply = await result.Content.ReadFromJsonAsync<RegisterReplyDto>().ConfigureAwait(false) ?? new();
|
|
if (!reply.Success)
|
|
{
|
|
_logger.LogWarning("Registration failed: {err}", reply.ErrorMessage);
|
|
_registrationMessage = reply.ErrorMessage;
|
|
if (_registrationMessage.IsNullOrEmpty())
|
|
_registrationMessage = "An unknown error occured. Please try again later.";
|
|
return;
|
|
}
|
|
_registrationMessage = "New account registered.\nPlease keep a copy of your secret key in case you need to reset your plugins, or to use it on another PC.";
|
|
_secretKey = reply.SecretKey ?? "";
|
|
_registrationReply = reply;
|
|
_registrationSuccess = true;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogWarning(ex, "Registration failed");
|
|
_registrationSuccess = false;
|
|
_registrationMessage = "An unknown error occured. Please try again later.";
|
|
}
|
|
finally
|
|
{
|
|
_registrationInProgress = false;
|
|
}
|
|
});
|
|
}
|
|
ImGui.EndDisabled(); // _registrationInProgress || _registrationSuccess
|
|
if (_registrationInProgress)
|
|
{
|
|
ImGui.TextUnformatted("Sending request...");
|
|
}
|
|
else if (!_registrationMessage.IsNullOrEmpty())
|
|
{
|
|
if (!_registrationSuccess)
|
|
ImGui.TextColored(ImGuiColors.DalamudYellow, _registrationMessage);
|
|
else
|
|
ImGui.TextUnformatted(_registrationMessage);
|
|
}
|
|
}
|
|
|
|
ImGui.Separator();
|
|
|
|
var text = "Enter Secret Key";
|
|
|
|
if (_registrationSuccess)
|
|
{
|
|
text = "Secret Key";
|
|
}
|
|
else
|
|
{
|
|
ImGui.TextUnformatted("If you already have a registered account, you can enter its secret key below to use it instead.");
|
|
}
|
|
|
|
var textSize = ImGui.CalcTextSize(text);
|
|
ImGui.AlignTextToFramePadding();
|
|
ImGui.TextUnformatted(text);
|
|
ImGui.SameLine();
|
|
ImGui.SetNextItemWidth(UiSharedService.GetWindowContentRegionWidth() - ImGui.GetWindowContentRegionMin().X - textSize.X);
|
|
ImGui.InputText("", ref _secretKey, 64);
|
|
if (_secretKey.Length > 0 && _secretKey.Length != 64)
|
|
{
|
|
UiSharedService.ColorTextWrapped("Your secret key must be exactly 64 characters long.", ImGuiColors.DalamudRed);
|
|
}
|
|
else if (_secretKey.Length == 64 && !HexRegex().IsMatch(_secretKey))
|
|
{
|
|
UiSharedService.ColorTextWrapped("Your secret key can only contain ABCDEF and the numbers 0-9.", ImGuiColors.DalamudRed);
|
|
}
|
|
else if (_secretKey.Length == 64)
|
|
{
|
|
using var saveDisabled = ImRaii.Disabled(_uiShared.ApiController.ServerState == ServerState.Connecting || _uiShared.ApiController.ServerState == ServerState.Reconnecting);
|
|
if (ImGui.Button("Save and Connect"))
|
|
{
|
|
string keyName;
|
|
if (_serverConfigurationManager.CurrentServer == null) _serverConfigurationManager.SelectServer(0);
|
|
if (_registrationReply != null && _secretKey.Equals(_registrationReply.SecretKey, StringComparison.Ordinal))
|
|
keyName = _registrationReply.UID + $" (registered {DateTime.Now:yyyy-MM-dd})";
|
|
else
|
|
keyName = $"Secret Key added on Setup ({DateTime.Now:yyyy-MM-dd})";
|
|
_serverConfigurationManager.CurrentServer!.SecretKeys.Add(_serverConfigurationManager.CurrentServer.SecretKeys.Select(k => k.Key).LastOrDefault() + 1, new SecretKey()
|
|
{
|
|
FriendlyName = keyName,
|
|
Key = _secretKey,
|
|
});
|
|
_serverConfigurationManager.AddCurrentCharacterToServer(save: false);
|
|
_ = Task.Run(() => _uiShared.ApiController.CreateConnections());
|
|
}
|
|
}
|
|
|
|
if (_uiShared.ApiController.ServerState != ServerState.NoSecretKey)
|
|
{
|
|
UiSharedService.ColorText(GetConnectionStatus(), GetConnectionColor());
|
|
}
|
|
|
|
ImGui.EndDisabled(); // _registrationInProgress
|
|
}
|
|
else
|
|
{
|
|
_secretKey = string.Empty;
|
|
_serverConfigurationManager.Save();
|
|
Mediator.Publish(new SwitchToMainUiMessage());
|
|
IsOpen = false;
|
|
}
|
|
}
|
|
|
|
private void GetToSLocalization(int changeLanguageTo = -1)
|
|
{
|
|
if (changeLanguageTo != -1)
|
|
{
|
|
_uiShared.LoadLocalization(_languages.ElementAt(changeLanguageTo).Value);
|
|
}
|
|
|
|
_tosParagraphs = [Strings.ToS.Paragraph1, Strings.ToS.Paragraph2, Strings.ToS.Paragraph3, Strings.ToS.Paragraph4, Strings.ToS.Paragraph5, Strings.ToS.Paragraph6];
|
|
}
|
|
|
|
[GeneratedRegex("^([A-F0-9]{2})+")]
|
|
private static partial Regex HexRegex();
|
|
}
|