diff --git a/Demo/App.xaml b/Demo/App.xaml index 278c3383..0c9e37eb 100644 --- a/Demo/App.xaml +++ b/Demo/App.xaml @@ -1,7 +1,156 @@  + xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" + xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" + StartupUri="MainWindow.xaml"> + /Assets/#Nunito + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Demo/App.xaml.cs b/Demo/App.xaml.cs index 154b6442..17ab99c4 100644 --- a/Demo/App.xaml.cs +++ b/Demo/App.xaml.cs @@ -2,10 +2,10 @@ namespace Demo { - /// - /// Interaction logic for App.xaml - /// - public partial class App : Application - { - } + /// + /// Interaction logic for App.xaml + /// + public partial class App : Application + { + } } \ No newline at end of file diff --git a/Demo/AssemblyInfo.cs b/Demo/AssemblyInfo.cs index d3292122..4a05c7d4 100644 --- a/Demo/AssemblyInfo.cs +++ b/Demo/AssemblyInfo.cs @@ -1,10 +1,10 @@ using System.Windows; [assembly: ThemeInfo( - ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located - //(used if a resource is not found in the page, - // or application resource dictionaries) - ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located - //(used if a resource is not found in the page, - // app, or any theme specific resource dictionaries) + ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located + //(used if a resource is not found in the page, + // or application resource dictionaries) + ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located + //(used if a resource is not found in the page, + // app, or any theme specific resource dictionaries) )] \ No newline at end of file diff --git a/Demo/Controls/NormalPlayerCell.xaml b/Demo/Controls/NormalPlayerCell.xaml index 596c0430..4ec3dcb5 100644 --- a/Demo/Controls/NormalPlayerCell.xaml +++ b/Demo/Controls/NormalPlayerCell.xaml @@ -1,10 +1,10 @@  @@ -14,6 +14,7 @@ + + - + + + + @@ -54,61 +59,18 @@ Margin="0,0,10,0" CornerRadius="10"> - + - - - - - - - - - - - - - - - - - - - - - - - + + + + + Text="{Binding PlayerCell.IgnData.Username, ElementName=Self}" + Visibility="{Binding PlayerCell.IgnData.TrackerDisabled, ElementName=Self}" /> + ToolTipService.InitialShowDelay="0" + Visibility="{Binding PlayerCell.IgnData.TrackerEnabled, ElementName=Self}"> - + + + Text="{Binding Path=PlayerCell.AccountLevel, ElementName=Self}" /> - + Source="{Binding PlayerCell.SkinData.VandalImage, ElementName=Self}" + ToolTip="{Binding PlayerCell.SkinData.VandalName, ElementName=Self}" + ToolTipService.InitialShowDelay="0" /> + + - + + Source="{Binding PlayerCell.RankData.PreviouspreviousrankImage, ElementName=Self}" + ToolTip="{Binding PlayerCell.RankData.PreviouspreviousrankName, ElementName=Self}" + ToolTipService.InitialShowDelay="0" /> + Source="{Binding PlayerCell.RankData.PreviousrankImage, ElementName=Self}" + ToolTip="{Binding PlayerCell.RankData.PreviousrankName, ElementName=Self}" + ToolTipService.InitialShowDelay="0" /> + + + + + + + + + + + + + + + + ToolTip="{Binding PlayerCell.RankData.RankName, ElementName=Self}" + ToolTipService.InitialShowDelay="0"> - + - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Demo/Controls/NormalPlayerCell.xaml.cs b/Demo/Controls/NormalPlayerCell.xaml.cs index a4e6183e..2bf1aa62 100644 --- a/Demo/Controls/NormalPlayerCell.xaml.cs +++ b/Demo/Controls/NormalPlayerCell.xaml.cs @@ -1,304 +1,35 @@ -using System.Diagnostics; +using System; +using System.Diagnostics; using System.Windows; using System.Windows.Controls; using System.Windows.Documents; using System.Windows.Navigation; +using Demo.Objects; namespace Demo.Controls { - public partial class NormalPlayerCell : UserControl - { - public NormalPlayerCell() - { - InitializeComponent(); - } - - public string Card - { - get { return (string)GetValue(CardProperty); } - set { SetValue(CardProperty, value); } - } - - public static readonly DependencyProperty CardProperty = - DependencyProperty.Register("Card", typeof(string), typeof(NormalPlayerCell), new PropertyMetadata(null)); - - public string Level - { - get { return (string)GetValue(LevelProperty); } - set { SetValue(LevelProperty, value); } - } - - public static readonly DependencyProperty LevelProperty = - DependencyProperty.Register("Level", typeof(string), typeof(NormalPlayerCell), new PropertyMetadata(null)); - - public string AgentPicture - { - get { return (string)GetValue(AgentPictureProperty); } - set { SetValue(AgentPictureProperty, value); } - } - - public static readonly DependencyProperty AgentPictureProperty = - DependencyProperty.Register("AgentPicture", typeof(string), typeof(NormalPlayerCell), - new PropertyMetadata(null)); - - public string Agent - { - get { return (string)GetValue(AgentProperty); } - set { SetValue(AgentProperty, value); } - } - - public static readonly DependencyProperty AgentProperty = - DependencyProperty.Register("Agent", typeof(string), typeof(NormalPlayerCell), new PropertyMetadata(null)); - - public string IGN - { - get { return (string)GetValue(IGNProperty); } - set { SetValue(IGNProperty, value); } - } - - public static readonly DependencyProperty IGNProperty = - DependencyProperty.Register("IGN", typeof(string), typeof(NormalPlayerCell), new PropertyMetadata(null)); - - public string VandalSkin - { - get { return (string)GetValue(VandalSkinProperty); } - set { SetValue(VandalSkinProperty, value); } - } - - public static readonly DependencyProperty VandalSkinProperty = - DependencyProperty.Register("VandalSkin", typeof(string), typeof(NormalPlayerCell), - new PropertyMetadata(null)); - - public string PhantomSkin - { - get { return (string)GetValue(PhantomSkinProperty); } - set { SetValue(PhantomSkinProperty, value); } - } - - public static readonly DependencyProperty PhantomSkinProperty = - DependencyProperty.Register("PhantomSkin", typeof(string), typeof(NormalPlayerCell), - new PropertyMetadata(null)); - - public string VandalSkinName - { - get { return (string)GetValue(VandalSkinNameProperty); } - set { SetValue(VandalSkinNameProperty, value); } - } - - public static readonly DependencyProperty VandalSkinNameProperty = - DependencyProperty.Register("VandalSkinName", typeof(string), typeof(NormalPlayerCell), - new PropertyMetadata(null)); - - public string PhantomSkinName - { - get { return (string)GetValue(PhantomSkinNameProperty); } - set { SetValue(PhantomSkinNameProperty, value); } - } - - public static readonly DependencyProperty PhantomSkinNameProperty = - DependencyProperty.Register("PhantomSkinName", typeof(string), typeof(NormalPlayerCell), - new PropertyMetadata(null)); - - public string PMatch - { - get { return (string)GetValue(PMatchProperty); } - set { SetValue(PMatchProperty, value); } - } - - public static readonly DependencyProperty PMatchProperty = - DependencyProperty.Register("PMatch", typeof(string), typeof(NormalPlayerCell), new PropertyMetadata(null)); - - public string PPMatch - { - get { return (string)GetValue(PPMatchProperty); } - set { SetValue(PPMatchProperty, value); } - } - - public static readonly DependencyProperty PPMatchProperty = - DependencyProperty.Register("PPMatch", typeof(string), typeof(NormalPlayerCell), - new PropertyMetadata(null)); - - public string PPPMatch - { - get { return (string)GetValue(PPPMatchProperty); } - set { SetValue(PPPMatchProperty, value); } - } - - public static readonly DependencyProperty PPPMatchProperty = - DependencyProperty.Register("PPPMatch", typeof(string), typeof(NormalPlayerCell), - new PropertyMetadata(null)); - - public string PMatchColour - { - get { return (string)GetValue(PMatchColourProperty); } - set { SetValue(PMatchColourProperty, value); } - } - - public static readonly DependencyProperty PMatchColourProperty = - DependencyProperty.Register("PMatchColour", typeof(string), typeof(NormalPlayerCell), new PropertyMetadata(null)); - - public string PPMatchColour - { - get { return (string)GetValue(PPMatchColourProperty); } - set { SetValue(PPMatchColourProperty, value); } - } - - public static readonly DependencyProperty PPMatchColourProperty = - DependencyProperty.Register("PPMatchColour", typeof(string), typeof(NormalPlayerCell), - new PropertyMetadata(null)); - - public string PPPMatchColour - { - get { return (string)GetValue(PPPMatchColourProperty); } - set { SetValue(PPPMatchColourProperty, value); } - } - - public static readonly DependencyProperty PPPMatchColourProperty = - DependencyProperty.Register("PPPMatchColour", typeof(string), typeof(NormalPlayerCell), - new PropertyMetadata(null)); - - public string PRankName - { - get { return (string)GetValue(PRankNameProperty); } - set { SetValue(PRankNameProperty, value); } - } - - public static readonly DependencyProperty PRankNameProperty = - DependencyProperty.Register("PRankName", typeof(string), typeof(NormalPlayerCell), - new PropertyMetadata(null)); - - public string PPRankName - { - get { return (string)GetValue(PPRankNameProperty); } - set { SetValue(PPRankNameProperty, value); } - } - - public static readonly DependencyProperty PPRankNameProperty = - DependencyProperty.Register("PPRankName", typeof(string), typeof(NormalPlayerCell), - new PropertyMetadata(null)); - - public string PPPRankName - { - get { return (string)GetValue(PPPRankNameProperty); } - set { SetValue(PPPRankNameProperty, value); } - } - - public static readonly DependencyProperty PPPRankNameProperty = - DependencyProperty.Register("PPPRankName", typeof(string), typeof(NormalPlayerCell), - new PropertyMetadata(null)); - - public string RankName - { - get { return (string)GetValue(RankNameProperty); } - set { SetValue(RankNameProperty, value); } - } - - public static readonly DependencyProperty RankNameProperty = - DependencyProperty.Register("RankName", typeof(string), typeof(NormalPlayerCell), - new PropertyMetadata(null)); - - public string PRank - { - get { return (string)GetValue(PRankProperty); } - set { SetValue(PRankProperty, value); } - } - - public static readonly DependencyProperty PRankProperty = - DependencyProperty.Register("PRank", typeof(string), typeof(NormalPlayerCell), new PropertyMetadata(null)); - - public string PPRank - { - get { return (string)GetValue(PPRankProperty); } - set { SetValue(PPRankProperty, value); } - } - - public static readonly DependencyProperty PPRankProperty = - DependencyProperty.Register("PPRank", typeof(string), typeof(NormalPlayerCell), new PropertyMetadata(null)); - - public string PPPRank - { - get { return (string)GetValue(PPPRankProperty); } - set { SetValue(PPPRankProperty, value); } - } - - public static readonly DependencyProperty PPPRankProperty = - DependencyProperty.Register("PPPRank", typeof(string), typeof(NormalPlayerCell), - new PropertyMetadata(null)); - - public string Rank - { - get { return (string)GetValue(RankProperty); } - set { SetValue(RankProperty, value); } - } - - public static readonly DependencyProperty RankProperty = - DependencyProperty.Register("Rank", typeof(string), typeof(NormalPlayerCell), new PropertyMetadata(null)); - - public string RankProgress - { - get { return (string)GetValue(RankProgressProperty); } - set { SetValue(RankProgressProperty, value); } - } - - public static readonly DependencyProperty RankProgressProperty = - DependencyProperty.Register("RankProgress", typeof(string), typeof(NormalPlayerCell), - new PropertyMetadata(null)); - - public string MaxRR - { - get { return (string)GetValue(MaxRRProperty); } - set { SetValue(MaxRRProperty, value); } - } - - public static readonly DependencyProperty MaxRRProperty = - DependencyProperty.Register("MaxRR", typeof(string), typeof(NormalPlayerCell), new PropertyMetadata(null)); - - public string TrackerUrl - { - get { return (string)GetValue(TrackerUrlProperty); } - set { SetValue(TrackerUrlProperty, value); } - } - - public static readonly DependencyProperty TrackerUrlProperty = - DependencyProperty.Register("TrackerUrl", typeof(string), typeof(NormalPlayerCell), - new PropertyMetadata(null)); - - public string TrackerEnabled - { - get { return (string)GetValue(TrackerEnabledProperty); } - set { SetValue(TrackerEnabledProperty, value); } - } - - public static readonly DependencyProperty TrackerEnabledProperty = - DependencyProperty.Register("TrackerEnabled", typeof(string), typeof(NormalPlayerCell), - new PropertyMetadata(null)); - - public string TrackerDisabled - { - get { return (string)GetValue(TrackerDisabledProperty); } - set { SetValue(TrackerDisabledProperty, value); } - } - - public static readonly DependencyProperty TrackerDisabledProperty = - DependencyProperty.Register("TrackerDisabled", typeof(string), typeof(NormalPlayerCell), - new PropertyMetadata(null)); - - public string PartyColour - { - get { return (string)GetValue(PartyColourProperty); } - set { SetValue(PartyColourProperty, value); } - } - - public static readonly DependencyProperty PartyColourProperty = - DependencyProperty.Register("PartyColour", typeof(string), typeof(NormalPlayerCell), - new PropertyMetadata(null)); - - private void HandleLinkClick(object sender, RequestNavigateEventArgs e) - { - Hyperlink hl = (Hyperlink)sender; - string navigateUri = hl.NavigateUri.ToString(); - Process.Start(new ProcessStartInfo(navigateUri) { UseShellExecute = true }); - e.Handled = true; - } - } + public partial class NormalPlayerCell : UserControl + { + public static readonly DependencyProperty PlayerProperty = + DependencyProperty.Register("PlayerCell", typeof(Player), typeof(NormalPlayerCell), new PropertyMetadata(new Player())); + + public NormalPlayerCell() + { + InitializeComponent(); + } + + public Player PlayerCell + { + get => (Player) GetValue(PlayerProperty); + set => SetValue(PlayerProperty, value); + } + + private void HandleLinkClick(object sender, RequestNavigateEventArgs e) + { + var hl = (Hyperlink) sender; + var navigateUri = hl.NavigateUri.ToString(); + Process.Start(new ProcessStartInfo(navigateUri) {UseShellExecute = true}); + e.Handled = true; + } + } } \ No newline at end of file diff --git a/Demo/Demo.csproj b/Demo/Demo.csproj index a6fe752c..c5469019 100644 --- a/Demo/Demo.csproj +++ b/Demo/Demo.csproj @@ -2,9 +2,10 @@ WinExe - net5.0-windows + net6.0-windows enable true + AnyCPU @@ -27,14 +28,17 @@ + + + @@ -186,6 +190,10 @@ + + + + Code @@ -203,6 +211,9 @@ PreserveNewest + + PreserveNewest + PreserveNewest @@ -218,6 +229,9 @@ PreserveNewest + + PreserveNewest + PreserveNewest @@ -227,6 +241,7 @@ PreserveNewest + diff --git a/Demo/MainWindow.xaml b/Demo/MainWindow.xaml index 9cc9dcbf..64cd29f5 100644 --- a/Demo/MainWindow.xaml +++ b/Demo/MainWindow.xaml @@ -3,438 +3,169 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" - xmlns:c="clr-namespace:Demo.Controls" + xmlns:c="clr-namespace:Demo.Controls" mc:Ignorable="d" Title="WAIUA DEMO" d:DesignHeight="754" - d:DesignWidth="1536" - Background="#2E3349"> - - - - - - - - - - - - - - - - - - - - - - - - - + d:DesignWidth="1536" + Background="#2E3349"> + - - + + - + - + + - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + + + - - - - - - - + + - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/WAIUA/Controls/OverlayControl.xaml.cs b/WAIUA/Controls/OverlayControl.xaml.cs new file mode 100644 index 00000000..53de315d --- /dev/null +++ b/WAIUA/Controls/OverlayControl.xaml.cs @@ -0,0 +1,33 @@ +using System.Diagnostics; +using System.Windows; +using System.Windows.Controls; +using WAIUA.Objects; + +namespace WAIUA.Controls; + +/// +/// Interaction logic for OverlayControl.xaml +/// +public partial class OverlayControl : UserControl +{ + public static readonly DependencyProperty OverlayProperty = + DependencyProperty.Register("Overlay", typeof(LoadingOverlay), typeof(OverlayControl), new PropertyMetadata(new LoadingOverlay())); + + public OverlayControl() + { + InitializeComponent(); + } + + public LoadingOverlay Overlay + { + get => (LoadingOverlay) GetValue(OverlayProperty); + set => SetValue(OverlayProperty, value); + } + + private void ImageClickAsync(object sender, RoutedEventArgs e) + { + var button = (Button) sender; + Process.Start(new ProcessStartInfo(button.Tag.ToString()) {UseShellExecute = true}); + e.Handled = true; + } +} \ No newline at end of file diff --git a/WAIUA/Controls/PlayerControl.xaml b/WAIUA/Controls/PlayerControl.xaml new file mode 100644 index 00000000..0aeb31e6 --- /dev/null +++ b/WAIUA/Controls/PlayerControl.xaml @@ -0,0 +1,317 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/WAIUA/Controls/PlayerControl.xaml.cs b/WAIUA/Controls/PlayerControl.xaml.cs new file mode 100644 index 00000000..06498ae1 --- /dev/null +++ b/WAIUA/Controls/PlayerControl.xaml.cs @@ -0,0 +1,33 @@ +using System.Diagnostics; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Documents; +using System.Windows.Navigation; +using WAIUA.Objects; + +namespace WAIUA.Controls; + +public partial class PlayerControl : UserControl +{ + public static readonly DependencyProperty PlayerProperty = + DependencyProperty.Register("PlayerCell", typeof(Player), typeof(PlayerControl), new PropertyMetadata(new Player())); + + public PlayerControl() + { + InitializeComponent(); + } + + public Player PlayerCell + { + get => (Player) GetValue(PlayerProperty); + set => SetValue(PlayerProperty, value); + } + + private void HandleLinkClick(object sender, RequestNavigateEventArgs e) + { + var hl = (Hyperlink) sender; + var navigateUri = hl.NavigateUri.ToString(); + Process.Start(new ProcessStartInfo(navigateUri) {UseShellExecute = true}); + e.Handled = true; + } +} \ No newline at end of file diff --git a/WAIUA/Converters/InverseBooleanConverter.cs b/WAIUA/Converters/InverseBooleanConverter.cs new file mode 100644 index 00000000..6db2ab4c --- /dev/null +++ b/WAIUA/Converters/InverseBooleanConverter.cs @@ -0,0 +1,28 @@ +using System; +using System.Globalization; +using System.Windows.Data; + +namespace WAIUA.Converters; + +[ValueConversion(typeof(bool), typeof(bool))] +public class InverseBooleanConverter : IValueConverter +{ + #region IValueConverter Members + + public object Convert(object value, Type targetType, object parameter, + CultureInfo culture) + { + if (targetType != typeof(bool)) + throw new InvalidOperationException("The target must be a boolean"); + + return !(bool) value; + } + + public object ConvertBack(object value, Type targetType, object parameter, + CultureInfo culture) + { + throw new NotSupportedException(); + } + + #endregion +} \ No newline at end of file diff --git a/WAIUA/Converters/IsStringEmptyToVisibilityConverter.cs b/WAIUA/Converters/IsStringEmptyToVisibilityConverter.cs new file mode 100644 index 00000000..11f89c69 --- /dev/null +++ b/WAIUA/Converters/IsStringEmptyToVisibilityConverter.cs @@ -0,0 +1,27 @@ +using System; +using System.Globalization; +using System.Windows; +using System.Windows.Data; +using System.Windows.Markup; + +namespace WAIUA.Converters; + +public class IsStringEmptyToVisibilityConverter : MarkupExtension, IValueConverter +{ + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + return string.IsNullOrEmpty(value as string) + ? Visibility.Collapsed + : Visibility.Visible; + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + return null; + } + + public override object ProvideValue(IServiceProvider serviceProvider) + { + return this; + } +} \ No newline at end of file diff --git a/WAIUA/Helpers/Checks.cs b/WAIUA/Helpers/Checks.cs new file mode 100644 index 00000000..ccac8c7b --- /dev/null +++ b/WAIUA/Helpers/Checks.cs @@ -0,0 +1,64 @@ +using System; +using System.IO; +using System.Text; +using System.Threading.Tasks; +using RestSharp; + +namespace WAIUA.Helpers; + +public class Checks +{ + public static async Task CheckLoginAsync() + { + if (Constants.Region == null || Constants.Ppuuid == Guid.Empty) return false; + var client = new RestClient($"https://pd.{Constants.Region}.a.pvp.net/account-xp/v1/players/{Constants.Ppuuid}"); + + var request = new RestRequest().AddHeader("Authorization", $"Bearer {Constants.AccessToken}") + .AddHeader("X-Riot-Entitlements-JWT", Constants.EntitlementToken); + var response = await client.ExecuteGetAsync(request).ConfigureAwait(false); + if (response.IsSuccessful) return true; + Constants.Log.Warning("CheckLoginAsync() failed. Response: {Response}", response.ErrorException); + return false; + } + + public static async Task CheckLocalAsync() + { + var lockfileLocation = + $@"{Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData)}\Riot Games\Riot Client\Config\lockfile"; + + if (!File.Exists(lockfileLocation)) + // Constants.Log.Warning("Valorant Not detected"); + return false; + + string lockFileString; + await using (var file = new FileStream(lockfileLocation, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) + { + using var reader = new StreamReader(file, Encoding.UTF8); + lockFileString = (string) reader.ReadToEnd().Clone(); + file.Close(); + reader.Close(); + } + + var parts = lockFileString.Split(":"); + Constants.Port = parts[2]; + Constants.LPassword = parts[3]; + return true; + } + + public static async Task CheckMatchAsync() + { + var client = new RestClient($"https://glz-{Constants.Shard}-1.{Constants.Region}.a.pvp.net/core-game/v1/players/{Constants.Ppuuid}"); + var request = new RestRequest(); + request.AddHeader("X-Riot-Entitlements-JWT", Constants.EntitlementToken); + request.AddHeader("Authorization", $"Bearer {Constants.AccessToken}"); + var response = await client.ExecuteGetAsync(request).ConfigureAwait(false); + if (response.IsSuccessful) return true; + + client = new RestClient($"https://glz-{Constants.Shard}-1.{Constants.Region}.a.pvp.net/pregame/v1/players/{Constants.Ppuuid}"); + response = await client.ExecuteGetAsync(request).ConfigureAwait(false); + if (response.IsSuccessful) return true; + + // Constants.Log.Error("CheckMatchAsync Failed: {e}", response.ErrorException); + return false; + } +} \ No newline at end of file diff --git a/WAIUA/Helpers/Constants.cs b/WAIUA/Helpers/Constants.cs new file mode 100644 index 00000000..811f6194 --- /dev/null +++ b/WAIUA/Helpers/Constants.cs @@ -0,0 +1,39 @@ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using RestSharp; +using Serilog.Core; + +namespace WAIUA.Helpers; + +public static class Constants +{ + public static ConcurrentDictionary UrlToBody = new(); + + // TODO: Automate this with translations + public static readonly Dictionary GamePodsDictionary = new() + { + {"aresqa.aws-rclusterprod-use1-1.dev1-gp-ashburn-1","Ashburn"},{"aresriot.aws-mes1-prod.eu-gp-bahrain-1","Bahrain"},{"aresriot.aws-mes1-prod.ext1-gp-bahrain-1","Bahrain"},{"aresriot.aws-rclusterprod-mes1-1.eu-gp-bahrain-awsedge-1","Bahrain"},{"aresriot.aws-rclusterprod-mes1-1.ext1-gp-bahrain-awsedge-1","Bahrain"},{"aresriot.aws-rclusterprod-mes1-1.tournament-gp-bahrain-awsedge-1","Bahrain"},{"aresriot.aws-rclusterprod-bog1-1.latam-gp-bogota-1","Bogotá"},{"aresriot.aws-rclusterprod-bog1-1.tournament-gp-bogota-1","Bogotá"},{"aresriot.aws-rclusterprod-usw2-1.tournament-gp-cmob-1","CMOB 1"},{"aresriot.aws-rclusterprod-usw2-1.tournament-gp-cmob-2","CMOB 2"},{"aresriot.aws-rclusterprod-usw2-1.tournament-gp-cmob-3","CMOB 3"},{"aresriot.aws-rclusterprod-usw2-1.tournament-gp-cmob-4","CMOB 4"},{"aresriot.mtl-riot-ord2-3.ext1-gp-chicago-1","Chicago"},{"aresriot.mtl-riot-ord2-3.latam-gp-chicago-1","Chicago"},{"aresqa.aws-rclusterprod-dfw1-1.dev1-gp-dallas-1","Dallas"},{"aresqa.aws-rclusterprod-euc1-1.dev1-gp-frankfurt-1","Frankfurt"},{"aresqa.aws-rclusterprod-euc1-1.stage1-gp-frankfurt-1","Frankfurt"},{"aresriot.aws-euc1-prod.eu-gp-frankfurt-1","Frankfurt"},{"aresriot.aws-euc1-prod.ext1-gp-eu1","Frankfurt"},{"aresriot.aws-euc1-prod.ext1-gp-frankfurt-1","Frankfurt"},{"aresriot.aws-rclusterprod-euc1-1.ext1-gp-eu1","Frankfurt"},{"aresriot.aws-rclusterprod-euc1-1.tournament-gp-frankfurt-1","Frankfurt"},{"aresriot.aws-rclusterprod-euc1-1.eu-gp-frankfurt-1","Frankfurt 1"},{"aresriot.aws-rclusterprod-euc1-1.eu-gp-frankfurt-awsedge-1","Frankfurt 2"},{"aresriot.aws-ape1-prod.ap-gp-hongkong-1","Hong Kong"},{"aresriot.aws-ape1-prod.ext1-gp-hongkong-1","Hong Kong"},{"aresriot.aws-rclusterprod-ape1-1.ext1-gp-hongkong-1","Hong Kong"},{"aresriot.aws-rclusterprod-ape1-1.tournament-gp-hongkong-1","Hong Kong"},{"aresriot.aws-rclusterprod-ape1-1.ap-gp-hongkong-1","Hong Kong 1"},{"aresriot.aws-rclusterprod-ape1-1.ap-gp-hongkong-awsedge-1","Hong Kong 2"},{"aresriot.mtl-riot-ist1-2.eu-gp-istanbul-1","Istanbul"},{"aresriot.mtl-riot-ist1-2.tournament-gp-istanbul-1","Istanbul"},{"aresriot.aws-euw2-prod.eu-gp-london-1","London"},{"aresriot.aws-rclusterprod-euw2-1.eu-gp-london-awsedge-1","London"},{"aresriot.aws-rclusterprod-euw2-1.tournament-gp-london-awsedge-1","London"},{"aresriot.aws-rclusterprod-mad1-1.eu-gp-madrid-1","Madrid"},{"aresriot.aws-rclusterprod-mad1-1.tournament-gp-madrid-1","Madrid"},{"aresriot.mtl-tmx-mex1-1.ext1-gp-mexicocity-1","Mexico City"},{"aresriot.mtl-tmx-mex1-1.latam-gp-mexicocity-1","Mexico City"},{"aresriot.mtl-tmx-mex1-1.tournament-gp-mexicocity-1","Mexico City"},{"aresriot.mia1.latam-gp-miami-1","Miami"},{"aresriot.mia1.tournament-gp-miami-1","Miami"},{"aresriot.aws-aps1-prod.ap-gp-mumbai-1","Mumbai"},{"aresriot.aws-rclusterprod-aps1-1.ap-gp-mumbai-awsedge-1","Mumbai"},{"aresriot.aws-rclusterprod-aps1-1.tournament-gp-mumbai-awsedge-1","Mumbai"},{"aresriot.aws-rclusterprod-usw2-1.tournament-gp-offline-1","Offline 1"},{"aresriot.aws-rclusterprod-usw2-1.tournament-gp-offline-2","Offline 2"},{"aresriot.aws-rclusterprod-usw2-1.tournament-gp-offline-3","Offline 3"},{"aresriot.aws-rclusterprod-usw2-1.tournament-gp-offline-4","Offline 4"},{"aresriot.aws-rclusterprod-usw2-1.tournament-gp-offline-5","Offline 5"},{"aresriot.aws-rclusterprod-usw2-1.tournament-gp-offline-6","Offline 6"},{"aresriot.aws-rclusterprod-usw2-1.tournament-gp-offline-7","Offline 7"},{"aresriot.aws-rclusterprod-usw2-1.tournament-gp-offline-8","Offline 8"},{"aresriot.aws-euw3-prod.eu-gp-paris-1","Paris"},{"aresriot.aws-rclusterprod-euw3-1.tournament-gp-paris-1","Paris"},{"aresriot.aws-rclusterprod-euw3-1.eu-gp-paris-1","Paris 1"},{"aresriot.aws-rclusterprod-euw3-1.eu-gp-paris-awsedge-1","Paris 2"},{"aresriot.mtl-ctl-scl2-2.ext1-gp-santiago-1","Santiago"},{"aresriot.mtl-ctl-scl2-2.latam-gp-santiago-1","Santiago"},{"aresriot.mtl-ctl-scl2-2.tournament-gp-santiago-1","Santiago"},{"aresriot.aws-rclusterprod-sae1-1.ext1-gp-saopaulo-1","Sao Paulo"},{"aresriot.aws-rclusterprod-sae1-1.tournament-gp-saopaulo-1","Sao Paulo"},{"aresriot.aws-sae1-prod.br-gp-saopaulo-1","Sao Paulo"},{"aresriot.aws-sae1-prod.ext1-gp-saopaulo-1","Sao Paulo"},{"aresriot.aws-rclusterprod-sae1-1.br-gp-saopaulo-1","Sao Paulo 1"},{"aresriot.aws-rclusterprod-sae1-1.br-gp-saopaulo-awsedge-1","Sao Paulo 2"},{"aresriot.aws-apne2-prod.ext1-gp-seoul-1","Seoul"},{"aresriot.aws-apne2-prod.kr-gp-seoul-1","Seoul"},{"aresriot.aws-rclusterprod-apne2-1.ext1-gp-seoul-1","Seoul"},{"aresriot.aws-rclusterprod-apne2-1.tournament-gp-seoul-1","Seoul"},{"aresriot.aws-rclusterprod-apne2-1.kr-gp-seoul-1","Seoul 1"},{"aresriot.aws-apse1-prod.ap-gp-singapore-1","Singapore"},{"aresriot.aws-apse1-prod.ext1-gp-singapore-1","Singapore"},{"aresriot.aws-rclusterprod-apse1-1.ext1-gp-singapore-1","Singapore"},{"aresriot.aws-rclusterprod-apse1-1.tournament-gp-singapore-1","Singapore"},{"aresriot.aws-rclusterprod-apse1-1.ap-gp-singapore-1","Singapore 1"},{"aresriot.aws-rclusterprod-apse1-1.ap-gp-singapore-awsedge-1","Singapore 2"},{"aresriot.aws-eun1-prod.eu-gp-stockholm-1","Stockholm"},{"aresriot.aws-rclusterprod-eun1-1.tournament-gp-stockholm-1","Stockholm"},{"aresriot.aws-rclusterprod-eun1-1.eu-gp-stockholm-1","Stockholm 1"},{"aresriot.aws-rclusterprod-eun1-1.eu-gp-stockholm-awsedge-1","Stockholm 2"},{"aresriot.aws-apse2-prod.ap-gp-sydney-1","Sydney"},{"aresriot.aws-apse2-prod.ext1-gp-sydney-1","Sydney"},{"aresriot.aws-rclusterprod-apse2-1.ext1-gp-sydney-1","Sydney"},{"aresriot.aws-rclusterprod-apse2-1.tournament-gp-sydney-1","Sydney"},{"aresriot.aws-rclusterprod-apse2-1.ap-gp-sydney-1","Sydney 1"},{"aresriot.aws-rclusterprod-apse2-1.ap-gp-sydney-awsedge-1","Sydney 2"},{"aresriot.aws-apne1-prod.ap-gp-tokyo-1","Tokyo"},{"aresriot.aws-apne1-prod.eu-gp-tokyo-1","Tokyo"},{"aresriot.aws-apne1-prod.ext1-gp-kr1","Tokyo"},{"aresriot.aws-apne1-prod.ext1-gp-tokyo-1","Tokyo"},{"aresriot.aws-rclusterprod-apne1-1.eu-gp-tokyo-1","Tokyo"},{"aresriot.aws-rclusterprod-apne1-1.ext1-gp-kr1","Tokyo"},{"aresriot.aws-rclusterprod-apne1-1.tournament-gp-tokyo-1","Tokyo"},{"aresriot.aws-rclusterprod-apne1-1.ap-gp-tokyo-1","Tokyo 1"},{"aresriot.aws-rclusterprod-apne1-1.ap-gp-tokyo-awsedge-1","Tokyo 2"},{"aresqa.aws-usw2-dev.main1-gp-tournament-2","Tournament"},{"aresriot.aws-rclusterprod-atl1-1.na-gp-atlanta-1","US Central (Georgia)"},{"aresriot.aws-rclusterprod-atl1-1.tournament-gp-atlanta-1","US Central (Georgia)"},{"aresriot.mtl-riot-ord2-3.na-gp-chicago-1","US Central (Illinois)"},{"aresriot.mtl-riot-ord2-3.tournament-gp-chicago-1","US Central (Illinois)"},{"aresriot.aws-rclusterprod-dfw1-1.na-gp-dallas-1","US Central (Texas)"},{"aresriot.aws-rclusterprod-dfw1-1.tournament-gp-dallas-1","US Central (Texas)"},{"aresriot.aws-rclusterprod-use1-1.na-gp-ashburn-1","US East (N. Virginia 1)"},{"aresriot.aws-rclusterprod-use1-1.na-gp-ashburn-awsedge-1","US East (N. Virginia 2)"},{"aresriot.aws-rclusterprod-use1-1.ext1-gp-ashburn-1","US East (N. Virginia)"},{"aresriot.aws-rclusterprod-use1-1.pbe-gp-ashburn-1","US East (N. Virginia)"},{"aresriot.aws-rclusterprod-use1-1.tournament-gp-ashburn-1","US East (N. Virginia)"},{"aresriot.aws-use1-prod.ext1-gp-ashburn-1","US East (N. Virginia)"},{"aresriot.aws-use1-prod.na-gp-ashburn-1","US East (N. Virginia)"},{"aresriot.aws-use1-prod.pbe-gp-ashburn-1","US East (N. Virginia)"},{"aresriot.aws-rclusterprod-usw1-1.na-gp-norcal-1","US West (N. California 1)"},{"aresriot.aws-rclusterprod-usw1-1.na-gp-norcal-awsedge-1","US West (N. California 2)"},{"aresriot.aws-rclusterprod-usw1-1.ext1-gp-na2","US West (N. California)"},{"aresriot.aws-rclusterprod-usw1-1.pbe-gp-norcal-1","US West (N. California)"},{"aresriot.aws-rclusterprod-usw1-1.tournament-gp-norcal-1","US West (N. California)"},{"aresriot.aws-usw1-prod.ext1-gp-na2","US West (N. California)"},{"aresriot.aws-usw1-prod.ext1-gp-norcal-1","US West (N. California)"},{"aresriot.aws-usw1-prod.na-gp-norcal-1","US West (N. California)"},{"aresriot.aws-rclusterprod-usw2-1.na-gp-oregon-1","US West (Oregon 1)"},{"aresriot.aws-rclusterprod-usw2-1.na-gp-oregon-awsedge-1","US West (Oregon 2)"},{"aresriot.aws-rclusterprod-usw2-1.pbe-gp-oregon-1","US West (Oregon)"},{"aresriot.aws-rclusterprod-usw2-1.tournament-gp-oregon-1","US West (Oregon)"},{"aresriot.aws-usw2-prod.na-gp-oregon-1","US West (Oregon)"},{"aresriot.aws-usw2-prod.pbe-gp-oregon-1","US West (Oregon)"},{"aresqa.aws-usw2-dev.main1-gp-1","US West 1"},{"aresqa.aws-usw2-dev.stage1-gp-1","US West 1"},{"aresqa.aws-usw2-dev.main1-gp-4","US West 2"},{"aresriot.aws-rclusterprod-waw1-1.eu-gp-warsaw-1","Warsaw"},{"aresriot.aws-rclusterprod-waw1-1.tournament-gp-warsaw-1","Warsaw"} + }; + + public static readonly List BeforeAscendantSeasons = new() + { + new Guid("3e47230a-463c-a301-eb7d-67bb60357d4f"), + new Guid("d929bc38-4ab6-7da4-94f0-ee84f8ac141e"), + new Guid("573f53ac-41a5-3a7d-d9ce-d6a6298e5704") + }; + + public static string AccessToken { get; set; } + public static string EntitlementToken { get; set; } + public static string Region { get; set; } + public static string Shard { get; set; } + public static string Version { get; set; } + public static string LocalAppDataPath { get; set; } + public static Guid Ppuuid { get; set; } + public static Guid PPartyId { get; set; } + public static string Port { get; set; } + public static string LPassword { get; set; } + + public static Logger Log { get; set; } + // public static RestClient RestClient { get; set; } +} \ No newline at end of file diff --git a/WAIUA/Helpers/LiveMatch.cs b/WAIUA/Helpers/LiveMatch.cs new file mode 100644 index 00000000..80eac1aa --- /dev/null +++ b/WAIUA/Helpers/LiveMatch.cs @@ -0,0 +1,931 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.Linq; +using System.Text; +using System.Text.Json; +using System.Text.Json.Serialization; +using System.Threading.Tasks; +using System.Windows; +using RestSharp; +using RestSharp.Serializers.Json; +using WAIUA.Objects; +using WAIUA.Properties; +using static WAIUA.Helpers.Login; + +namespace WAIUA.Helpers; + +public class LiveMatch +{ + public delegate void UpdateProgress(int percentage); + + public MatchDetails MatchInfo { get; } = new(); + private static Guid Matchid { get; set; } + private static Guid Partyid { get; set; } + private static string Stage { get; set; } + public string QueueId { get; set; } + public string Status { get; set; } + + private static async Task CheckAndSetLiveMatchIdAsync() + { + var client = new RestClient($"https://glz-{Constants.Shard}-1.{Constants.Region}.a.pvp.net/core-game/v1/players/{Constants.Ppuuid}"); + var request = new RestRequest(); + request.AddHeader("X-Riot-Entitlements-JWT", Constants.EntitlementToken); + request.AddHeader("Authorization", $"Bearer {Constants.AccessToken}"); + var response = await client.ExecuteGetAsync(request).ConfigureAwait(false); + if (response.IsSuccessful) + { + Matchid = response.Data.MatchId; + Stage = "core"; + return true; + } + + client = new RestClient($"https://glz-{Constants.Shard}-1.{Constants.Region}.a.pvp.net/pregame/v1/players/{Constants.Ppuuid}"); + response = await client.ExecuteGetAsync(request).ConfigureAwait(false); + if (response.IsSuccessful) + { + Matchid = response.Data.MatchId; + Stage = "pre"; + return true; + } + + Constants.Log.Error("CheckAndSetLiveMatchIdAsync() failed. Response: {Response}", response.ErrorException); + return false; + } + + public async Task CheckAndSetPartyIdAsync() + { + var client = new RestClient($"https://glz-{Constants.Shard}-1.{Constants.Region}.a.pvp.net/parties/v1/players/{Constants.Ppuuid}"); + var request = new RestRequest(); + request.AddHeader("X-Riot-Entitlements-JWT", Constants.EntitlementToken); + request.AddHeader("Authorization", $"Bearer {Constants.AccessToken}"); + request.AddHeader("X-Riot-ClientVersion", Constants.Version); + var response = await client.ExecuteGetAsync(request).ConfigureAwait(false); + if (!response.IsSuccessful) return false; + Partyid = response.Data.CurrentPartyId; + return true; + } + + + public static async Task LiveMatchChecksAsync() + { + if (await Checks.CheckLoginAsync().ConfigureAwait(false)) + { + await LocalRegionAsync().ConfigureAwait(false); + return await CheckAndSetLiveMatchIdAsync().ConfigureAwait(false); + } + + if (!await Checks.CheckLocalAsync().ConfigureAwait(false)) return false; + await LocalLoginAsync().ConfigureAwait(false); + await Checks.CheckLoginAsync().ConfigureAwait(false); + await LocalRegionAsync().ConfigureAwait(false); + + return await CheckAndSetLiveMatchIdAsync().ConfigureAwait(false); + } + + private static async Task GetLiveMatchDetailsAsync() + { + RestClient client = new($"https://glz-{Constants.Shard}-1.{Constants.Region}.a.pvp.net/core-game/v1/matches/{Matchid}"); + RestRequest request = new(); + request.AddHeader("X-Riot-Entitlements-JWT", Constants.EntitlementToken); + request.AddHeader("Authorization", $"Bearer {Constants.AccessToken}"); + var response = await client.ExecuteGetAsync(request).ConfigureAwait(false); + if (response.IsSuccessful) return response.Data; + Constants.Log.Error("GetLiveMatchDetailsAsync() failed. Response: {Response}", response.ErrorException); + return null; + } + + private static async Task GetPreMatchDetailsAsync() + { + RestClient client = new($"https://glz-{Constants.Shard}-1.{Constants.Region}.a.pvp.net/pregame/v1/matches/{Matchid}"); + RestRequest request = new(); + request.AddHeader("X-Riot-Entitlements-JWT", Constants.EntitlementToken); + request.AddHeader("Authorization", $"Bearer {Constants.AccessToken}"); + var response = await client.ExecuteGetAsync(request).ConfigureAwait(false); + if (response.IsSuccessful) return response.Data; + Constants.Log.Error("GetPreMatchDetailsAsync() failed. Response: {Response}", response.ErrorException); + return null; + } + + private static async Task GetPartyDetailsAsync() + { + RestClient client = new($"https://glz-{Constants.Shard}-1.{Constants.Region}.a.pvp.net/parties/v1/parties/{Partyid}"); + RestRequest request = new(); + request.AddHeader("X-Riot-Entitlements-JWT", Constants.EntitlementToken); + request.AddHeader("Authorization", $"Bearer {Constants.AccessToken}"); + var response = await client.ExecuteGetAsync(request).ConfigureAwait(false); + if (response.IsSuccessful) return response.Data; + Constants.Log.Error("GetPreMatchDetailsAsync() failed. Response: {Response}", response.ErrorException); + return null; + } + + public async Task> LiveMatchOutputAsync(UpdateProgress updateProgress) + { + var playerList = new List(); + var playerTasks = new List>(); + var seasonData = new SeasonData(); + var presencesResponse = new PresencesResponse(); + + if (Stage == "pre") + { + var matchIdInfo = await GetPreMatchDetailsAsync().ConfigureAwait(false); + updateProgress(10); + + if (matchIdInfo != null) + { + Task sTask = Task.Run(async () => seasonData = await GetSeasonsAsync().ConfigureAwait(false)); + Task pTask = Task.Run(async () => presencesResponse = await GetPresencesAsync().ConfigureAwait(false)); + await Task.WhenAll(sTask, pTask).ConfigureAwait(false); + sbyte index = 0; + + foreach (var riotPlayer in matchIdInfo.AllyTeam.Players) + { + async Task GetPlayerInfo() + { + Player player = new(); + + var t1 = GetCardAsync(riotPlayer.PlayerIdentity.PlayerCardId, index); + var t3 = GetMatchHistoryAsync(riotPlayer.Subject); + var t4 = GetPlayerHistoryAsync(riotPlayer.Subject, seasonData); + var t5 = GetPreSkinInfoAsync(index); + var t6 = GetPresenceInfoAsync(riotPlayer.Subject, presencesResponse); + + await Task.WhenAll(t1, t3, t4, t5, t6).ConfigureAwait(false); + // await Task.WhenAll(t1, t3, t5, t6).ConfigureAwait(false); + + player.IdentityData = t1.Result; + player.MatchHistoryData = t3.Result; + player.RankData = t4.Result; + player.SkinData = t5.Result; + player.PlayerUiData = t6.Result; + player.IgnData = await GetIgcUsernameAsync(riotPlayer.Subject, riotPlayer.PlayerIdentity.Incognito, player.PlayerUiData.PartyUuid).ConfigureAwait(false); + player.AccountLevel = !riotPlayer.PlayerIdentity.HideAccountLevel ? riotPlayer.PlayerIdentity.AccountLevel.ToString() : "-"; + player.TeamId = "Blue"; + player.Active = Visibility.Visible; + return player; + } + + playerTasks.Add(GetPlayerInfo()); + + index++; + } + + var gamePodId = matchIdInfo.GamePodId; + if (Constants.GamePodsDictionary.TryGetValue(gamePodId, out var serverName)) MatchInfo.Server = "🌍 " + serverName; + } + } + else + { + var matchIdInfo = await GetLiveMatchDetailsAsync().ConfigureAwait(false); + updateProgress(10); + + if (matchIdInfo != null) + { + Task sTask = Task.Run(async () => seasonData = await GetSeasonsAsync().ConfigureAwait(false)); + Task pTask = Task.Run(async () => presencesResponse = await GetPresencesAsync().ConfigureAwait(false)); + await Task.WhenAll(sTask, pTask).ConfigureAwait(false); + sbyte index = 0; + + foreach (var riotPlayer in matchIdInfo.Players) + { + if (!riotPlayer.IsCoach) + { + async Task GetPlayerInfo() + { + Player player = new(); + + var t1 = GetAgentInfoAsync(riotPlayer.CharacterId); + // var t2 = GetCompHistoryAsync(riotPlayer.Subject); + var t3 = GetPlayerHistoryAsync(riotPlayer.Subject, seasonData); + var t4 = GetMatchSkinInfoAsync(index); + var t5 = GetPresenceInfoAsync(riotPlayer.Subject, presencesResponse); + + await Task.WhenAll(t1, t3, t4, t5).ConfigureAwait(false); + // await Task.WhenAll(t1, t2, t3, t4, t5).ConfigureAwait(false); + + player.IdentityData = t1.Result; + // player.MatchHistoryData = t2.Result; + player.RankData = t3.Result; + player.SkinData = t4.Result; + player.PlayerUiData = t5.Result; + player.IgnData = await GetIgcUsernameAsync(riotPlayer.Subject, riotPlayer.PlayerIdentity.Incognito, player.PlayerUiData.PartyUuid).ConfigureAwait(false); + // player.RankData = await GetPlayerHistoryAsync(riotPlayer.Subject, seasonData).ConfigureAwait(false); + player.AccountLevel = !riotPlayer.PlayerIdentity.HideAccountLevel ? riotPlayer.PlayerIdentity.AccountLevel.ToString() : "-"; + player.TeamId = riotPlayer.TeamId; + player.Active = Visibility.Visible; + return player; + } + + playerTasks.Add(GetPlayerInfo()); + } + + index++; + } + + var gamePodId = matchIdInfo.GamePodId; + if (Constants.GamePodsDictionary.TryGetValue(gamePodId, out var serverName)) MatchInfo.Server = "🌍 " + serverName; + } + } + + playerList.AddRange(await Task.WhenAll(playerTasks).ConfigureAwait(false)); + updateProgress(75); + + var colours = new List + {"Red", "#32e2b2", "DarkOrange", "White", "DeepSkyBlue", "MediumPurple", "SaddleBrown"}; + + List newArray = new(); + newArray.AddRange(Enumerable.Repeat("Transparent", playerList.Count)); + + try + { + for (var i = 0; i < playerList.Count; i++) + { + if (playerList[i].PlayerUiData is null) continue; + + var colourused = false; + var id = playerList[i].PlayerUiData.PartyUuid; + for (var j = i; j < playerList.Count; j++) + { + if (newArray[i] != "Transparent" || playerList[i] == playerList[j] || + playerList[j].PlayerUiData?.PartyUuid != id || id == Guid.Empty) continue; + newArray[j] = colours[0]; + colourused = true; + } + if (!colourused) continue; + newArray[i] = colours[0]; + colours.RemoveAt(0); + + } + + for (var i = 0; i < playerList.Count; i++) playerList[i].PlayerUiData.PartyColour = newArray[i]; + updateProgress(100); + } + catch (Exception) + { + Constants.Log.Error("LiveMatchOutputAsync() party colour failed."); + } + + return playerList; + } + + public async Task> PartyOutputAsync() + { + var playerList = new List(); + var playerTasks = new List>(); + var partyInfo = await GetPartyDetailsAsync().ConfigureAwait(false); + + if (partyInfo != null) + { + var seasonData = await GetSeasonsAsync().ConfigureAwait(false); + sbyte index = 0; + + foreach (var riotPlayer in partyInfo.Members) + { + async Task GetPlayerInfo() + { + Player player = new(); + + var t1 = GetCardAsync(riotPlayer.PlayerIdentity.PlayerCardId, index); + var t3 = GetMatchHistoryAsync(riotPlayer.Subject); + var t4 = GetPlayerHistoryAsync(riotPlayer.Subject, seasonData); + + await Task.WhenAll(t1, t3, t4).ConfigureAwait(false); + + player.IdentityData = t1.Result; + player.MatchHistoryData = t3.Result; + player.RankData = t4.Result; + player.PlayerUiData = new PlayerUIData + { + BackgroundColour = "#252A40", + PartyUuid = Partyid, + PartyColour = "Transparent", + Puuid = riotPlayer.PlayerIdentity.Subject + }; + player.IgnData = await GetIgcUsernameAsync(riotPlayer.Subject, false, player.PlayerUiData.PartyUuid).ConfigureAwait(false); + player.AccountLevel = !riotPlayer.PlayerIdentity.HideAccountLevel ? riotPlayer.PlayerIdentity.AccountLevel.ToString() : "-"; + player.TeamId = "Blue"; + player.Active = Visibility.Visible; + return player; + } + + playerTasks.Add(GetPlayerInfo()); + index++; + } + } + + playerList.AddRange(await Task.WhenAll(playerTasks).ConfigureAwait(false)); + + return playerList; + } + + private static async Task GetIgcUsernameAsync(Guid puuid, bool isIncognito, Guid partyId) + { + IgnData ignData = new(); + if (isIncognito && partyId != Constants.PPartyId) + { + ignData.Username = "----"; + ignData.TrackerEnabled = Visibility.Hidden; + ignData.TrackerDisabled = Visibility.Visible; + } + else + { + ignData.Username = await GetNameServiceGetUsernameAsync(puuid).ConfigureAwait(false); + var trackerUri = await TrackerAsync(ignData.Username).ConfigureAwait(false); + if (trackerUri != null) + return new IgnData + { + TrackerEnabled = Visibility.Visible, + TrackerDisabled = Visibility.Collapsed, + TrackerUri = trackerUri, + Username = ignData.Username + " 🔗" + }; + ignData.TrackerEnabled = Visibility.Hidden; + ignData.TrackerDisabled = Visibility.Visible; + } + + return ignData; + } + + private static async Task GetAgentInfoAsync(Guid agentid) + { + IdentityData identityData = new(); + if (agentid != Guid.Empty) + { + identityData.Image = new Uri(Constants.LocalAppDataPath + $"\\ValAPI\\agentsimg\\{agentid}.png"); + var agents = JsonSerializer.Deserialize>(await File.ReadAllTextAsync(Constants.LocalAppDataPath + "\\ValAPI\\agents.txt").ConfigureAwait(false)); + agents.TryGetValue(agentid, out var agentName); + identityData.Name = agentName; + } + else + { + Constants.Log.Error("GetAgentInfoAsync Failed: AgentID is empty"); + identityData.Image = null; + identityData.Name = ""; + } + + return identityData; + } + + private static async Task GetCardAsync(Guid cardid, sbyte index) + { + IdentityData identityData = new(); + if (cardid != Guid.Empty) + { + var cards = JsonSerializer.Deserialize>(await File.ReadAllTextAsync(Constants.LocalAppDataPath + "\\ValAPI\\cards.txt").ConfigureAwait(false)); + cards.TryGetValue(cardid, out var card); + identityData.Image = card; + identityData.Name = Resources.Player + " " + (index + 1); + } + else + { + Constants.Log.Error("GetCardAsync Failed: CardID is empty"); + identityData.Image = null; + identityData.Name = ""; + } + + return identityData; + } + + private static async Task GetMatchSkinInfoAsync(sbyte playerno) + { + var response = await DoCachedRequestAsync(Method.Get, + $"https://glz-{Constants.Shard}-1.{Constants.Region}.a.pvp.net/core-game/v1/matches/{Matchid}/loadouts", + true).ConfigureAwait(false); + if (response.IsSuccessful) + { + var content = JsonSerializer.Deserialize(response.Content); + var vandalchroma = content.Loadouts[playerno].Loadout + .Items["9c82e19d-4575-0200-1a81-3eacf00cf872"].Sockets["3ad1b2b2-acdb-4524-852f-954a76ddae0a"] + .Item.Id; + var phantomchroma = content.Loadouts[playerno].Loadout + .Items["ee8e8d15-496b-07ac-e5f6-8fae5d4c7b1a"].Sockets["3ad1b2b2-acdb-4524-852f-954a76ddae0a"] + .Item.Id; + + return await GetSkinInfoAsync(phantomchroma, vandalchroma); + } + + Constants.Log.Error("GetMatchSkinInfoAsync Failed: {e}", response.ErrorException); + return new SkinData(); + } + + private static async Task GetPreSkinInfoAsync(sbyte playerno) + { + var response = await DoCachedRequestAsync(Method.Get, + $"https://glz-{Constants.Shard}-1.{Constants.Region}.a.pvp.net/pregame/v1/matches/{Matchid}/loadouts", + true).ConfigureAwait(false); + if (response.IsSuccessful) + try + { + var content = JsonSerializer.Deserialize(response.Content); + var vandalchroma = content.Loadouts[playerno] + .Items["9c82e19d-4575-0200-1a81-3eacf00cf872"].Sockets["3ad1b2b2-acdb-4524-852f-954a76ddae0a"] + .Item.Id; + var phantomchroma = content.Loadouts[playerno] + .Items["ee8e8d15-496b-07ac-e5f6-8fae5d4c7b1a"].Sockets["3ad1b2b2-acdb-4524-852f-954a76ddae0a"] + .Item.Id; + + return await GetSkinInfoAsync(phantomchroma, vandalchroma); + } + catch + { + // ignored + } + + Constants.Log.Error("GetPreSkinInfoAsync Failed: {e}", response.ErrorException); + return new SkinData(); + } + + private static async Task GetSkinInfoAsync(Guid phantomchroma, Guid vandalchroma) + { + var skins = JsonSerializer.Deserialize>(await File.ReadAllTextAsync(Constants.LocalAppDataPath + "\\ValAPI\\skinchromas.txt").ConfigureAwait(false)); + + skins.TryGetValue(phantomchroma, out var phantom); + skins.TryGetValue(vandalchroma, out var vandal); + + return new SkinData + { + PhantomImage = phantomchroma == new Guid("52221ba2-4e4c-ec76-8c81-3483506d5242") ? new Uri("pack://application:,,,/Assets/phantom.png") : phantom.Image, + PhantomName = phantom?.Name, + VandalImage = vandalchroma == new Guid("19629ae1-4996-ae98-7742-24a240d41f99") ? new Uri("pack://application:,,,/Assets/vandal.png") : vandal.Image, + VandalName = vandal?.Name + }; + } + + + public static async Task GetMatchHistoryAsync(Guid puuid) + { + MatchHistoryData history = new() + { + PreviousGameColour = "#7f7f7f", + PreviouspreviousGameColour = "#7f7f7f", + PreviouspreviouspreviousGameColour = "#7f7f7f" + }; + + try + { + if (puuid != Guid.Empty) + { + var response = await DoCachedRequestAsync(Method.Get, + $"https://pd.{Constants.Region}.a.pvp.net/mmr/v1/players/{puuid}/competitiveupdates?queue=competitive", + true, true).ConfigureAwait(false); + if (!response.IsSuccessful) + { + Constants.Log.Error("GetCompHistoryAsync request failed: {e}", response.ErrorException); + return history; + } + + var options = new JsonSerializerOptions + { + DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingDefault + }; + var content = JsonSerializer.Deserialize(response.Content, options); + + if (content?.Matches.Length > 0) + { + history.RankProgress = content.Matches[0].RankedRatingAfterUpdate; + var pmatch = content.Matches[0].RankedRatingEarned; + history.PreviousGame = Math.Abs(pmatch); + history.PreviousGameColour = pmatch switch + { + > 0 => "#32e2b2", + < 0 => "#ff4654", + _ => "#7f7f7f" + }; + } + + if (content?.Matches.Length > 1) + { + var ppmatch = content.Matches[1].RankedRatingEarned; + history.PreviouspreviousGame = Math.Abs(ppmatch); + history.PreviouspreviousGameColour = ppmatch switch + { + > 0 => "#32e2b2", + < 0 => "#ff4654", + _ => "#7f7f7f" + }; + } + + if (content?.Matches.Length > 2) + { + var pppmatch = content.Matches[2].RankedRatingEarned; + history.PreviouspreviouspreviousGame = Math.Abs(pppmatch); + history.PreviouspreviouspreviousGameColour = pppmatch switch + { + > 0 => "#32e2b2", + < 0 => "#ff4654", + _ => "#7f7f7f" + }; + } + } + else + { + Constants.Log.Error("GetMatchHistoryAsync: Puuid is null"); + } + } + catch (Exception e) + { + Constants.Log.Error("GetMatchHistoryAsync failed: {e}", e); + } + + return history; + } + + private static async Task GetPlayerHistoryAsync(Guid puuid, SeasonData seasonData) + { + var rankData = new RankData(); + if (puuid != Guid.Empty) + { + int rank = 0, prank = 0, pprank = 0, ppprank = 0; + var response = await DoCachedRequestAsync(Method.Get, + $"https://pd.{Constants.Region}.a.pvp.net/mmr/v1/players/{puuid}", + true, + true).ConfigureAwait(false); + + if (!response.IsSuccessful) + { + Constants.Log.Error("GetPlayerHistoryAsync Failed: {e}", response.ErrorException); + return rankData; + } + + var options = new JsonSerializerOptions + { + DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingDefault + }; + var content = JsonSerializer.Deserialize(response.Content, options); + // var content = JsonSerializer.Deserialize>(allcontent.QueueSkills.Competitive.SeasonalInfoBySeasonId.Act.Keys); + try + { + content.QueueSkills.Competitive.SeasonalInfoBySeasonId.Act.TryGetValue(seasonData.CurrentSeason.ToString(), out var currentActJsonElement); + var currentAct = currentActJsonElement.Deserialize(); + rank = currentAct.CompetitiveTier; + if (rank is 1 or 2) rank = 0; + } + catch (Exception) + { + rank = 0; + } + + try + { + content.QueueSkills.Competitive.SeasonalInfoBySeasonId.Act.TryGetValue(seasonData.PreviousSeason.ToString(), out var pActJsonElement); + var PAct = pActJsonElement.Deserialize(); + switch (PAct.CompetitiveTier) + { + case 1 or 2: + prank = 0; + break; + case > 20: + { + if (Constants.BeforeAscendantSeasons.Contains(seasonData.PreviousSeason)) + { + prank = PAct.CompetitiveTier + 3; + } + else + { + prank = PAct.CompetitiveTier; + } + break; + } + default: + prank = PAct.CompetitiveTier; + break; + } + } + catch (Exception) + { + prank = 0; + } + + try + { + content.QueueSkills.Competitive.SeasonalInfoBySeasonId.Act.TryGetValue(seasonData.PreviouspreviousSeason.ToString(), out var ppActJsonElement); + var PPAct = ppActJsonElement.Deserialize(); + switch (PPAct.CompetitiveTier) + { + case 1 or 2: + pprank = 0; + break; + case > 20: + { + if (Constants.BeforeAscendantSeasons.Contains(seasonData.PreviouspreviousSeason)) + { + pprank = PPAct.CompetitiveTier + 3; + } + else + { + pprank = PPAct.CompetitiveTier; + } + break; + } + default: + pprank = PPAct.CompetitiveTier; + break; + } + } + catch (Exception) + { + pprank = 0; + } + + try + { + content.QueueSkills.Competitive.SeasonalInfoBySeasonId.Act.TryGetValue(seasonData.PreviouspreviouspreviousSeason.ToString(), out var pppActJsonElement); + var PPPAct = pppActJsonElement.Deserialize(); + switch (PPPAct.CompetitiveTier) + { + case 1 or 2: + ppprank = 0; + break; + case > 20: + { + if (Constants.BeforeAscendantSeasons.Contains(seasonData.PreviouspreviouspreviousSeason)) + { + ppprank = PPPAct.CompetitiveTier + 3; + } + else + { + ppprank = PPPAct.CompetitiveTier; + } + break; + } + default: + ppprank = PPPAct.CompetitiveTier; + break; + } + } + catch (Exception) + { + ppprank = 0; + } + + if (rank is 24 or 25 or 26) + { + var leaderboardResponse = await DoCachedRequestAsync(Method.Get, + $"https://pd.{Constants.Shard}.a.pvp.net/mmr/v1/leaderboards/affinity/{Constants.Region}/queue/competitive/season/{seasonData.CurrentSeason}?startIndex=0&size=0", + true).ConfigureAwait(false); + if (leaderboardResponse.Content != null) + { + var leaderboardcontent = JsonSerializer.Deserialize(leaderboardResponse.Content); + rankData.MaxRr = rank switch + { + 24 => leaderboardcontent.TierDetails["22"].RankedRatingThreshold, + 25 => leaderboardcontent.TierDetails["23"].RankedRatingThreshold, + 26 => leaderboardcontent.TierDetails["24"].RankedRatingThreshold, + _ => 100 + }; + } + } + + var ranks = JsonSerializer.Deserialize>(await File.ReadAllTextAsync(Constants.LocalAppDataPath + "\\ValAPI\\competitivetiers.txt").ConfigureAwait(false)); + + ranks.TryGetValue(rank, out var rank0); + rankData.RankImage = new Uri(Constants.LocalAppDataPath + $"\\ValAPI\\ranksimg\\{rank}.png"); + rankData.RankName = rank0; + + ranks.TryGetValue(prank, out var rank1); + rankData.PreviousrankImage = new Uri(Constants.LocalAppDataPath + $"\\ValAPI\\ranksimg\\{prank}.png"); + rankData.PreviousrankName = rank1; + + ranks.TryGetValue(pprank, out var rank2); + rankData.PreviouspreviousrankImage = new Uri(Constants.LocalAppDataPath + $"\\ValAPI\\ranksimg\\{pprank}.png"); + rankData.PreviouspreviousrankName = rank2; + + ranks.TryGetValue(ppprank, out var rank3); + rankData.PreviouspreviouspreviousrankImage = new Uri(Constants.LocalAppDataPath + $"\\ValAPI\\ranksimg\\{ppprank}.png"); + rankData.PreviouspreviouspreviousrankName = rank3; + } + else + { + Constants.Log.Error("GetPlayerHistoryAsync Failed: PUUID is empty"); + } + + return rankData; + } + + private static async Task GetSeasonsAsync() + { + var seasonData = new SeasonData(); + try + { + RestClient client = new($"https://shared.{Constants.Region}.a.pvp.net/content-service/v3/content"); + var request = new RestRequest().AddHeader("X-Riot-Entitlements-JWT", Constants.EntitlementToken) + .AddHeader("Authorization", $"Bearer {Constants.AccessToken}") + .AddHeader("X-Riot-ClientPlatform", + "ew0KCSJwbGF0Zm9ybVR5cGUiOiAiUEMiLA0KCSJwbGF0Zm9ybU9TIjogIldpbmRvd3MiLA0KCSJwbGF0Zm9ybU9TVmVyc2lvbiI6ICIxMC4wLjE5MDQyLjEuMjU2LjY0Yml0IiwNCgkicGxhdGZvcm1DaGlwc2V0IjogIlVua25vd24iDQp9") + .AddHeader("X-Riot-ClientVersion", Constants.Version); + client.UseSystemTextJson(new JsonSerializerOptions + { + DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingDefault + }); + var response = await client.ExecuteGetAsync(request).ConfigureAwait(false); + sbyte index = 0; + sbyte currentindex = 0; + + if (!response.IsSuccessful) + { + Constants.Log.Error("GetSeasonsAsync Failed: {e}", response.ErrorException); + return seasonData; + } + + foreach (var season in response.Data.Seasons) + { + if (season.IsActive & (season.Type == "act")) + { + seasonData.CurrentSeason = season.Id; + currentindex = index; + break; + } + + index++; + } + + currentindex--; + if (response.Data.Seasons[currentindex].Type == "act") + { + seasonData.PreviousSeason = response.Data.Seasons[currentindex].Id; + } + else + { + currentindex--; + seasonData.PreviousSeason = response.Data.Seasons[currentindex].Id; + } + + currentindex--; + if (response.Data.Seasons[currentindex].Type == "act") + { + seasonData.PreviouspreviousSeason = response.Data.Seasons[currentindex].Id; + } + else + { + currentindex--; + seasonData.PreviouspreviousSeason = response.Data.Seasons[currentindex].Id; + } + + currentindex--; + if (response.Data.Seasons[currentindex].Type == "act") + { + seasonData.PreviouspreviouspreviousSeason = response.Data.Seasons[currentindex].Id; + } + else + { + currentindex--; + seasonData.PreviouspreviouspreviousSeason = response.Data.Seasons[currentindex].Id; + } + } + catch (Exception e) + { + Constants.Log.Error("GetSeasonsAsync Failed: {Exception}", e); + } + + return seasonData; + } + + + private static async Task TrackerAsync(string username) + { + try + { + if (!string.IsNullOrEmpty(username)) + { + var encodedUsername = Uri.EscapeDataString(username); + var url = new Uri("https://tracker.gg/valorant/profile/riot/" + encodedUsername); + + RestClient client = new(url); + RestRequest request = new(); + var response = await client.ExecuteAsync(request).ConfigureAwait(false); + var numericStatusCode = (short) response.StatusCode; + + if (numericStatusCode == 200) return url; + } + } + catch (Exception e) + { + Constants.Log.Error("TrackerAsync Failed: {Exception}", e); + } + + return null; + } + + + private static async Task GetPresencesAsync() + { + var options = new RestClientOptions($"https://127.0.0.1:{Constants.Port}/chat/v4/presences") + { + RemoteCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => true + }; + var client = new RestClient(options); + + var request = new RestRequest().AddHeader("Authorization", + $"Basic {Convert.ToBase64String(Encoding.UTF8.GetBytes($"riot:{Constants.LPassword}"))}") + .AddHeader("X-Riot-ClientPlatform", + "ew0KCSJwbGF0Zm9ybVR5cGUiOiAiUEMiLA0KCSJwbGF0Zm9ybU9TIjogIldpbmRvd3MiLA0KCSJwbGF0Zm9ybU9TVmVyc2lvbiI6ICIxMC4wLjE5MDQyLjEuMjU2LjY0Yml0IiwNCgkicGxhdGZvcm1DaGlwc2V0IjogIlVua25vd24iDQp9") + .AddHeader("X-Riot-ClientVersion", Constants.Version); + client.UseSystemTextJson(new JsonSerializerOptions + { + DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingDefault + }); + var response = await client.ExecuteGetAsync(request).ConfigureAwait(false); + if (response.IsSuccessful) + return response.Data; + Constants.Log.Error("GetPresencesAsync Failed: {e}", response.ErrorException); + return null; + } + + private async Task GetPresenceInfoAsync(Guid puuid, PresencesResponse presences) + { + PlayerUIData playerUiData = new() + { + BackgroundColour = "#252A40", + Puuid = puuid + }; + try + { + foreach (var friend in presences.Presences) + if (friend.Puuid == puuid) + { + var json = Encoding.UTF8.GetString(Convert.FromBase64String(friend.Private)); + var content = JsonSerializer.Deserialize(json); + playerUiData.PartyUuid = content.PartyId; + if (puuid == Constants.Ppuuid) + { + var maps = JsonSerializer.Deserialize>(await File.ReadAllTextAsync(Constants.LocalAppDataPath + "\\ValAPI\\maps.txt").ConfigureAwait(false)); + + maps.TryGetValue(content.MatchMap, out var map); + MatchInfo.Map = map.Name; + MatchInfo.MapImage = new Uri(Constants.LocalAppDataPath + $"\\ValAPI\\mapsimg\\{map.UUID}.png"); + playerUiData.BackgroundColour = "#181E34"; + Constants.PPartyId = content.PartyId; + + if (content?.ProvisioningFlow == "CustomGame") + { + MatchInfo.GameMode = "Custom"; + MatchInfo.GameModeImage = new Uri(Constants.LocalAppDataPath + "\\ValAPI\\gamemodeimg\\96bd3920-4f36-d026-2b28-c683eb0bcac5.png"); + } + else + { + var textInfo = new CultureInfo("en-US", false).TextInfo; + + var gameModeName = ""; + var gameModeId = Guid.Parse("96bd3920-4f36-d026-2b28-c683eb0bcac5"); + QueueId = content?.QueueId; + Status = content?.SessionLoopState; + + switch (content?.QueueId) + { + case "competitive": + gameModeName = "Competitive"; + break; + case "unrated": + gameModeName = "Unrated"; + break; + case "deathmatch": + gameModeId = Guid.Parse("a8790ec5-4237-f2f0-e93b-08a8e89865b2"); + break; + case "spikerush": + gameModeId = Guid.Parse("e921d1e6-416b-c31f-1291-74930c330b7b"); + break; + case "ggteam": + gameModeId = Guid.Parse("a4ed6518-4741-6dcb-35bd-f884aecdc859"); + break; + case "newmap": + gameModeName = "New Map"; + break; + case "onefa": + gameModeId = Guid.Parse("96bd3920-4f36-d026-2b28-c683eb0bcac5"); + break; + case "snowball": + gameModeId = Guid.Parse("57038d6d-49b1-3a74-c5ef-3395d9f23a97"); + break; + default: + gameModeName = textInfo.ToTitleCase(content.QueueId); + break; + } + + + if (gameModeName == "") + { + var gamemodes = JsonSerializer.Deserialize>(await File.ReadAllTextAsync(Constants.LocalAppDataPath + "\\ValAPI\\gamemode.txt").ConfigureAwait(false)); + gamemodes.TryGetValue(gameModeId, out var gamemode); + MatchInfo.GameMode = gamemode; + } + else + { + MatchInfo.GameMode = gameModeName; + } + + MatchInfo.GameModeImage = new Uri(Constants.LocalAppDataPath + $"\\ValAPI\\gamemodeimg\\{gameModeId}.png"); + } + } + + break; + } + } + catch (Exception e) + { + Constants.Log.Error("GetPresenceInfoAsync Failed: {Exception}", e); + } + + return playerUiData; + } +} \ No newline at end of file diff --git a/WAIUA/Helpers/Login.cs b/WAIUA/Helpers/Login.cs new file mode 100644 index 00000000..953fa9ef --- /dev/null +++ b/WAIUA/Helpers/Login.cs @@ -0,0 +1,136 @@ +using System; +using System.IO; +using System.Linq; +using System.Text; +using System.Text.Json; +using System.Threading.Tasks; +using RestSharp; +using WAIUA.Objects; + +namespace WAIUA.Helpers; + +public static class Login +{ + public static async Task LocalLoginAsync() + { + await GetLatestVersionAsync().ConfigureAwait(false); + var options = new RestClientOptions($"https://127.0.0.1:{Constants.Port}/entitlements/v1/token") + { + RemoteCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => true + }; + var client = new RestClient(options); + var request = new RestRequest() + .AddHeader("Authorization", $"Basic {Convert.ToBase64String(Encoding.UTF8.GetBytes($"riot:{Constants.LPassword}"))}"); + var response = await client.ExecuteGetAsync(request).ConfigureAwait(false); + if (!response.IsSuccessful) + { + Constants.Log.Error("LocalLoginAsync Failed"); + return false; + } + + Constants.AccessToken = response.Data.AccessToken; + Constants.EntitlementToken = response.Data.Token; + Constants.Ppuuid = response.Data.Subject; + Constants.Log.Information("Logged in as {Ppuuid}", Constants.Ppuuid); + return true; + } + + public static async Task LocalRegionAsync() + { + var options = new RestClientOptions(new Uri($"https://127.0.0.1:{Constants.Port}/product-session/v1/external-sessions")) + { + RemoteCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => true + }; + + var client = new RestClient(options); + var request = new RestRequest().AddHeader("Authorization", $"Basic {Convert.ToBase64String(Encoding.UTF8.GetBytes($"riot:{Constants.LPassword}"))}") + .AddHeader("X-Riot-ClientPlatform", "ew0KCSJwbGF0Zm9ybVR5cGUiOiAiUEMiLA0KCSJwbGF0Zm9ybU9TIjogIldpbmRvd3MiLA0KCSJwbGF0Zm9ybU9TVmVyc2lvbiI6ICIxMC4wLjE5MDQyLjEuMjU2LjY0Yml0IiwNCgkicGxhdGZvcm1DaGlwc2V0IjogIlVua25vd24iDQp9") + .AddHeader("X-Riot-ClientVersion", Constants.Version); + var response = await client.ExecuteGetAsync(request).ConfigureAwait(false); + if (!response.IsSuccessful || response.Content == "{}") + { + Constants.Log.Error("LocalRegionAsync Failed: {e}", response.ErrorException); + return; + } + + var parts = response.Data.ExtensionData.First().Value.Deserialize().LaunchConfiguration.Arguments[3].Split('=', '&'); + switch (parts[1]) + { + case "latam": + Constants.Region = "na"; + Constants.Shard = "latam"; + break; + case "br": + Constants.Region = "na"; + Constants.Shard = "br"; + break; + default: + Constants.Region = parts[1]; + Constants.Shard = parts[1]; + break; + } + } + + public static async Task GetNameServiceGetUsernameAsync(Guid puuid) + { + if (puuid == Guid.Empty) return null; + var options = new RestClientOptions(new Uri($"https://pd.{Constants.Region}.a.pvp.net/name-service/v2/players")) + { + RemoteCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => true + }; + var client = new RestClient(options); + RestRequest request = new() + { + RequestFormat = DataFormat.Json + }; + + string[] body = {puuid.ToString()}; + request.AddJsonBody(body); + var response = await client.ExecutePutAsync(request).ConfigureAwait(false); + if (response.IsSuccessful) + { + var incorrectContent = response.Content.Replace("[", string.Empty).Replace("]", string.Empty).Replace("\n", string.Empty); + var content = JsonSerializer.Deserialize(incorrectContent); + return content.GameName + "#" + content.TagLine; + } + + Constants.Log.Error("GetNameServiceGetUsernameAsync Failed: {e}", response.ErrorException); + return ""; + } + + + private static async Task GetLatestVersionAsync() + { + var lines = await File.ReadAllLinesAsync(Constants.LocalAppDataPath + "\\ValAPI\\version.txt").ConfigureAwait(false); + Constants.Version = lines[0]; + } + + public static async Task DoCachedRequestAsync(Method method, string url, bool addRiotAuth, + bool bypassCache = false) + { + var attemptCache = method == Method.Get && !bypassCache; + if (attemptCache) + if (Constants.UrlToBody.TryGetValue(url, out var res)) + return res; + var client = new RestClient(url); + var request = new RestRequest(); + if (addRiotAuth) + { + request.AddHeader("X-Riot-Entitlements-JWT", Constants.EntitlementToken); + request.AddHeader("Authorization", $"Bearer {Constants.AccessToken}"); + request.AddHeader("X-Riot-ClientPlatform", + "ew0KCSJwbGF0Zm9ybVR5cGUiOiAiUEMiLA0KCSJwbGF0Zm9ybU9TIjogIldpbmRvd3MiLA0KCSJwbGF0Zm9ybU9TVmVyc2lvbiI6ICIxMC4wLjE5MDQyLjEuMjU2LjY0Yml0IiwNCgkicGxhdGZvcm1DaGlwc2V0IjogIlVua25vd24iDQp9"); + request.AddHeader("X-Riot-ClientVersion", Constants.Version); + } + + var response = await client.ExecuteAsync(request, method).ConfigureAwait(false); + if (!response.IsSuccessful) + { + Constants.Log.Error("Request to {url} Failed: {e}", url, response.ErrorException); + return response; + } + + if (attemptCache) Constants.UrlToBody.TryAdd(url, response); + return response; + } +} \ No newline at end of file diff --git a/WAIUA/Helpers/ValAPI.cs b/WAIUA/Helpers/ValAPI.cs new file mode 100644 index 00000000..8bcbc9b2 --- /dev/null +++ b/WAIUA/Helpers/ValAPI.cs @@ -0,0 +1,367 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text.Json; +using System.Threading.Tasks; +using System.Windows; +using RestSharp; +using WAIUA.Objects; +using Settings = WAIUA.Properties.Settings; + +namespace WAIUA.Helpers; + +public static class ValApi +{ + private static readonly RestClient Client; + private static readonly RestClient MediaClient; + + private static Urls _mapsInfo; + private static Urls _agentsInfo; + private static Urls _ranksInfo; + private static Urls _versionInfo; + private static Urls _skinsInfo; + private static Urls _cardsInfo; + private static Urls _gamemodeInfo; + private static List _allInfo; + + private static readonly Dictionary ValApiLanguages = new() + { + {"ar", "ar-AE"}, + {"de", "de-DE"}, + {"en", "en-US"}, + {"es", "es-ES"}, + {"fr", "fr-FR"}, + {"id", "id-ID"}, + {"it", "it-IT"}, + {"ja", "ja-JP"}, + {"ko", "ko-KR"}, + {"pl", "pl-PL"}, + {"pt", "pt-BR"}, + {"ru", "ru-RU"}, + {"th", "th-TH"}, + {"tr", "tr-TR"}, + {"vi", "vi-VN"}, + {"zh", "zh-CN"} + }; + + static ValApi() + { + Client = new RestClient("https://valorant-api.com/v1"); + MediaClient = new RestClient(); + } + + private static async Task GetValApiVersionAsync() + { + var request = new RestRequest("/version"); + var response = await Client.ExecuteGetAsync(request).ConfigureAwait(false); + return !response.IsSuccessful ? null : response.Data.Data.BuildDate; + } + + private static async Task GetLocalValApiVersionAsync() + { + if (!File.Exists(Constants.LocalAppDataPath + "\\ValAPI\\version.txt")) return null; + try + { + var lines = await File.ReadAllLinesAsync(Constants.LocalAppDataPath + "\\ValAPI\\version.txt") + .ConfigureAwait(false); + return lines[1]; + } + catch + { + return ""; + } + } + + private static Task GetUrlsAsync() + { + var language = ValApiLanguages.GetValueOrDefault(Settings.Default.Language, "en-US"); + _mapsInfo = new Urls + { + Name = "Maps", + Filepath = Constants.LocalAppDataPath + "\\ValAPI\\maps.txt", + Url = $"/maps?language={language}" + }; + _agentsInfo = new Urls + { + Name = "Agents", + Filepath = Constants.LocalAppDataPath + "\\ValAPI\\agents.txt", + Url = $"/agents?language={language}" + }; + _skinsInfo = new Urls + { + Name = "Skins", + Filepath = Constants.LocalAppDataPath + "\\ValAPI\\skinchromas.txt", + Url = $"/weapons/skinchromas?language={language}" + }; + _cardsInfo = new Urls + { + Name = "Cards", + Filepath = Constants.LocalAppDataPath + "\\ValAPI\\cards.txt", + Url = "/playercards" + }; + _ranksInfo = new Urls + { + Name = "Ranks", + Filepath = Constants.LocalAppDataPath + "\\ValAPI\\competitivetiers.txt", + Url = $"/competitivetiers?language={language}" + }; + _versionInfo = new Urls + { + Name = "Version", + Filepath = Constants.LocalAppDataPath + "\\ValAPI\\version.txt", + Url = "/version" + }; + _gamemodeInfo = new Urls + { + Name = "Gamemode", + Filepath = Constants.LocalAppDataPath + "\\ValAPI\\gamemode.txt", + Url = "/gamemodes" + }; + _allInfo = new List {_mapsInfo, _agentsInfo, _ranksInfo, _versionInfo, _skinsInfo, _cardsInfo, _gamemodeInfo}; + return Task.CompletedTask; + } + + public static async Task UpdateFilesAsync() + { + try + { + await GetUrlsAsync().ConfigureAwait(false); + if (!Directory.Exists(Constants.LocalAppDataPath + "\\ValAPI")) + Directory.CreateDirectory(Constants.LocalAppDataPath + "\\ValAPI"); + + async Task UpdateVersion() + { + var versionRequest = new RestRequest(_versionInfo.Url); + var versionResponse = + await Client.ExecuteGetAsync(versionRequest).ConfigureAwait(false); + if (versionResponse.IsSuccessful) + { + string[] lines = + { + versionResponse.Data?.Data.RiotClientVersion, versionResponse.Data?.Data.BuildDate + }; + await File.WriteAllLinesAsync(_versionInfo.Filepath, lines).ConfigureAwait(false); + } + else + { + Constants.Log.Error("updateVersion Failed, Response:{error}", versionResponse.ErrorException); + } + } + + async Task UpdateMapsDictionary() + { + var mapsRequest = new RestRequest(_mapsInfo.Url); + var mapsResponse = await Client.ExecuteGetAsync(mapsRequest).ConfigureAwait(false); + if (mapsResponse.IsSuccessful) + { + Dictionary mapsDictionary = new(); + if (!Directory.Exists(Constants.LocalAppDataPath + "\\ValAPI\\mapsimg")) + Directory.CreateDirectory(Constants.LocalAppDataPath + "\\ValAPI\\mapsimg"); + if (mapsResponse.Data?.Data != null) + foreach (var map in mapsResponse.Data.Data) + { + mapsDictionary.TryAdd(map.MapUrl, new ValMap + { + Name = map.DisplayName, + UUID = map.Uuid + }); + var fileName = Constants.LocalAppDataPath + $"\\ValAPI\\mapsimg\\{map.Uuid}.png"; + var request = new RestRequest(map.ListViewIcon); + var response = await MediaClient.DownloadDataAsync(request).ConfigureAwait(false); + if (response != null) + await File.WriteAllBytesAsync(fileName, response).ConfigureAwait(false); + } + + await File.WriteAllTextAsync(_mapsInfo.Filepath, JsonSerializer.Serialize(mapsDictionary)).ConfigureAwait(false); + } + else + { + Constants.Log.Error("updateMapsDictionary Failed, Response:{error}", mapsResponse.ErrorException); + } + } + + async Task UpdateAgentsDictionary() + { + var agentsRequest = new RestRequest(_agentsInfo.Url); + var agentsResponse = await Client.ExecuteGetAsync(agentsRequest).ConfigureAwait(false); + if (agentsResponse.IsSuccessful) + { + Dictionary agentsDictionary = new(); + if (!Directory.Exists(Constants.LocalAppDataPath + "\\ValAPI\\agentsimg")) + Directory.CreateDirectory(Constants.LocalAppDataPath + "\\ValAPI\\agentsimg"); + if (agentsResponse.Data != null) + foreach (var agent in agentsResponse.Data.Data) + { + agentsDictionary.TryAdd(agent.Uuid, agent.DisplayName); + + var fileName = Constants.LocalAppDataPath + $"\\ValAPI\\agentsimg\\{agent.Uuid}.png"; + var request = new RestRequest(agent.DisplayIcon); + var response = await MediaClient.DownloadDataAsync(request).ConfigureAwait(false); + if (response != null) + await File.WriteAllBytesAsync(fileName, response) + .ConfigureAwait(false); + } + + await File.WriteAllTextAsync(_agentsInfo.Filepath, JsonSerializer.Serialize(agentsDictionary)).ConfigureAwait(false); + } + else + { + Constants.Log.Error("updateAgentsDictionary Failed, Response:{error}", agentsResponse.ErrorException); + } + } + + async Task UpdateSkinsDictionary() + { + var skinsRequest = new RestRequest(_skinsInfo.Url); + var skinsResponse = await Client.ExecuteGetAsync(skinsRequest).ConfigureAwait(false); + if (skinsResponse.IsSuccessful) + { + Dictionary skinsDictionary = new(); + if (skinsResponse.Data != null) + foreach (var skin in skinsResponse.Data.Data) + skinsDictionary.TryAdd(skin.Uuid, new ValSkin {Name = skin.DisplayName, Image = skin.FullRender}); + await File.WriteAllTextAsync(_skinsInfo.Filepath, JsonSerializer.Serialize(skinsDictionary)).ConfigureAwait(false); + } + else + { + Constants.Log.Error("updateSkinsDictionary Failed, Response:{error}", skinsResponse.ErrorException); + } + } + + async Task UpdateCardsDictionary() + { + var cardsRequest = new RestRequest(_cardsInfo.Url); + var cardsResponse = await Client.ExecuteGetAsync(cardsRequest).ConfigureAwait(false); + if (cardsResponse.IsSuccessful) + { + Dictionary cardsDictionary = new(); + if (cardsResponse.Data != null) + foreach (var card in cardsResponse.Data.Data) + cardsDictionary.TryAdd(card.Uuid, card.DisplayIcon); + await File.WriteAllTextAsync(_cardsInfo.Filepath, JsonSerializer.Serialize(cardsDictionary)).ConfigureAwait(false); + } + else + { + Constants.Log.Error("updateCardsDictionary Failed, Response:{error}", cardsResponse.ErrorException); + } + } + + async Task UpdateRanksDictionary() + { + var ranksRequest = new RestRequest(_ranksInfo.Url); + var ranksResponse = + await Client.ExecuteGetAsync(ranksRequest).ConfigureAwait(false); + if (ranksResponse.IsSuccessful) + { + Dictionary ranksDictionary = new(); + if (!Directory.Exists(Constants.LocalAppDataPath + "\\ValAPI\\ranksimg")) + Directory.CreateDirectory(Constants.LocalAppDataPath + "\\ValAPI\\ranksimg"); + if (ranksResponse.Data != null) + foreach (var rank in ranksResponse.Data.Data.Last().Tiers) + { + var tier = rank.TierTier; + ranksDictionary.TryAdd(tier, rank.TierName); + + switch (tier) + { + case 1 or 2: + continue; + case 0: + { + // File.Copy(Directory.GetCurrentDirectory() + "\\Assets\\0.png", + // Constants.LocalAppDataPath + "\\ValAPI\\ranksimg\\0.png", true); + + const string imagePath = "pack://application:,,,/Assets/0.png"; + var imageInfo = Application.GetResourceStream(new Uri(imagePath)); + using var ms = new MemoryStream(); + if (imageInfo != null) + { + await imageInfo.Stream.CopyToAsync(ms); + var imageBytes = ms.ToArray(); + await File.WriteAllBytesAsync(Constants.LocalAppDataPath + "\\ValAPI\\ranksimg\\0.png", imageBytes); + } + + continue; + } + } + + var fileName = Constants.LocalAppDataPath + $"\\ValAPI\\ranksimg\\{tier}.png"; + + var request = new RestRequest(rank.LargeIcon); + var response = await MediaClient.DownloadDataAsync(request).ConfigureAwait(false); + + // if (response.IsCompletedSuccessfully) + if (response != null) + await File.WriteAllBytesAsync(fileName, response) + .ConfigureAwait(false); + } + + await File.WriteAllTextAsync(_ranksInfo.Filepath, JsonSerializer.Serialize(ranksDictionary)).ConfigureAwait(false); + } + else + { + Constants.Log.Error("updateRanksDictionary Failed, Response:{error}", ranksResponse.ErrorException); + } + } + + async Task UpdateGamemodeDictionary() + { + var gameModeRequest = new RestRequest(_gamemodeInfo.Url); + var gameModeResponse = await Client.ExecuteGetAsync(gameModeRequest).ConfigureAwait(false); + if (gameModeResponse.IsSuccessful) + { + Dictionary gamemodeDictionary = new(); + if (!Directory.Exists(Constants.LocalAppDataPath + "\\ValAPI\\gamemodeimg")) + Directory.CreateDirectory(Constants.LocalAppDataPath + "\\ValAPI\\gamemodeimg"); + if (gameModeResponse.Data != null) + foreach (var gamemode in gameModeResponse.Data.Data) + { + if (gamemode.DisplayIcon == null) continue; + gamemodeDictionary.TryAdd(gamemode.Uuid, gamemode.DisplayName); + + var fileName = Constants.LocalAppDataPath + $"\\ValAPI\\gamemodeimg\\{gamemode.Uuid}.png"; + var request = new RestRequest(gamemode.DisplayIcon); + var response = await MediaClient.DownloadDataAsync(request).ConfigureAwait(false); + if (response != null) + await File.WriteAllBytesAsync(fileName, response) + .ConfigureAwait(false); + } + + await File.WriteAllTextAsync(_gamemodeInfo.Filepath, JsonSerializer.Serialize(gamemodeDictionary)).ConfigureAwait(false); + } + else + { + Constants.Log.Error("updateGamemodeDictionary Failed, Response:{error}", gameModeResponse.ErrorException); + } + } + + await Task.WhenAll(UpdateVersion(), UpdateRanksDictionary(), UpdateAgentsDictionary(), UpdateMapsDictionary(), UpdateSkinsDictionary(), UpdateCardsDictionary(), UpdateGamemodeDictionary()).ConfigureAwait(false); + } + catch (Exception e) + { + Constants.Log.Error("UpdateFilesAsync Failed, Response:{error}", e); + } + } + + public static async Task CheckAndUpdateJsonAsync() + { + try + { + await GetUrlsAsync().ConfigureAwait(false); + + if (await GetValApiVersionAsync().ConfigureAwait(false) != + await GetLocalValApiVersionAsync().ConfigureAwait(false)) + { + await UpdateFilesAsync().ConfigureAwait(false); + return; + } + + if (_allInfo.Any(url => !File.Exists(url.Filepath))) await UpdateFilesAsync().ConfigureAwait(false); + } + catch (Exception) + { + // ignored + } + } +} \ No newline at end of file diff --git a/WAIUA/IViewFactory.cs b/WAIUA/IViewFactory.cs new file mode 100644 index 00000000..a39ca88b --- /dev/null +++ b/WAIUA/IViewFactory.cs @@ -0,0 +1,8 @@ +using System.Windows; + +namespace WAIUA; + +public interface IViewFactory +{ + FrameworkElement? ResolveView(object viewModel); +} \ No newline at end of file diff --git a/WAIUA/MainWindow.xaml b/WAIUA/MainWindow.xaml index e1f53f87..aaee161b 100644 --- a/WAIUA/MainWindow.xaml +++ b/WAIUA/MainWindow.xaml @@ -2,32 +2,16 @@ x:Class="WAIUA.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" - xmlns:commands="clr-namespace:WAIUA.Commands" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" - xmlns:viewmodels="clr-namespace:WAIUA.ViewModels" - xmlns:views="clr-namespace:WAIUA.Views" - Title="WAIUA" - Width="{commands:SettingBinding Width}" - Height="{commands:SettingBinding Height}" + xmlns:waiua="clr-namespace:WAIUA" + xmlns:viewModels="clr-namespace:WAIUA.ViewModels" + Title="Who Am I Up Against? (WAIUA)" d:DesignHeight="{Binding Source={x:Static SystemParameters.WorkArea}, Path=Height}" d:DesignWidth="{Binding Source={x:Static SystemParameters.WorkArea}, Path=Width}" + d:DataContext="{d:DesignInstance Type=viewModels:MainViewModel}" Background="#2E3349" - Left="{commands:SettingBinding Left}" - Top="{commands:SettingBinding Top}" - WindowState="{commands:SettingBinding WindowState}" + UseLayoutRounding="True" mc:Ignorable="d"> - - - - - - - - - - - - - + \ No newline at end of file diff --git a/WAIUA/MainWindow.xaml.cs b/WAIUA/MainWindow.xaml.cs index cea95c91..2a5698d1 100644 --- a/WAIUA/MainWindow.xaml.cs +++ b/WAIUA/MainWindow.xaml.cs @@ -1,12 +1,15 @@ using System.Windows; +using Microsoft.Toolkit.Mvvm.DependencyInjection; +using WAIUA.ViewModels; -namespace WAIUA +namespace WAIUA; + +public partial class MainWindow : Window { - public partial class MainWindow : Window - { - public MainWindow() - { - InitializeComponent(); - } - } + public MainWindow() + { + InitializeComponent(); + DataContext = Ioc.Default.GetRequiredService(); + ((App) Application.Current).WindowPlace.Register(this); + } } \ No newline at end of file diff --git a/WAIUA/Objects/CustomObjects.cs b/WAIUA/Objects/CustomObjects.cs new file mode 100644 index 00000000..818eb3fc --- /dev/null +++ b/WAIUA/Objects/CustomObjects.cs @@ -0,0 +1,119 @@ +using System; +using System.Windows; +using Microsoft.Toolkit.Mvvm.ComponentModel; + +namespace WAIUA.Objects; + +[INotifyPropertyChanged] +public partial class IgnData +{ + [ObservableProperty] private Visibility _trackerDisabled; + [ObservableProperty] private Visibility _trackerEnabled; + [ObservableProperty] private Uri _trackerUri; + [ObservableProperty] private string _username; +} + +[INotifyPropertyChanged] +public partial class IdentityData +{ + [ObservableProperty] private Uri _image; + [ObservableProperty] private string _name; +} + +[INotifyPropertyChanged] +public partial class PlayerUIData +{ + [ObservableProperty] private string _backgroundColour; + [ObservableProperty] private string _partyColour; + [ObservableProperty] private Guid _partyUuid; + [ObservableProperty] private Guid _Puuid; +} + +[INotifyPropertyChanged] +public partial class SeasonData +{ + [ObservableProperty] private Guid _currentSeason; + [ObservableProperty] private Guid _previouspreviouspreviousSeason; + [ObservableProperty] private Guid _previouspreviousSeason; + [ObservableProperty] private Guid _previousSeason; +} + +[INotifyPropertyChanged] +public partial class SkinData +{ + [ObservableProperty] private Uri _phantomImage; + [ObservableProperty] private string _phantomName; + [ObservableProperty] private Uri _vandalImage; + [ObservableProperty] private string _vandalName; +} + +[INotifyPropertyChanged] +public partial class RankData +{ + [ObservableProperty] private int _maxRr = 100; + [ObservableProperty] private Uri _previouspreviouspreviousrankImage; + [ObservableProperty] private string _previouspreviouspreviousrankName; + [ObservableProperty] private Uri _previouspreviousrankImage; + [ObservableProperty] private string _previouspreviousrankName; + [ObservableProperty] private Uri _previousrankImage; + [ObservableProperty] private string _previousrankName; + [ObservableProperty] private Uri _rankImage; + [ObservableProperty] private string _rankName; +} + +[INotifyPropertyChanged] +public partial class MatchHistoryData +{ + [ObservableProperty] private int _previousGame; + [ObservableProperty] private string _previousGameColour; + [ObservableProperty] private int _previouspreviousGame; + [ObservableProperty] private string _previouspreviousGameColour; + [ObservableProperty] private int _previouspreviouspreviousGame; + [ObservableProperty] private string _previouspreviouspreviousGameColour; + [ObservableProperty] private int _rankProgress; +} + +public class ValMap +{ + public string Name { get; set; } + public Guid UUID { get; set; } +} + +public class ValSkin +{ + public string Name { get; set; } + public Uri Image { get; set; } +} + +[INotifyPropertyChanged] +public partial class MatchDetails +{ + [ObservableProperty] private string _gameMode; + [ObservableProperty] private Uri _gameModeImage; + [ObservableProperty] private string _map; + [ObservableProperty] private Uri _mapImage; + [ObservableProperty] private string _server; +} + +[INotifyPropertyChanged] +public partial class Player +{ + [ObservableProperty] private string _accountLevel; + [ObservableProperty] private Visibility _active = Visibility.Collapsed; + [ObservableProperty] private IdentityData _identityData; + [ObservableProperty] private IgnData _ignData; + [ObservableProperty] private MatchHistoryData _matchHistoryData; + [ObservableProperty] private PlayerUIData _playerUiData; + [ObservableProperty] private RankData _rankData; + [ObservableProperty] private SkinData _skinData; + [ObservableProperty] private string _teamId; +} + +[INotifyPropertyChanged] +public partial class LoadingOverlay +{ + [ObservableProperty] private string _content; + [ObservableProperty] private string _header; + [ObservableProperty] private bool _isBusy; + [ObservableProperty] private int _progress; +} \ No newline at end of file diff --git a/WAIUA/Objects/RiotAPIObjects.cs b/WAIUA/Objects/RiotAPIObjects.cs new file mode 100644 index 00000000..7db58b96 --- /dev/null +++ b/WAIUA/Objects/RiotAPIObjects.cs @@ -0,0 +1,971 @@ +using System; +using System.Collections.Generic; +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace WAIUA.Objects; + +public class XpResponse +{ + [JsonPropertyName("Version")] public long Version { get; set; } + + [JsonPropertyName("Subject")] public Guid Subject { get; set; } + + [JsonPropertyName("Progress")] public Progress Progress { get; set; } + + [JsonPropertyName("History")] public History[] History { get; set; } + + [JsonPropertyName("LastTimeGrantedFirstWin")] + public string LastTimeGrantedFirstWin { get; set; } + + [JsonPropertyName("NextTimeFirstWinAvailable")] + public string NextTimeFirstWinAvailable { get; set; } +} + +public class History +{ + [JsonPropertyName("ID")] public Guid Id { get; set; } + + [JsonPropertyName("MatchStart")] public string MatchStart { get; set; } + + [JsonPropertyName("StartProgress")] public Progress StartProgress { get; set; } + + [JsonPropertyName("EndProgress")] public Progress EndProgress { get; set; } + + [JsonPropertyName("XPDelta")] public long XpDelta { get; set; } + + [JsonPropertyName("XPSources")] public XpSource[] XpSources { get; set; } + + [JsonPropertyName("XPMultipliers")] public object[] XpMultipliers { get; set; } +} + +public class Progress +{ + [JsonPropertyName("Level")] public long Level { get; set; } + + [JsonPropertyName("XP")] public long Xp { get; set; } +} + +public class XpSource +{ + [JsonPropertyName("ID")] public string Id { get; set; } + + [JsonPropertyName("Amount")] public long Amount { get; set; } +} + +public class EntitlementsResponse +{ + [JsonPropertyName("accessToken")] public string AccessToken { get; set; } + + [JsonPropertyName("entitlements")] public object[] Entitlements { get; set; } + + [JsonPropertyName("issuer")] public Uri Issuer { get; set; } + + [JsonPropertyName("subject")] public Guid Subject { get; set; } + + [JsonPropertyName("token")] public string Token { get; set; } +} + +public class ExternalSessionsResponse +{ + // [JsonExtensionData] public Dictionary RandString { get; set; } + [JsonExtensionData] public Dictionary? ExtensionData { get; set; } +} + +public class ExternalSessions +{ + [JsonPropertyName("exitCode")] public int ExitCode { get; set; } + + [JsonPropertyName("exitReason")] public object ExitReason { get; set; } + + [JsonPropertyName("isInternal")] public bool IsInternal { get; set; } + + [JsonPropertyName("launchConfiguration")] + public LaunchConfiguration LaunchConfiguration { get; set; } + + [JsonPropertyName("patchlineFullName")] + public string PatchlineFullName { get; set; } + + [JsonPropertyName("patchlineId")] public string PatchlineId { get; set; } + + [JsonPropertyName("phase")] public string Phase { get; set; } + + [JsonPropertyName("productId")] public string ProductId { get; set; } + + [JsonPropertyName("version")] public string Version { get; set; } +} + +public class LaunchConfiguration +{ + [JsonPropertyName("arguments")] public string[] Arguments { get; set; } + + [JsonPropertyName("executable")] public string Executable { get; set; } + + [JsonPropertyName("locale")] public string Locale { get; set; } + + [JsonPropertyName("voiceLocale")] public object VoiceLocale { get; set; } + + [JsonPropertyName("workingDirectory")] public string WorkingDirectory { get; set; } +} + +public class MatchIDResponse +{ + [JsonPropertyName("Subject")] public Guid Subject { get; set; } + + [JsonPropertyName("MatchID")] public Guid MatchId { get; set; } + + [JsonPropertyName("Version")] public long Version { get; set; } +} + +public class LiveMatchResponse +{ + [JsonPropertyName("MatchID")] public Guid MatchId { get; set; } + + [JsonPropertyName("Version")] public long Version { get; set; } + + [JsonPropertyName("State")] public string State { get; set; } + + [JsonPropertyName("MapID")] public string MapId { get; set; } + + [JsonPropertyName("ModeID")] public string ModeId { get; set; } + + [JsonPropertyName("ProvisioningFlow")] public string ProvisioningFlow { get; set; } + + [JsonPropertyName("GamePodID")] public string GamePodId { get; set; } + + [JsonPropertyName("AllMUCName")] public string AllMucName { get; set; } + + [JsonPropertyName("TeamMUCName")] public string TeamMucName { get; set; } + + [JsonPropertyName("TeamVoiceID")] public string TeamVoiceId { get; set; } + + [JsonPropertyName("IsReconnectable")] public bool IsReconnectable { get; set; } + + [JsonPropertyName("ConnectionDetails")] + public ConnectionDetails ConnectionDetails { get; set; } + + [JsonPropertyName("PostGameDetails")] public object PostGameDetails { get; set; } + + [JsonPropertyName("Players")] public RiotLivePlayer[] Players { get; set; } + + [JsonPropertyName("MatchmakingData")] public object MatchmakingData { get; set; } +} + +public class PreMatchResponse +{ + [JsonPropertyName("ID")] public Guid Id { get; set; } + + [JsonPropertyName("Version")] public long Version { get; set; } + + [JsonPropertyName("Teams")] public PreTeam[] Teams { get; set; } + + [JsonPropertyName("AllyTeam")] public PreTeam AllyTeam { get; set; } + + [JsonPropertyName("EnemyTeam")] public object EnemyTeam { get; set; } + + [JsonPropertyName("ObserverSubjects")] public object[] ObserverSubjects { get; set; } + + [JsonPropertyName("MatchCoaches")] public object[] MatchCoaches { get; set; } + + [JsonPropertyName("EnemyTeamSize")] public long EnemyTeamSize { get; set; } + + [JsonPropertyName("EnemyTeamLockCount")] + public long EnemyTeamLockCount { get; set; } + + [JsonPropertyName("PregameState")] public string PregameState { get; set; } + + [JsonPropertyName("LastUpdated")] public string LastUpdated { get; set; } + + [JsonPropertyName("MapID")] public string MapId { get; set; } + + [JsonPropertyName("MapSelectPool")] public object[] MapSelectPool { get; set; } + + [JsonPropertyName("BannedMapIDs")] public object[] BannedMapIDs { get; set; } + + [JsonPropertyName("CastedVotes")] public object CastedVotes { get; set; } + + [JsonPropertyName("MapSelectSteps")] public object[] MapSelectSteps { get; set; } + + [JsonPropertyName("MapSelectStep")] public long MapSelectStep { get; set; } + + [JsonPropertyName("Team1")] public string Team1 { get; set; } + + [JsonPropertyName("GamePodID")] public string GamePodId { get; set; } + + [JsonPropertyName("Mode")] public string Mode { get; set; } + + [JsonPropertyName("VoiceSessionID")] public string VoiceSessionId { get; set; } + + [JsonPropertyName("MUCName")] public string MucName { get; set; } + + [JsonPropertyName("QueueID")] public string QueueId { get; set; } + + [JsonPropertyName("ProvisioningFlowID")] + public string ProvisioningFlowId { get; set; } + + [JsonPropertyName("IsRanked")] public bool IsRanked { get; set; } + + [JsonPropertyName("PhaseTimeRemainingNS")] + public long PhaseTimeRemainingNs { get; set; } + + [JsonPropertyName("StepTimeRemainingNS")] + public long StepTimeRemainingNs { get; set; } + + [JsonPropertyName("altModesFlagADA")] public bool AltModesFlagAda { get; set; } + + [JsonPropertyName("TournamentMetadata")] + public object TournamentMetadata { get; set; } +} + +public class PreTeam +{ + [JsonPropertyName("TeamID")] public string TeamId { get; set; } + + [JsonPropertyName("Players")] public RiotPrePlayer[] Players { get; set; } +} + +public class ConnectionDetails +{ + [JsonPropertyName("GameServerHosts")] public string[] GameServerHosts { get; set; } + + [JsonPropertyName("GameServerHost")] public string GameServerHost { get; set; } + + [JsonPropertyName("GameServerPort")] public int GameServerPort { get; set; } + + [JsonPropertyName("GameServerObfuscatedIP")] + public long GameServerObfuscatedIp { get; set; } + + [JsonPropertyName("GameClientHash")] public long GameClientHash { get; set; } + + [JsonPropertyName("PlayerKey")] public string PlayerKey { get; set; } +} + +public class RiotLivePlayer +{ + [JsonPropertyName("Subject")] public Guid Subject { get; set; } + + [JsonPropertyName("TeamID")] public string TeamId { get; set; } + + [JsonPropertyName("CharacterID")] public Guid CharacterId { get; set; } + + [JsonPropertyName("PlayerIdentity")] public PlayerIdentity PlayerIdentity { get; set; } + + [JsonPropertyName("SeasonalBadgeInfo")] + public SeasonalBadgeInfo SeasonalBadgeInfo { get; set; } + + [JsonPropertyName("IsCoach")] public bool IsCoach { get; set; } +} + +public class RiotPrePlayer +{ + [JsonPropertyName("Subject")] public Guid Subject { get; set; } + + [JsonPropertyName("CharacterID")] + [JsonIgnore] + public Guid CharacterId { get; set; } + + [JsonPropertyName("CharacterSelectionState")] + public string CharacterSelectionState { get; set; } + + [JsonPropertyName("PregamePlayerState")] + public string PregamePlayerState { get; set; } + + [JsonPropertyName("CompetitiveTier")] public long CompetitiveTier { get; set; } + [JsonPropertyName("PlayerIdentity")] public PlayerIdentity PlayerIdentity { get; set; } + + [JsonPropertyName("SeasonalBadgeInfo")] + public SeasonalBadgeInfo SeasonalBadgeInfo { get; set; } + + [JsonPropertyName("IsCaptain")] public bool IsCaptain { get; set; } +} + +public class PlayerIdentity +{ + [JsonPropertyName("Subject")] public Guid Subject { get; set; } + + [JsonPropertyName("PlayerCardID")] public Guid PlayerCardId { get; set; } + + [JsonPropertyName("PlayerTitleID")] public Guid PlayerTitleId { get; set; } + + [JsonPropertyName("AccountLevel")] public int AccountLevel { get; set; } + + [JsonPropertyName("PreferredLevelBorderID")] + public Guid PreferredLevelBorderId { get; set; } + + [JsonPropertyName("Incognito")] public bool Incognito { get; set; } + + [JsonPropertyName("HideAccountLevel")] public bool HideAccountLevel { get; set; } +} + +public class SeasonalBadgeInfo +{ + [JsonPropertyName("SeasonID")] public string SeasonId { get; set; } + + [JsonPropertyName("NumberOfWins")] public int NumberOfWins { get; set; } + + [JsonPropertyName("WinsByTier")] public object WinsByTier { get; set; } + + [JsonPropertyName("Rank")] public int Rank { get; set; } + + [JsonPropertyName("LeaderboardRank")] public int LeaderboardRank { get; set; } +} + +public class NameServiceResponse +{ + [JsonPropertyName("DisplayName")] public string DisplayName { get; set; } + + [JsonPropertyName("Subject")] public Guid Subject { get; set; } + + [JsonPropertyName("GameName")] public string GameName { get; set; } + + [JsonPropertyName("TagLine")] public string TagLine { get; set; } +} + +public class MatchLoadoutsResponse +{ + [JsonPropertyName("Loadouts")] public LoadoutElement[] Loadouts { get; set; } +} + +public class PreMatchLoadoutsResponse +{ + [JsonPropertyName("Loadouts")] public LoadoutLoadout[] Loadouts { get; set; } + + [JsonPropertyName("LoadoutsValid")] + [JsonIgnore] + public bool LoadoutsValid { get; set; } +} + +public class LoadoutElement +{ + [JsonPropertyName("CharacterID")] + [JsonIgnore] + public Guid CharacterId { get; set; } + + [JsonPropertyName("Loadout")] public LoadoutLoadout Loadout { get; set; } +} + +public class LoadoutLoadout +{ + [JsonPropertyName("Sprays")] public Sprays Sprays { get; set; } + + [JsonPropertyName("Items")] public Dictionary Items { get; set; } +} + +public class ItemValue +{ + [JsonPropertyName("ID")] public Guid Id { get; set; } + + [JsonPropertyName("TypeID")] public Guid TypeId { get; set; } + + [JsonPropertyName("Sockets")] public Dictionary Sockets { get; set; } +} + +public class Socket +{ + [JsonPropertyName("ID")] public Guid Id { get; set; } + + [JsonPropertyName("Item")] public SocketItem Item { get; set; } +} + +public class SocketItem +{ + [JsonPropertyName("ID")] public Guid Id { get; set; } + + [JsonPropertyName("TypeID")] public Guid TypeId { get; set; } +} + +public class Sprays +{ + [JsonPropertyName("SpraySelections")] public SpraySelection[] SpraySelections { get; set; } +} + +public class SpraySelection +{ + [JsonPropertyName("SocketID")] public Guid SocketId { get; set; } + + [JsonPropertyName("SprayID")] public Guid SprayId { get; set; } + + [JsonPropertyName("LevelID")] public Guid LevelId { get; set; } +} + +public class CompetitiveUpdatesResponse +{ + [JsonPropertyName("Version")] public long Version { get; set; } + + [JsonPropertyName("Subject")] public Guid Subject { get; set; } + + [JsonPropertyName("Matches")] public CompetitiveUpdatesMatch[] Matches { get; set; } +} + +public class CompetitiveUpdatesMatch +{ + [JsonPropertyName("MatchID")] public Guid MatchId { get; set; } + + [JsonPropertyName("MapID")] public string MapId { get; set; } + + [JsonPropertyName("SeasonID")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public Guid? SeasonId { get; set; } + + [JsonPropertyName("MatchStartTime")] public long MatchStartTime { get; set; } + + [JsonPropertyName("TierAfterUpdate")] public int TierAfterUpdate { get; set; } + + [JsonPropertyName("TierBeforeUpdate")] public int TierBeforeUpdate { get; set; } + + [JsonPropertyName("RankedRatingAfterUpdate")] + public int RankedRatingAfterUpdate { get; set; } + + [JsonPropertyName("RankedRatingBeforeUpdate")] + public int RankedRatingBeforeUpdate { get; set; } + + [JsonPropertyName("RankedRatingEarned")] + public int RankedRatingEarned { get; set; } + + [JsonPropertyName("RankedRatingPerformanceBonus")] + public int RankedRatingPerformanceBonus { get; set; } + + [JsonPropertyName("CompetitiveMovement")] + public string CompetitiveMovement { get; set; } + + [JsonPropertyName("AFKPenalty")] public int AfkPenalty { get; set; } +} + +public class MmrResponse +{ + [JsonPropertyName("Version")] public long Version { get; set; } + + [JsonPropertyName("Subject")] public Guid Subject { get; set; } + + [JsonPropertyName("NewPlayerExperienceFinished")] + public bool NewPlayerExperienceFinished { get; set; } + + [JsonPropertyName("QueueSkills")] public QueueSkills QueueSkills { get; set; } + + [JsonPropertyName("LatestCompetitiveUpdate")] + public LatestCompetitiveUpdate LatestCompetitiveUpdate { get; set; } + + [JsonPropertyName("IsLeaderboardAnonymized")] + public bool IsLeaderboardAnonymized { get; set; } + + [JsonPropertyName("IsActRankBadgeHidden")] + public bool IsActRankBadgeHidden { get; set; } +} + +public class LatestCompetitiveUpdate +{ + [JsonPropertyName("MatchID")] public Guid MatchId { get; set; } + + [JsonPropertyName("MapID")] public string MapId { get; set; } + + [JsonPropertyName("SeasonID")] public Guid SeasonId { get; set; } + + [JsonPropertyName("MatchStartTime")] public long MatchStartTime { get; set; } + + [JsonPropertyName("TierAfterUpdate")] public int TierAfterUpdate { get; set; } + + [JsonPropertyName("TierBeforeUpdate")] public int TierBeforeUpdate { get; set; } + + [JsonPropertyName("RankedRatingAfterUpdate")] + public int RankedRatingAfterUpdate { get; set; } + + [JsonPropertyName("RankedRatingBeforeUpdate")] + public int RankedRatingBeforeUpdate { get; set; } + + [JsonPropertyName("RankedRatingEarned")] + public int RankedRatingEarned { get; set; } + + [JsonPropertyName("RankedRatingPerformanceBonus")] + public int RankedRatingPerformanceBonus { get; set; } + + [JsonPropertyName("CompetitiveMovement")] + public string CompetitiveMovement { get; set; } + + [JsonPropertyName("AFKPenalty")] public int AfkPenalty { get; set; } +} + +public class QueueSkills +{ + [JsonPropertyName("competitive")] public Competitive Competitive { get; set; } + + [JsonPropertyName("custom")] public Custom Custom { get; set; } + + [JsonPropertyName("deathmatch")] public Custom Deathmatch { get; set; } + + [JsonPropertyName("ggteam")] public Custom Ggteam { get; set; } + + [JsonPropertyName("newmap")] public Custom Newmap { get; set; } + + [JsonPropertyName("onefa")] public Custom Onefa { get; set; } + + [JsonPropertyName("seeding")] public Seeding Seeding { get; set; } + + [JsonPropertyName("snowball")] public Custom Snowball { get; set; } + + [JsonPropertyName("spikerush")] public Custom Spikerush { get; set; } + + [JsonPropertyName("unrated")] public Custom Unrated { get; set; } +} + +public class Competitive +{ + [JsonPropertyName("TotalGamesNeededForRating")] + public int TotalGamesNeededForRating { get; set; } + + [JsonPropertyName("TotalGamesNeededForLeaderboard")] + public int TotalGamesNeededForLeaderboard { get; set; } + + [JsonPropertyName("CurrentSeasonGamesNeededForRating")] + public int CurrentSeasonGamesNeededForRating { get; set; } + + [JsonPropertyName("SeasonalInfoBySeasonID")] + public SeasonalInfoBySeasonId SeasonalInfoBySeasonId { get; set; } +} + +public class SeasonalInfoBySeasonId +{ + [JsonExtensionData] public Dictionary Act { get; set; } +} + +public class ActInfo +{ + [JsonPropertyName("SeasonID")] public Guid SeasonId { get; set; } + + [JsonPropertyName("NumberOfWins")] public int NumberOfWins { get; set; } + + [JsonPropertyName("NumberOfWinsWithPlacements")] + public int NumberOfWinsWithPlacements { get; set; } + + [JsonPropertyName("NumberOfGames")] public int NumberOfGames { get; set; } + + [JsonPropertyName("Rank")] public int Rank { get; set; } + + [JsonPropertyName("CapstoneWins")] public int CapstoneWins { get; set; } + + [JsonPropertyName("LeaderboardRank")] public int LeaderboardRank { get; set; } + + [JsonPropertyName("CompetitiveTier")] public int CompetitiveTier { get; set; } + + [JsonPropertyName("RankedRating")] public int RankedRating { get; set; } + + [JsonPropertyName("WinsByTier")] public Dictionary WinsByTier { get; set; } + + [JsonPropertyName("GamesNeededForRating")] + public int GamesNeededForRating { get; set; } + + [JsonPropertyName("TotalWinsNeededForRank")] + public int TotalWinsNeededForRank { get; set; } +} + +public class Custom +{ + [JsonPropertyName("TotalGamesNeededForRating")] + public int TotalGamesNeededForRating { get; set; } + + [JsonPropertyName("TotalGamesNeededForLeaderboard")] + public int TotalGamesNeededForLeaderboard { get; set; } + + [JsonPropertyName("CurrentSeasonGamesNeededForRating")] + public int CurrentSeasonGamesNeededForRating { get; set; } + + [JsonPropertyName("SeasonalInfoBySeasonID")] + public SeasonalInfoBySeasonId SeasonalInfoBySeasonId { get; set; } +} + +public class Seeding +{ + [JsonPropertyName("TotalGamesNeededForRating")] + public int TotalGamesNeededForRating { get; set; } + + [JsonPropertyName("TotalGamesNeededForLeaderboard")] + public int TotalGamesNeededForLeaderboard { get; set; } + + [JsonPropertyName("CurrentSeasonGamesNeededForRating")] + public int CurrentSeasonGamesNeededForRating { get; set; } + + [JsonPropertyName("SeasonalInfoBySeasonID")] + public SeasonalInfoBySeasonId SeasonalInfoBySeasonId { get; set; } +} + +public class LeaderboardsResponse +{ + [JsonPropertyName("Deployment")] public string Deployment { get; set; } + + [JsonPropertyName("QueueID")] public string QueueId { get; set; } + + [JsonPropertyName("SeasonID")] public Guid SeasonId { get; set; } + + [JsonPropertyName("Players")] public object[] Players { get; set; } + + [JsonPropertyName("totalPlayers")] public int TotalPlayers { get; set; } + + [JsonPropertyName("immortalStartingPage")] + public int ImmortalStartingPage { get; set; } + + [JsonPropertyName("immortalStartingIndex")] + public int ImmortalStartingIndex { get; set; } + + [JsonPropertyName("topTierRRThreshold")] + public int TopTierRrThreshold { get; set; } + + [JsonPropertyName("tierDetails")] public Dictionary TierDetails { get; set; } + + [JsonPropertyName("startIndex")] public int StartIndex { get; set; } + + [JsonPropertyName("query")] public string Query { get; set; } +} + +public class TierDetail +{ + [JsonPropertyName("rankedRatingThreshold")] + public int RankedRatingThreshold { get; set; } + + [JsonPropertyName("startingPage")] public int StartingPage { get; set; } + + [JsonPropertyName("startingIndex")] public int StartingIndex { get; set; } +} + +public class ContentResponse +{ + [JsonPropertyName("DisabledIDs")] public object[] DisabledIDs { get; set; } + + [JsonPropertyName("Seasons")] public Event[] Seasons { get; set; } + + [JsonPropertyName("Events")] public Event[] Events { get; set; } +} + +public class Event +{ + [JsonPropertyName("ID")] public Guid Id { get; set; } + + [JsonPropertyName("Name")] public string Name { get; set; } + + [JsonPropertyName("StartTime")] public string StartTime { get; set; } + + [JsonPropertyName("EndTime")] public string EndTime { get; set; } + + [JsonPropertyName("IsActive")] public bool IsActive { get; set; } + + [JsonPropertyName("DevelopmentOnly")] public bool DevelopmentOnly { get; set; } + + [JsonPropertyName("Type")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public string? Type { get; set; } +} + +public class PresencesResponse +{ + [JsonPropertyName("presences")] public Presence[] Presences { get; set; } +} + +public class Presence +{ + [JsonPropertyName("actor")] public string Actor { get; set; } + + [JsonPropertyName("basic")] public string Basic { get; set; } + + [JsonPropertyName("details")] public string Details { get; set; } + + [JsonPropertyName("game_name")] public string GameName { get; set; } + + [JsonPropertyName("game_tag")] public string GameTag { get; set; } + + [JsonPropertyName("location")] public string Location { get; set; } + + [JsonPropertyName("msg")] public string Msg { get; set; } + + [JsonPropertyName("name")] public string Name { get; set; } + + [JsonPropertyName("patchline")] public string Patchline { get; set; } + + [JsonPropertyName("pid")] public string Pid { get; set; } + + [JsonPropertyName("platform")] public string Platform { get; set; } + + [JsonPropertyName("private")] public string Private { get; set; } + + [JsonPropertyName("privateJwt")] public object PrivateJwt { get; set; } + + [JsonPropertyName("product")] public string Product { get; set; } + + [JsonPropertyName("puuid")] public Guid Puuid { get; set; } + + [JsonPropertyName("region")] public string Region { get; set; } + + [JsonPropertyName("resource")] public string Resource { get; set; } + + [JsonPropertyName("state")] public string State { get; set; } + + [JsonPropertyName("summary")] public string Summary { get; set; } + + [JsonPropertyName("time")] + [JsonIgnore] + public long Time { get; set; } +} + +public class PresencesPrivate +{ + [JsonPropertyName("isValid")] public bool IsValid { get; set; } + + [JsonPropertyName("sessionLoopState")] public string SessionLoopState { get; set; } + + [JsonPropertyName("partyOwnerSessionLoopState")] + public string PartyOwnerSessionLoopState { get; set; } + + [JsonPropertyName("customGameName")] public string CustomGameName { get; set; } + + [JsonPropertyName("customGameTeam")] public string CustomGameTeam { get; set; } + + [JsonPropertyName("partyOwnerMatchMap")] + public string PartyOwnerMatchMap { get; set; } + + [JsonPropertyName("partyOwnerMatchCurrentTeam")] + public string PartyOwnerMatchCurrentTeam { get; set; } + + [JsonPropertyName("partyOwnerMatchScoreAllyTeam")] + public int PartyOwnerMatchScoreAllyTeam { get; set; } + + [JsonPropertyName("partyOwnerMatchScoreEnemyTeam")] + public int PartyOwnerMatchScoreEnemyTeam { get; set; } + + [JsonPropertyName("partyOwnerProvisioningFlow")] + public string PartyOwnerProvisioningFlow { get; set; } + + [JsonPropertyName("provisioningFlow")] public string ProvisioningFlow { get; set; } + + [JsonPropertyName("matchMap")] public string MatchMap { get; set; } + + [JsonPropertyName("partyId")] public Guid PartyId { get; set; } + + [JsonPropertyName("isPartyOwner")] public bool IsPartyOwner { get; set; } + + [JsonPropertyName("partyState")] public string PartyState { get; set; } + + [JsonPropertyName("partyAccessibility")] + public string PartyAccessibility { get; set; } + + [JsonPropertyName("maxPartySize")] public int MaxPartySize { get; set; } + + [JsonPropertyName("queueId")] public string QueueId { get; set; } + + [JsonPropertyName("partyLFM")] public bool PartyLfm { get; set; } + + [JsonPropertyName("partyClientVersion")] + public string PartyClientVersion { get; set; } + + [JsonPropertyName("partySize")] public int PartySize { get; set; } + + [JsonPropertyName("tournamentId")] public string TournamentId { get; set; } + + [JsonPropertyName("rosterId")] public string RosterId { get; set; } + + [JsonPropertyName("partyVersion")] public long PartyVersion { get; set; } + + [JsonPropertyName("queueEntryTime")] public string QueueEntryTime { get; set; } + + [JsonPropertyName("playerCardId")] public Guid PlayerCardId { get; set; } + + [JsonPropertyName("playerTitleId")] + [JsonIgnore] + public Guid PlayerTitleId { get; set; } + + [JsonPropertyName("preferredLevelBorderId")] + public string PreferredLevelBorderId { get; set; } + + [JsonPropertyName("accountLevel")] public int AccountLevel { get; set; } + + [JsonPropertyName("competitiveTier")] public int CompetitiveTier { get; set; } + + [JsonPropertyName("leaderboardPosition")] + public int LeaderboardPosition { get; set; } + + [JsonPropertyName("isIdle")] public bool IsIdle { get; set; } +} + +public class PartyIdResponse +{ + [JsonPropertyName("Subject")] public Guid Subject { get; set; } + + [JsonPropertyName("Version")] public long Version { get; set; } + + [JsonPropertyName("CurrentPartyID")] public Guid CurrentPartyId { get; set; } + + [JsonPropertyName("Invites")] public object Invites { get; set; } + + [JsonPropertyName("Requests")] public object[] Requests { get; set; } + + [JsonPropertyName("PlatformInfo")] public PlatformInfo PlatformInfo { get; set; } +} + +public class PlatformInfo +{ + [JsonPropertyName("platformType")] public string PlatformType { get; set; } + + [JsonPropertyName("platformOS")] public string PlatformOs { get; set; } + + [JsonPropertyName("platformOSVersion")] + public string PlatformOsVersion { get; set; } + + [JsonPropertyName("platformChipset")] public string PlatformChipset { get; set; } +} + +public class PartyResponse +{ + [JsonPropertyName("ID")] public Guid Id { get; set; } + + [JsonPropertyName("MUCName")] public string MucName { get; set; } + + [JsonPropertyName("VoiceRoomID")] public string VoiceRoomId { get; set; } + + [JsonPropertyName("Version")] public long Version { get; set; } + + [JsonPropertyName("ClientVersion")] public string ClientVersion { get; set; } + + [JsonPropertyName("Members")] public Member[] Members { get; set; } + + [JsonPropertyName("State")] public string State { get; set; } + + [JsonPropertyName("PreviousState")] public string PreviousState { get; set; } + + [JsonPropertyName("StateTransitionReason")] + public string StateTransitionReason { get; set; } + + [JsonPropertyName("Accessibility")] public string Accessibility { get; set; } + + [JsonPropertyName("CustomGameData")] public CustomGameData CustomGameData { get; set; } + + [JsonPropertyName("MatchmakingData")] public MatchmakingData MatchmakingData { get; set; } + + [JsonPropertyName("Invites")] public object Invites { get; set; } + + [JsonPropertyName("Requests")] public object[] Requests { get; set; } + + [JsonPropertyName("QueueEntryTime")] public string QueueEntryTime { get; set; } + + [JsonPropertyName("ErrorNotification")] + public ErrorNotification ErrorNotification { get; set; } + + [JsonPropertyName("RestrictedSeconds")] + public long RestrictedSeconds { get; set; } + + [JsonPropertyName("EligibleQueues")] public string[] EligibleQueues { get; set; } + + [JsonPropertyName("QueueIneligibilities")] + public object[] QueueIneligibilities { get; set; } + + [JsonPropertyName("CheatData")] public CheatData CheatData { get; set; } + + [JsonPropertyName("XPBonuses")] public object[] XpBonuses { get; set; } +} + +public class CheatData +{ + [JsonPropertyName("GamePodOverride")] public string GamePodOverride { get; set; } + + [JsonPropertyName("ForcePostGameProcessing")] + public bool ForcePostGameProcessing { get; set; } +} + +public class CustomGameData +{ + [JsonPropertyName("Settings")] public Settings Settings { get; set; } + + [JsonPropertyName("Membership")] public Membership Membership { get; set; } + + [JsonPropertyName("MaxPartySize")] public long MaxPartySize { get; set; } + + [JsonPropertyName("AutobalanceEnabled")] + public bool AutobalanceEnabled { get; set; } + + [JsonPropertyName("AutobalanceMinPlayers")] + public long AutobalanceMinPlayers { get; set; } +} + +public class Membership +{ + [JsonPropertyName("teamOne")] public TeamOne[] TeamOne { get; set; } + + [JsonPropertyName("teamTwo")] public object[] TeamTwo { get; set; } + + [JsonPropertyName("teamSpectate")] public object[] TeamSpectate { get; set; } + + [JsonPropertyName("teamOneCoaches")] public object[] TeamOneCoaches { get; set; } + + [JsonPropertyName("teamTwoCoaches")] public object[] TeamTwoCoaches { get; set; } +} + +public class TeamOne +{ + [JsonPropertyName("Subject")] public Guid Subject { get; set; } +} + +public class Settings +{ + [JsonPropertyName("Map")] public string Map { get; set; } + + [JsonPropertyName("Mode")] public string Mode { get; set; } + + [JsonPropertyName("UseBots")] public bool UseBots { get; set; } + + [JsonPropertyName("GamePod")] public string GamePod { get; set; } + + [JsonPropertyName("GameRules")] public GameRules GameRules { get; set; } +} + +public class GameRules +{ + [JsonPropertyName("AllowGameModifiers")] + public string AllowGameModifiers { get; set; } +} + +public class ErrorNotification +{ + [JsonPropertyName("ErrorType")] public string ErrorType { get; set; } + + [JsonPropertyName("ErroredPlayers")] public object ErroredPlayers { get; set; } +} + +public class MatchmakingData +{ + [JsonPropertyName("QueueID")] public string QueueId { get; set; } + + [JsonPropertyName("PreferredGamePods")] + public string[] PreferredGamePods { get; set; } + + [JsonPropertyName("SkillDisparityRRPenalty")] + public long SkillDisparityRrPenalty { get; set; } +} + +public class Member +{ + [JsonPropertyName("Subject")] public Guid Subject { get; set; } + + [JsonPropertyName("CompetitiveTier")] public long CompetitiveTier { get; set; } + + [JsonPropertyName("PlayerIdentity")] public PlayerIdentity PlayerIdentity { get; set; } + + [JsonPropertyName("SeasonalBadgeInfo")] + public object SeasonalBadgeInfo { get; set; } + + [JsonPropertyName("IsOwner")] public bool IsOwner { get; set; } + + [JsonPropertyName("QueueEligibleRemainingAccountLevels")] + public long QueueEligibleRemainingAccountLevels { get; set; } + + [JsonPropertyName("Pings")] public Ping[] Pings { get; set; } + + [JsonPropertyName("IsReady")] public bool IsReady { get; set; } + + [JsonPropertyName("IsModerator")] public bool IsModerator { get; set; } + + [JsonPropertyName("UseBroadcastHUD")] public bool UseBroadcastHud { get; set; } + + [JsonPropertyName("PlatformType")] public string PlatformType { get; set; } +} + +public class Ping +{ + [JsonPropertyName("Ping")] public long PingPing { get; set; } + + [JsonPropertyName("GamePodID")] public string GamePodId { get; set; } +} \ No newline at end of file diff --git a/WAIUA/Objects/ValAPIObjects.cs b/WAIUA/Objects/ValAPIObjects.cs new file mode 100644 index 00000000..2c583a96 --- /dev/null +++ b/WAIUA/Objects/ValAPIObjects.cs @@ -0,0 +1,251 @@ +using System; +using System.Collections.Generic; +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace WAIUA.Objects; + +public class Urls +{ + public string Name { get; init; } + public string Filepath { get; init; } + public string Url { get; init; } +} + +public class VapiVersionResponse +{ + [JsonPropertyName("status")] public int Status { get; set; } + + [JsonPropertyName("data")] public VapiVersion Data { get; set; } +} + +public class VapiVersion +{ + [JsonPropertyName("manifestId")] public string ManifestId { get; set; } + + [JsonPropertyName("branch")] public string Branch { get; set; } + + [JsonPropertyName("version")] public string Version { get; set; } + + [JsonPropertyName("buildVersion")] public long BuildVersion { get; set; } + + [JsonPropertyName("riotClientVersion")] + public string RiotClientVersion { get; set; } + + [JsonPropertyName("buildDate")] public string BuildDate { get; set; } +} + +public class ValApiMapsResponse +{ + [JsonPropertyName("status")] public int Status { get; set; } + + [JsonPropertyName("data")] public VapiMaps[] Data { get; set; } +} + +public class VapiMaps +{ + [JsonPropertyName("uuid")] public Guid Uuid { get; set; } + + [JsonPropertyName("displayName")] public string DisplayName { get; set; } + + [JsonPropertyName("coordinates")] public string Coordinates { get; set; } + + [JsonPropertyName("displayIcon")] public Uri DisplayIcon { get; set; } + + [JsonPropertyName("listViewIcon")] public Uri ListViewIcon { get; set; } + + [JsonPropertyName("splash")] public Uri Splash { get; set; } + + [JsonPropertyName("assetPath")] public string AssetPath { get; set; } + + [JsonPropertyName("mapUrl")] public string MapUrl { get; set; } + + [JsonPropertyName("xMultiplier")] public double XMultiplier { get; set; } + + [JsonPropertyName("yMultiplier")] public double YMultiplier { get; set; } + + [JsonPropertyName("xScalarToAdd")] public double XScalarToAdd { get; set; } + + [JsonPropertyName("yScalarToAdd")] public double YScalarToAdd { get; set; } + + [JsonExtensionData] public Dictionary? ExtensionData { get; set; } +} + +public class ValApiAgentsResponse +{ + [JsonPropertyName("status")] public int Status { get; set; } + + [JsonPropertyName("data")] public ValApiAgents[] Data { get; set; } +} + +public class ValApiAgents +{ + [JsonPropertyName("uuid")] public Guid Uuid { get; set; } + + [JsonPropertyName("displayName")] public string DisplayName { get; set; } + + [JsonPropertyName("description")] public string Description { get; set; } + + [JsonPropertyName("developerName")] public string DeveloperName { get; set; } + + [JsonPropertyName("characterTags")] public string[] CharacterTags { get; set; } + + [JsonPropertyName("displayIcon")] public Uri DisplayIcon { get; set; } + + [JsonPropertyName("displayIconSmall")] public Uri DisplayIconSmall { get; set; } + + [JsonPropertyName("bustPortrait")] public Uri BustPortrait { get; set; } + + [JsonPropertyName("fullPortrait")] public Uri FullPortrait { get; set; } + + [JsonPropertyName("killfeedPortrait")] public Uri KillfeedPortrait { get; set; } + + [JsonPropertyName("background")] public Uri Background { get; set; } + + [JsonPropertyName("assetPath")] public string AssetPath { get; set; } + + [JsonPropertyName("isFullPortraitRightFacing")] + public bool IsFullPortraitRightFacing { get; set; } + + [JsonPropertyName("isPlayableCharacter")] + public bool IsPlayableCharacter { get; set; } + + [JsonPropertyName("isAvailableForTest")] + public bool IsAvailableForTest { get; set; } + + [JsonPropertyName("isBaseContent")] public bool IsBaseContent { get; set; } + + public Dictionary? ExtensionData { get; set; } +} + +public class ValApiSkinsResponse +{ + [JsonPropertyName("status")] public int Status { get; set; } + + [JsonPropertyName("data")] public ValApiSkins[] Data { get; set; } +} + +public class ValApiCardsResponse +{ + [JsonPropertyName("status")] public int Status { get; set; } + + [JsonPropertyName("data")] public ValApiCards[] Data { get; set; } +} + +public class ValApiSkins +{ + [JsonPropertyName("uuid")] public Guid Uuid { get; set; } + + [JsonPropertyName("displayName")] public string DisplayName { get; set; } + + [JsonPropertyName("displayIcon")] public Uri DisplayIcon { get; set; } + + [JsonPropertyName("fullRender")] public Uri FullRender { get; set; } + + [JsonPropertyName("swatch")] public Uri Swatch { get; set; } + + [JsonPropertyName("streamedVideo")] public Uri StreamedVideo { get; set; } + + [JsonPropertyName("assetPath")] public string AssetPath { get; set; } + + public Dictionary? ExtensionData { get; set; } +} + +public class ValApiCards +{ + [JsonPropertyName("uuid")] public Guid Uuid { get; set; } + + [JsonPropertyName("displayName")] public string DisplayName { get; set; } + + [JsonPropertyName("isHiddenIfNotOwned")] + public bool IsHiddenIfNotOwned { get; set; } + + [JsonPropertyName("themeUuid")] public Guid? ThemeUuid { get; set; } + + [JsonPropertyName("displayIcon")] public Uri DisplayIcon { get; set; } + + [JsonPropertyName("smallArt")] public Uri SmallArt { get; set; } + + [JsonPropertyName("wideArt")] public Uri WideArt { get; set; } + + [JsonPropertyName("largeArt")] public Uri LargeArt { get; set; } + + [JsonPropertyName("assetPath")] public string AssetPath { get; set; } +} + +public class ValApiRanksResponse +{ + [JsonPropertyName("status")] public int Status { get; set; } + + [JsonPropertyName("data")] public ValApiRanks[] Data { get; set; } +} + +public class ValApiRanks +{ + [JsonPropertyName("uuid")] public Guid Uuid { get; set; } + + [JsonPropertyName("assetObjectName")] public string AssetObjectName { get; set; } + + [JsonPropertyName("tiers")] public Tier[] Tiers { get; set; } + + [JsonPropertyName("assetPath")] public string AssetPath { get; set; } + + public Dictionary? ExtensionData { get; set; } +} + +public class Tier +{ + [JsonPropertyName("tier")] public int TierTier { get; set; } + + [JsonPropertyName("tierName")] public string TierName { get; set; } + + [JsonPropertyName("division")] public string Division { get; set; } + + [JsonPropertyName("divisionName")] public string DivisionName { get; set; } + + [JsonPropertyName("smallIcon")] public Uri SmallIcon { get; set; } + + [JsonPropertyName("largeIcon")] public Uri LargeIcon { get; set; } + + [JsonPropertyName("rankTriangleDownIcon")] + public Uri RankTriangleDownIcon { get; set; } + + [JsonPropertyName("rankTriangleUpIcon")] + public Uri RankTriangleUpIcon { get; set; } + + public Dictionary? ExtensionData { get; set; } +} + +public class ValApiGamemodeResponse +{ + [JsonPropertyName("status")] public long Status { get; set; } + + [JsonPropertyName("data")] public ValApiGamemode[] Data { get; set; } +} + +public class ValApiGamemode +{ + [JsonPropertyName("uuid")] public Guid Uuid { get; set; } + + [JsonPropertyName("displayName")] public string DisplayName { get; set; } + + [JsonPropertyName("duration")] public string Duration { get; set; } + + [JsonPropertyName("allowsMatchTimeouts")] + public bool AllowsMatchTimeouts { get; set; } + + [JsonPropertyName("isTeamVoiceAllowed")] + public bool IsTeamVoiceAllowed { get; set; } + + [JsonPropertyName("isMinimapHidden")] public bool IsMinimapHidden { get; set; } + + [JsonPropertyName("orbCount")] public long OrbCount { get; set; } + + [JsonPropertyName("teamRoles")] public string[] TeamRoles { get; set; } + + public Dictionary? ExtensionData { get; set; } + + [JsonPropertyName("displayIcon")] public Uri DisplayIcon { get; set; } + + [JsonPropertyName("assetPath")] public string AssetPath { get; set; } +} \ No newline at end of file diff --git a/WAIUA/Properties/Annotations.cs b/WAIUA/Properties/Annotations.cs new file mode 100644 index 00000000..2a050c07 --- /dev/null +++ b/WAIUA/Properties/Annotations.cs @@ -0,0 +1,1882 @@ +/* MIT License + +Copyright (c) 2016 JetBrains http://www.jetbrains.com + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. */ + +using System; + +// ReSharper disable UnusedType.Global + +#pragma warning disable 1591 +// ReSharper disable UnusedMember.Global +// ReSharper disable MemberCanBePrivate.Global +// ReSharper disable UnusedAutoPropertyAccessor.Global +// ReSharper disable IntroduceOptionalParameters.Global +// ReSharper disable MemberCanBeProtected.Global +// ReSharper disable InconsistentNaming + +namespace WAIUA.Annotations; + +/// +/// Indicates that the value of the marked element could be null sometimes, +/// so checking for null is required before its usage. +/// +/// +/// +/// [CanBeNull] object Test() => null; +/// +/// void UseTest() { +/// var p = Test(); +/// var s = p.ToString(); // Warning: Possible 'System.NullReferenceException' +/// } +/// +/// +[AttributeUsage( + AttributeTargets.Method | AttributeTargets.Parameter | AttributeTargets.Property | + AttributeTargets.Delegate | AttributeTargets.Field | AttributeTargets.Event | + AttributeTargets.Class | AttributeTargets.Interface | AttributeTargets.GenericParameter)] +public sealed class CanBeNullAttribute : Attribute +{ +} + +/// +/// Indicates that the value of the marked element can never be null. +/// +/// +/// +/// [NotNull] object Foo() { +/// return null; // Warning: Possible 'null' assignment +/// } +/// +/// +[AttributeUsage( + AttributeTargets.Method | AttributeTargets.Parameter | AttributeTargets.Property | + AttributeTargets.Delegate | AttributeTargets.Field | AttributeTargets.Event | + AttributeTargets.Class | AttributeTargets.Interface | AttributeTargets.GenericParameter)] +public sealed class NotNullAttribute : Attribute +{ +} + +/// +/// Can be applied to symbols of types derived from IEnumerable as well as to symbols of Task +/// and Lazy classes to indicate that the value of a collection item, of the Task.Result property +/// or of the Lazy.Value property can never be null. +/// +/// +/// +/// public void Foo([ItemNotNull]List<string> books) +/// { +/// foreach (var book in books) { +/// if (book != null) // Warning: Expression is always true +/// Console.WriteLine(book.ToUpper()); +/// } +/// } +/// +/// +[AttributeUsage( + AttributeTargets.Method | AttributeTargets.Parameter | AttributeTargets.Property | + AttributeTargets.Delegate | AttributeTargets.Field)] +public sealed class ItemNotNullAttribute : Attribute +{ +} + +/// +/// Can be applied to symbols of types derived from IEnumerable as well as to symbols of Task +/// and Lazy classes to indicate that the value of a collection item, of the Task.Result property +/// or of the Lazy.Value property can be null. +/// +/// +/// +/// public void Foo([ItemCanBeNull]List<string> books) +/// { +/// foreach (var book in books) +/// { +/// // Warning: Possible 'System.NullReferenceException' +/// Console.WriteLine(book.ToUpper()); +/// } +/// } +/// +/// +[AttributeUsage( + AttributeTargets.Method | AttributeTargets.Parameter | AttributeTargets.Property | + AttributeTargets.Delegate | AttributeTargets.Field)] +public sealed class ItemCanBeNullAttribute : Attribute +{ +} + +/// +/// Indicates that the marked method builds string by the format pattern and (optional) arguments. +/// The parameter, which contains the format string, should be given in the constructor. The format string +/// should be in -like form. +/// +/// +/// +/// [StringFormatMethod("message")] +/// void ShowError(string message, params object[] args) { /* do something */ } +/// +/// void Foo() { +/// ShowError("Failed: {0}"); // Warning: Non-existing argument in format string +/// } +/// +/// +[AttributeUsage( + AttributeTargets.Constructor | AttributeTargets.Method | + AttributeTargets.Property | AttributeTargets.Delegate)] +public sealed class StringFormatMethodAttribute : Attribute +{ + /// + /// Specifies which parameter of an annotated method should be treated as the format string + /// + public StringFormatMethodAttribute([NotNull] string formatParameterName) + { + FormatParameterName = formatParameterName; + } + + [NotNull] public string FormatParameterName { get; } +} + +/// +/// Indicates that the marked parameter is a message template where placeholders are to be replaced by the following +/// arguments +/// in the order in which they appear +/// +/// +/// +/// void LogInfo([StructuredMessageTemplate]string message, params object[] args) { /* do something */ } +/// +/// void Foo() { +/// LogInfo("User created: {username}"); // Warning: Non-existing argument in format string +/// } +/// +/// +[AttributeUsage(AttributeTargets.Parameter)] +public sealed class StructuredMessageTemplateAttribute : Attribute +{ +} + +/// +/// Use this annotation to specify a type that contains static or const fields +/// with values for the annotated property/field/parameter. +/// The specified type will be used to improve completion suggestions. +/// +/// +/// +/// namespace TestNamespace +/// { +/// public class Constants +/// { +/// public static int INT_CONST = 1; +/// public const string STRING_CONST = "1"; +/// } +/// +/// public class Class1 +/// { +/// [ValueProvider("TestNamespace.Constants")] public int myField; +/// public void Foo([ValueProvider("TestNamespace.Constants")] string str) { } +/// +/// public void Test() +/// { +/// Foo(/*try completion here*/);// +/// myField = /*try completion here*/ +/// } +/// } +/// } +/// +/// +[AttributeUsage( + AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.Field, + AllowMultiple = true)] +public sealed class ValueProviderAttribute : Attribute +{ + public ValueProviderAttribute([NotNull] string name) + { + Name = name; + } + + [NotNull] public string Name { get; } +} + +/// +/// Indicates that the integral value falls into the specified interval. +/// It's allowed to specify multiple non-intersecting intervals. +/// Values of interval boundaries are inclusive. +/// +/// +/// +/// void Foo([ValueRange(0, 100)] int value) { +/// if (value == -1) { // Warning: Expression is always 'false' +/// ... +/// } +/// } +/// +/// +[AttributeUsage( + AttributeTargets.Parameter | AttributeTargets.Field | AttributeTargets.Property | + AttributeTargets.Method | AttributeTargets.Delegate, + AllowMultiple = true)] +public sealed class ValueRangeAttribute : Attribute +{ + public ValueRangeAttribute(long from, long to) + { + From = from; + To = to; + } + + public ValueRangeAttribute(ulong from, ulong to) + { + From = from; + To = to; + } + + public ValueRangeAttribute(long value) + { + From = To = value; + } + + public ValueRangeAttribute(ulong value) + { + From = To = value; + } + + public object From { get; } + public object To { get; } +} + +/// +/// Indicates that the integral value never falls below zero. +/// +/// +/// +/// void Foo([NonNegativeValue] int value) { +/// if (value == -1) { // Warning: Expression is always 'false' +/// ... +/// } +/// } +/// +/// +[AttributeUsage( + AttributeTargets.Parameter | AttributeTargets.Field | AttributeTargets.Property | + AttributeTargets.Method | AttributeTargets.Delegate)] +public sealed class NonNegativeValueAttribute : Attribute +{ +} + +/// +/// Indicates that the function argument should be a string literal and match one +/// of the parameters of the caller function. For example, ReSharper annotates +/// the parameter of . +/// +/// +/// +/// void Foo(string param) { +/// if (param == null) +/// throw new ArgumentNullException("par"); // Warning: Cannot resolve symbol +/// } +/// +/// +[AttributeUsage(AttributeTargets.Parameter)] +public sealed class InvokerParameterNameAttribute : Attribute +{ +} + +/// +/// Indicates that the method is contained in a type that implements +/// System.ComponentModel.INotifyPropertyChanged interface and this method +/// is used to notify that some property value changed. +/// +/// +/// The method should be non-static and conform to one of the supported signatures: +/// +/// +/// NotifyChanged(string) +/// +/// +/// NotifyChanged(params string[]) +/// +/// +/// NotifyChanged{T}(Expression{Func{T}}) +/// +/// +/// NotifyChanged{T,U}(Expression{Func{T,U}}) +/// +/// +/// SetProperty{T}(ref T, T, string) +/// +/// +/// +/// +/// +/// public class Foo : INotifyPropertyChanged { +/// public event PropertyChangedEventHandler PropertyChanged; +/// +/// [NotifyPropertyChangedInvocator] +/// protected virtual void NotifyChanged(string propertyName) { ... } +/// +/// string _name; +/// +/// public string Name { +/// get { return _name; } +/// set { _name = value; NotifyChanged("LastName"); /* Warning */ } +/// } +/// } +/// +/// Examples of generated notifications: +/// +/// +/// NotifyChanged("Property") +/// +/// +/// NotifyChanged(() => Property) +/// +/// +/// NotifyChanged((VM x) => x.Property) +/// +/// +/// SetProperty(ref myField, value, "Property") +/// +/// +/// +[AttributeUsage(AttributeTargets.Method)] +public sealed class NotifyPropertyChangedInvocatorAttribute : Attribute +{ + public NotifyPropertyChangedInvocatorAttribute() + { + } + + public NotifyPropertyChangedInvocatorAttribute([NotNull] string parameterName) + { + ParameterName = parameterName; + } + + [CanBeNull] public string ParameterName { get; } +} + +/// +/// Describes dependency between method input and output. +/// +/// +///

Function Definition Table syntax:

+/// +/// FDT ::= FDTRow [;FDTRow]* +/// FDTRow ::= Input => Output | Output <= Input +/// Input ::= ParameterName: Value [, Input]* +/// Output ::= [ParameterName: Value]* {halt|stop|void|nothing|Value} +/// Value ::= true | false | null | notnull | canbenull +/// +/// If the method has a single input parameter, its name could be omitted.
+/// Using halt (or void/nothing, which is the same) for the method output +/// means that the method doesn't return normally (throws or terminates the process).
+/// Value canbenull is only applicable for output parameters.
+/// You can use multiple [ContractAnnotation] for each FDT row, or use single attribute +/// with rows separated by the semicolon. There is no notion of order rows, all rows are checked +/// for applicability and applied per each program state tracked by the analysis engine.
+///
+/// +/// +/// +/// +/// [ContractAnnotation("=> halt")] +/// public void TerminationMethod() +/// +/// +/// +/// +/// [ContractAnnotation("null <= param:null")] // reverse condition syntax +/// public string GetName(string surname) +/// +/// +/// +/// +/// [ContractAnnotation("s:null => true")] +/// public bool IsNullOrEmpty(string s) // string.IsNullOrEmpty() +/// +/// +/// +/// +/// // A method that returns null if the parameter is null, +/// // and not null if the parameter is not null +/// [ContractAnnotation("null => null; notnull => notnull")] +/// public object Transform(object data) +/// +/// +/// +/// +/// [ContractAnnotation("=> true, result: notnull; => false, result: null")] +/// public bool TryParse(string s, out Person result) +/// +/// +/// +/// +[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] +public sealed class ContractAnnotationAttribute : Attribute +{ + public ContractAnnotationAttribute([NotNull] string contract) + : this(contract, false) + { + } + + public ContractAnnotationAttribute([NotNull] string contract, bool forceFullStates) + { + Contract = contract; + ForceFullStates = forceFullStates; + } + + [NotNull] public string Contract { get; } + + public bool ForceFullStates { get; } +} + +/// +/// Indicates whether the marked element should be localized. +/// +/// +/// +/// [LocalizationRequiredAttribute(true)] +/// class Foo { +/// string str = "my string"; // Warning: Localizable string +/// } +/// +/// +[AttributeUsage(AttributeTargets.All)] +public sealed class LocalizationRequiredAttribute : Attribute +{ + public LocalizationRequiredAttribute() : this(true) + { + } + + public LocalizationRequiredAttribute(bool required) + { + Required = required; + } + + public bool Required { get; } +} + +/// +/// Indicates that the value of the marked type (or its derivatives) +/// cannot be compared using '==' or '!=' operators and Equals() +/// should be used instead. However, using '==' or '!=' for comparison +/// with null is always permitted. +/// +/// +/// +/// [CannotApplyEqualityOperator] +/// class NoEquality { } +/// +/// class UsesNoEquality { +/// void Test() { +/// var ca1 = new NoEquality(); +/// var ca2 = new NoEquality(); +/// if (ca1 != null) { // OK +/// bool condition = ca1 == ca2; // Warning +/// } +/// } +/// } +/// +/// +[AttributeUsage(AttributeTargets.Interface | AttributeTargets.Class | AttributeTargets.Struct)] +public sealed class CannotApplyEqualityOperatorAttribute : Attribute +{ +} + +/// +/// When applied to a target attribute, specifies a requirement for any type marked +/// with the target attribute to implement or inherit specific type or types. +/// +/// +/// +/// [BaseTypeRequired(typeof(IComponent)] // Specify requirement +/// class ComponentAttribute : Attribute { } +/// +/// [Component] // ComponentAttribute requires implementing IComponent interface +/// class MyComponent : IComponent { } +/// +/// +[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] +[BaseTypeRequired(typeof(Attribute))] +public sealed class BaseTypeRequiredAttribute : Attribute +{ + public BaseTypeRequiredAttribute([NotNull] Type baseType) + { + BaseType = baseType; + } + + [NotNull] public Type BaseType { get; } +} + +/// +/// Indicates that the marked symbol is used implicitly (e.g. via reflection, in external library), +/// so this symbol will be ignored by usage-checking inspections.
+/// You can use and +/// to configure how this attribute is applied. +///
+/// +/// +/// [UsedImplicitly] +/// public class TypeConverter {} +/// +/// public class SummaryData +/// { +/// [UsedImplicitly(ImplicitUseKindFlags.InstantiatedWithFixedConstructorSignature)] +/// public SummaryData() {} +/// } +/// +/// [UsedImplicitly(ImplicitUseTargetFlags.WithInheritors | ImplicitUseTargetFlags.Default)] +/// public interface IService {} +/// +/// +[AttributeUsage(AttributeTargets.All)] +public sealed class UsedImplicitlyAttribute : Attribute +{ + public UsedImplicitlyAttribute() + : this(ImplicitUseKindFlags.Default, ImplicitUseTargetFlags.Default) + { + } + + public UsedImplicitlyAttribute(ImplicitUseKindFlags useKindFlags) + : this(useKindFlags, ImplicitUseTargetFlags.Default) + { + } + + public UsedImplicitlyAttribute(ImplicitUseTargetFlags targetFlags) + : this(ImplicitUseKindFlags.Default, targetFlags) + { + } + + public UsedImplicitlyAttribute(ImplicitUseKindFlags useKindFlags, ImplicitUseTargetFlags targetFlags) + { + UseKindFlags = useKindFlags; + TargetFlags = targetFlags; + } + + public ImplicitUseKindFlags UseKindFlags { get; } + + public ImplicitUseTargetFlags TargetFlags { get; } +} + +/// +/// Can be applied to attributes, type parameters, and parameters of a type assignable from +/// . +/// When applied to an attribute, the decorated attribute behaves the same as . +/// When applied to a type parameter or to a parameter of type , +/// indicates that the corresponding type is used implicitly. +/// +[AttributeUsage(AttributeTargets.Class | AttributeTargets.GenericParameter | AttributeTargets.Parameter)] +public sealed class MeansImplicitUseAttribute : Attribute +{ + public MeansImplicitUseAttribute() + : this(ImplicitUseKindFlags.Default, ImplicitUseTargetFlags.Default) + { + } + + public MeansImplicitUseAttribute(ImplicitUseKindFlags useKindFlags) + : this(useKindFlags, ImplicitUseTargetFlags.Default) + { + } + + public MeansImplicitUseAttribute(ImplicitUseTargetFlags targetFlags) + : this(ImplicitUseKindFlags.Default, targetFlags) + { + } + + public MeansImplicitUseAttribute(ImplicitUseKindFlags useKindFlags, ImplicitUseTargetFlags targetFlags) + { + UseKindFlags = useKindFlags; + TargetFlags = targetFlags; + } + + [UsedImplicitly] public ImplicitUseKindFlags UseKindFlags { get; } + + [UsedImplicitly] public ImplicitUseTargetFlags TargetFlags { get; } +} + +/// +/// Specifies the details of implicitly used symbol when it is marked +/// with or . +/// +[Flags] +public enum ImplicitUseKindFlags +{ + Default = Access | Assign | InstantiatedWithFixedConstructorSignature, + + /// Only entity marked with attribute considered used. + Access = 1, + + /// Indicates implicit assignment to a member. + Assign = 2, + + /// + /// Indicates implicit instantiation of a type with fixed constructor signature. + /// That means any unused constructor parameters won't be reported as such. + /// + InstantiatedWithFixedConstructorSignature = 4, + + /// Indicates implicit instantiation of a type. + InstantiatedNoFixedConstructorSignature = 8 +} + +/// +/// Specifies what is considered to be used implicitly when marked +/// with or . +/// +[Flags] +public enum ImplicitUseTargetFlags +{ + Default = Itself, + Itself = 1, + + /// Members of the type marked with the attribute are considered used. + Members = 2, + + /// Inherited entities are considered used. + WithInheritors = 4, + + /// Entity marked with the attribute and all its members considered used. + WithMembers = Itself | Members +} + +/// +/// This attribute is intended to mark publicly available API, +/// which should not be removed and so is treated as used. +/// +[MeansImplicitUse(ImplicitUseTargetFlags.WithMembers)] +[AttributeUsage(AttributeTargets.All, Inherited = false)] +public sealed class PublicAPIAttribute : Attribute +{ + public PublicAPIAttribute() + { + } + + public PublicAPIAttribute([NotNull] string comment) + { + Comment = comment; + } + + [CanBeNull] public string Comment { get; } +} + +/// +/// Tells the code analysis engine if the parameter is completely handled when the invoked method is on stack. +/// If the parameter is a delegate, indicates that delegate can only be invoked during method execution +/// (the delegate can be invoked zero or multiple times, but not stored to some field and invoked later, +/// when the containing method is no longer on the execution stack). +/// If the parameter is an enumerable, indicates that it is enumerated while the method is executed. +/// If is true, the attribute will only takes effect if the method invocation is located +/// under the 'await' expression. +/// +[AttributeUsage(AttributeTargets.Parameter)] +public sealed class InstantHandleAttribute : Attribute +{ + /// + /// Require the method invocation to be used under the 'await' expression for this attribute to take effect on code + /// analysis engine. + /// Can be used for delegate/enumerable parameters of 'async' methods. + /// + public bool RequireAwait { get; set; } +} + +/// +/// Indicates that a method does not make any observable state changes. +/// The same as System.Diagnostics.Contracts.PureAttribute. +/// +/// +/// +/// [Pure] int Multiply(int x, int y) => x * y; +/// +/// void M() { +/// Multiply(123, 42); // Warning: Return value of pure method is not used +/// } +/// +/// +[AttributeUsage(AttributeTargets.Method)] +public sealed class PureAttribute : Attribute +{ +} + +/// +/// Indicates that the return value of the method invocation must be used. +/// +/// +/// Methods decorated with this attribute (in contrast to pure methods) might change state, +/// but make no sense without using their return value.
+/// Similarly to , this attribute +/// will help to detect usages of the method when the return value is not used. +/// Optionally, you can specify a message to use when showing warnings, e.g. +/// [MustUseReturnValue("Use the return value to...")]. +///
+[AttributeUsage(AttributeTargets.Method)] +public sealed class MustUseReturnValueAttribute : Attribute +{ + public MustUseReturnValueAttribute() + { + } + + public MustUseReturnValueAttribute([NotNull] string justification) + { + Justification = justification; + } + + [CanBeNull] public string Justification { get; } +} + +/// +/// This annotation allows to enforce allocation-less usage patterns of delegates for performance-critical APIs. +/// When this annotation is applied to the parameter of delegate type, IDE checks the input argument of this parameter: +/// * When lambda expression or anonymous method is passed as an argument, IDE verifies that the passed closure +/// has no captures of the containing local variables and the compiler is able to cache the delegate instance +/// to avoid heap allocations. Otherwise the warning is produced. +/// * IDE warns when method name or local function name is passed as an argument as this always results +/// in heap allocation of the delegate instance. +/// +/// +/// In C# 9.0 code IDE would also suggest to annotate the anonymous function with 'static' modifier +/// to make use of the similar analysis provided by the language/compiler. +/// +[AttributeUsage(AttributeTargets.Parameter)] +public class RequireStaticDelegateAttribute : Attribute +{ + public bool IsError { get; set; } +} + +/// +/// Indicates the type member or parameter of some type, that should be used instead of all other ways +/// to get the value of that type. This annotation is useful when you have some "context" value evaluated +/// and stored somewhere, meaning that all other ways to get this value must be consolidated with existing one. +/// +/// +/// +/// class Foo { +/// [ProvidesContext] IBarService _barService = ...; +/// +/// void ProcessNode(INode node) { +/// DoSomething(node, node.GetGlobalServices().Bar); +/// // ^ Warning: use value of '_barService' field +/// } +/// } +/// +/// +[AttributeUsage( + AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Parameter | AttributeTargets.Method | + AttributeTargets.Class | AttributeTargets.Interface | AttributeTargets.Struct | AttributeTargets.GenericParameter)] +public sealed class ProvidesContextAttribute : Attribute +{ +} + +/// +/// Indicates that a parameter is a path to a file or a folder within a web project. +/// Path can be relative or absolute, starting from web root (~). +/// +[AttributeUsage(AttributeTargets.Parameter)] +public sealed class PathReferenceAttribute : Attribute +{ + public PathReferenceAttribute() + { + } + + public PathReferenceAttribute([NotNull] [PathReference] string basePath) + { + BasePath = basePath; + } + + [CanBeNull] public string BasePath { get; } +} + +/// +/// An extension method marked with this attribute is processed by code completion +/// as a 'Source Template'. When the extension method is completed over some expression, its source code +/// is automatically expanded like a template at call site. +/// +/// +/// Template method body can contain valid source code and/or special comments starting with '$'. +/// Text inside these comments is added as source code when the template is applied. Template parameters +/// can be used either as additional method parameters or as identifiers wrapped in two '$' signs. +/// Use the attribute to specify macros for parameters. +/// +/// +/// In this example, the 'forEach' method is a source template available over all values +/// of enumerable types, producing ordinary C# 'foreach' statement and placing caret inside block: +/// +/// [SourceTemplate] +/// public static void forEach<T>(this IEnumerable<T> xs) { +/// foreach (var x in xs) { +/// //$ $END$ +/// } +/// } +/// +/// +[AttributeUsage(AttributeTargets.Method)] +public sealed class SourceTemplateAttribute : Attribute +{ +} + +/// +/// Allows specifying a macro for a parameter of a source template. +/// +/// +/// You can apply the attribute on the whole method or on any of its additional parameters. The macro expression +/// is defined in the property. When applied on a method, the target +/// template parameter is defined in the property. To apply the macro silently +/// for the parameter, set the property value = -1. +/// +/// +/// Applying the attribute on a source template method: +/// +/// [SourceTemplate, Macro(Target = "item", Expression = "suggestVariableName()")] +/// public static void forEach<T>(this IEnumerable<T> collection) { +/// foreach (var item in collection) { +/// //$ $END$ +/// } +/// } +/// +/// Applying the attribute on a template method parameter: +/// +/// [SourceTemplate] +/// public static void something(this Entity x, [Macro(Expression = "guid()", Editable = -1)] string newguid) { +/// /*$ var $x$Id = "$newguid$" + x.ToString(); +/// x.DoSomething($x$Id); */ +/// } +/// +/// +[AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Method, AllowMultiple = true)] +public sealed class MacroAttribute : Attribute +{ + /// + /// Allows specifying a macro that will be executed for a source template + /// parameter when the template is expanded. + /// + [CanBeNull] + public string Expression { get; set; } + + /// + /// Allows specifying which occurrence of the target parameter becomes editable when the template is deployed. + /// + /// + /// If the target parameter is used several times in the template, only one occurrence becomes editable; + /// other occurrences are changed synchronously. To specify the zero-based index of the editable occurrence, + /// use values >= 0. To make the parameter non-editable when the template is expanded, use -1. + /// + public int Editable { get; set; } + + /// + /// Identifies the target parameter of a source template if the + /// is applied on a template method. + /// + [CanBeNull] + public string Target { get; set; } +} + +[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = true)] +public sealed class AspMvcAreaMasterLocationFormatAttribute : Attribute +{ + public AspMvcAreaMasterLocationFormatAttribute([NotNull] string format) + { + Format = format; + } + + [NotNull] public string Format { get; } +} + +[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = true)] +public sealed class AspMvcAreaPartialViewLocationFormatAttribute : Attribute +{ + public AspMvcAreaPartialViewLocationFormatAttribute([NotNull] string format) + { + Format = format; + } + + [NotNull] public string Format { get; } +} + +[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = true)] +public sealed class AspMvcAreaViewLocationFormatAttribute : Attribute +{ + public AspMvcAreaViewLocationFormatAttribute([NotNull] string format) + { + Format = format; + } + + [NotNull] public string Format { get; } +} + +[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = true)] +public sealed class AspMvcMasterLocationFormatAttribute : Attribute +{ + public AspMvcMasterLocationFormatAttribute([NotNull] string format) + { + Format = format; + } + + [NotNull] public string Format { get; } +} + +[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = true)] +public sealed class AspMvcPartialViewLocationFormatAttribute : Attribute +{ + public AspMvcPartialViewLocationFormatAttribute([NotNull] string format) + { + Format = format; + } + + [NotNull] public string Format { get; } +} + +[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = true)] +public sealed class AspMvcViewLocationFormatAttribute : Attribute +{ + public AspMvcViewLocationFormatAttribute([NotNull] string format) + { + Format = format; + } + + [NotNull] public string Format { get; } +} + +/// +/// ASP.NET MVC attribute. If applied to a parameter, indicates that the parameter +/// is an MVC action. If applied to a method, the MVC action name is calculated +/// implicitly from the context. Use this attribute for custom wrappers similar to +/// System.Web.Mvc.Html.ChildActionExtensions.RenderAction(HtmlHelper, String). +/// +[AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Method | AttributeTargets.Field | AttributeTargets.Property)] +public sealed class AspMvcActionAttribute : Attribute +{ + public AspMvcActionAttribute() + { + } + + public AspMvcActionAttribute([NotNull] string anonymousProperty) + { + AnonymousProperty = anonymousProperty; + } + + [CanBeNull] public string AnonymousProperty { get; } +} + +/// +/// ASP.NET MVC attribute. Indicates that the marked parameter is an MVC area. +/// Use this attribute for custom wrappers similar to +/// System.Web.Mvc.Html.ChildActionExtensions.RenderAction(HtmlHelper, String). +/// +[AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Field | AttributeTargets.Property)] +public sealed class AspMvcAreaAttribute : Attribute +{ + public AspMvcAreaAttribute() + { + } + + public AspMvcAreaAttribute([NotNull] string anonymousProperty) + { + AnonymousProperty = anonymousProperty; + } + + [CanBeNull] public string AnonymousProperty { get; } +} + +/// +/// ASP.NET MVC attribute. If applied to a parameter, indicates that the parameter is +/// an MVC controller. If applied to a method, the MVC controller name is calculated +/// implicitly from the context. Use this attribute for custom wrappers similar to +/// System.Web.Mvc.Html.ChildActionExtensions.RenderAction(HtmlHelper, String, String). +/// +[AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Method | AttributeTargets.Field | AttributeTargets.Property)] +public sealed class AspMvcControllerAttribute : Attribute +{ + public AspMvcControllerAttribute() + { + } + + public AspMvcControllerAttribute([NotNull] string anonymousProperty) + { + AnonymousProperty = anonymousProperty; + } + + [CanBeNull] public string AnonymousProperty { get; } +} + +/// +/// ASP.NET MVC attribute. Indicates that the marked parameter is an MVC Master. Use this attribute +/// for custom wrappers similar to System.Web.Mvc.Controller.View(String, String). +/// +[AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Field | AttributeTargets.Property)] +public sealed class AspMvcMasterAttribute : Attribute +{ +} + +/// +/// ASP.NET MVC attribute. Indicates that the marked parameter is an MVC model type. Use this attribute +/// for custom wrappers similar to System.Web.Mvc.Controller.View(String, Object). +/// +[AttributeUsage(AttributeTargets.Parameter)] +public sealed class AspMvcModelTypeAttribute : Attribute +{ +} + +/// +/// ASP.NET MVC attribute. If applied to a parameter, indicates that the parameter is an MVC +/// partial view. If applied to a method, the MVC partial view name is calculated implicitly +/// from the context. Use this attribute for custom wrappers similar to +/// System.Web.Mvc.Html.RenderPartialExtensions.RenderPartial(HtmlHelper, String). +/// +[AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Method | AttributeTargets.Field | AttributeTargets.Property)] +public sealed class AspMvcPartialViewAttribute : Attribute +{ +} + +/// +/// ASP.NET MVC attribute. Allows disabling inspections for MVC views within a class or a method. +/// +[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)] +public sealed class AspMvcSuppressViewErrorAttribute : Attribute +{ +} + +/// +/// ASP.NET MVC attribute. Indicates that a parameter is an MVC display template. +/// Use this attribute for custom wrappers similar to +/// System.Web.Mvc.Html.DisplayExtensions.DisplayForModel(HtmlHelper, String). +/// +[AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Field | AttributeTargets.Property)] +public sealed class AspMvcDisplayTemplateAttribute : Attribute +{ +} + +/// +/// ASP.NET MVC attribute. Indicates that the marked parameter is an MVC editor template. +/// Use this attribute for custom wrappers similar to +/// System.Web.Mvc.Html.EditorExtensions.EditorForModel(HtmlHelper, String). +/// +[AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Field | AttributeTargets.Property)] +public sealed class AspMvcEditorTemplateAttribute : Attribute +{ +} + +/// +/// ASP.NET MVC attribute. Indicates that the marked parameter is an MVC template. +/// Use this attribute for custom wrappers similar to +/// System.ComponentModel.DataAnnotations.UIHintAttribute(System.String). +/// +[AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Field | AttributeTargets.Property)] +public sealed class AspMvcTemplateAttribute : Attribute +{ +} + +/// +/// ASP.NET MVC attribute. If applied to a parameter, indicates that the parameter +/// is an MVC view component. If applied to a method, the MVC view name is calculated implicitly +/// from the context. Use this attribute for custom wrappers similar to +/// System.Web.Mvc.Controller.View(Object). +/// +[AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Method | AttributeTargets.Field | AttributeTargets.Property)] +public sealed class AspMvcViewAttribute : Attribute +{ +} + +/// +/// ASP.NET MVC attribute. If applied to a parameter, indicates that the parameter +/// is an MVC view component name. +/// +[AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Field | AttributeTargets.Property)] +public sealed class AspMvcViewComponentAttribute : Attribute +{ +} + +/// +/// ASP.NET MVC attribute. If applied to a parameter, indicates that the parameter +/// is an MVC view component view. If applied to a method, the MVC view component view name is default. +/// +[AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Method | AttributeTargets.Field | AttributeTargets.Property)] +public sealed class AspMvcViewComponentViewAttribute : Attribute +{ +} + +/// +/// ASP.NET MVC attribute. When applied to a parameter of an attribute, +/// indicates that this parameter is an MVC action name. +/// +/// +/// +/// [ActionName("Foo")] +/// public ActionResult Login(string returnUrl) { +/// ViewBag.ReturnUrl = Url.Action("Foo"); // OK +/// return RedirectToAction("Bar"); // Error: Cannot resolve action +/// } +/// +/// +[AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Property)] +public sealed class AspMvcActionSelectorAttribute : Attribute +{ +} + +[AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.Field)] +public sealed class HtmlElementAttributesAttribute : Attribute +{ + public HtmlElementAttributesAttribute() + { + } + + public HtmlElementAttributesAttribute([NotNull] string name) + { + Name = name; + } + + [CanBeNull] public string Name { get; } +} + +[AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Field | AttributeTargets.Property)] +public sealed class HtmlAttributeValueAttribute : Attribute +{ + public HtmlAttributeValueAttribute([NotNull] string name) + { + Name = name; + } + + [NotNull] public string Name { get; } +} + +/// +/// Razor attribute. Indicates that the marked parameter or method is a Razor section. +/// Use this attribute for custom wrappers similar to +/// System.Web.WebPages.WebPageBase.RenderSection(String). +/// +[AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Method)] +public sealed class RazorSectionAttribute : Attribute +{ +} + +/// +/// Indicates how method, constructor invocation, or property access +/// over collection type affects the contents of the collection. +/// When applied to a return value of a method indicates if the returned collection +/// is created exclusively for the caller (CollectionAccessType.UpdatedContent) or +/// can be read/updated from outside (CollectionAccessType.Read | CollectionAccessType.UpdatedContent) +/// Use to specify the access type. +/// +/// +/// Using this attribute only makes sense if all collection methods are marked with this attribute. +/// +/// +/// +/// public class MyStringCollection : List<string> +/// { +/// [CollectionAccess(CollectionAccessType.Read)] +/// public string GetFirstString() +/// { +/// return this.ElementAt(0); +/// } +/// } +/// class Test +/// { +/// public void Foo() +/// { +/// // Warning: Contents of the collection is never updated +/// var col = new MyStringCollection(); +/// string x = col.GetFirstString(); +/// } +/// } +/// +/// +[AttributeUsage(AttributeTargets.Method | AttributeTargets.Constructor | AttributeTargets.Property | AttributeTargets.ReturnValue)] +public sealed class CollectionAccessAttribute : Attribute +{ + public CollectionAccessAttribute(CollectionAccessType collectionAccessType) + { + CollectionAccessType = collectionAccessType; + } + + public CollectionAccessType CollectionAccessType { get; } +} + +/// +/// Provides a value for the to define +/// how the collection method invocation affects the contents of the collection. +/// +[Flags] +public enum CollectionAccessType +{ + /// Method does not use or modify content of the collection. + None = 0, + + /// Method only reads content of the collection but does not modify it. + Read = 1, + + /// Method can change content of the collection but does not add new elements. + ModifyExistingContent = 2, + + /// Method can add new elements to the collection. + UpdatedContent = ModifyExistingContent | 4 +} + +/// +/// Indicates that the marked method is assertion method, i.e. it halts the control flow if +/// one of the conditions is satisfied. To set the condition, mark one of the parameters with +/// attribute. +/// +[AttributeUsage(AttributeTargets.Method)] +public sealed class AssertionMethodAttribute : Attribute +{ +} + +/// +/// Indicates the condition parameter of the assertion method. The method itself should be +/// marked by attribute. The mandatory argument of +/// the attribute is the assertion type. +/// +[AttributeUsage(AttributeTargets.Parameter)] +public sealed class AssertionConditionAttribute : Attribute +{ + public AssertionConditionAttribute(AssertionConditionType conditionType) + { + ConditionType = conditionType; + } + + public AssertionConditionType ConditionType { get; } +} + +/// +/// Specifies assertion type. If the assertion method argument satisfies the condition, +/// then the execution continues. Otherwise, execution is assumed to be halted. +/// +public enum AssertionConditionType +{ + /// Marked parameter should be evaluated to true. + IS_TRUE = 0, + + /// Marked parameter should be evaluated to false. + IS_FALSE = 1, + + /// Marked parameter should be evaluated to null value. + IS_NULL = 2, + + /// Marked parameter should be evaluated to not null value. + IS_NOT_NULL = 3 +} + +/// +/// Indicates that the marked method unconditionally terminates control flow execution. +/// For example, it could unconditionally throw exception. +/// +[Obsolete("Use [ContractAnnotation('=> halt')] instead")] +[AttributeUsage(AttributeTargets.Method)] +public sealed class TerminatesProgramAttribute : Attribute +{ +} + +/// +/// Indicates that the method is a pure LINQ method, with postponed enumeration (like Enumerable.Select, +/// .Where). This annotation allows inference of [InstantHandle] annotation for parameters +/// of delegate type by analyzing LINQ method chains. +/// +[AttributeUsage(AttributeTargets.Method)] +public sealed class LinqTunnelAttribute : Attribute +{ +} + +/// +/// Indicates that IEnumerable passed as a parameter is not enumerated. +/// Use this annotation to suppress the 'Possible multiple enumeration of IEnumerable' inspection. +/// +/// +/// +/// static void ThrowIfNull<T>([NoEnumeration] T v, string n) where T : class +/// { +/// // custom check for null but no enumeration +/// } +/// +/// void Foo(IEnumerable<string> values) +/// { +/// ThrowIfNull(values, nameof(values)); +/// var x = values.ToList(); // No warnings about multiple enumeration +/// } +/// +/// +[AttributeUsage(AttributeTargets.Parameter)] +public sealed class NoEnumerationAttribute : Attribute +{ +} + +/// +/// Indicates that the marked parameter, field, or property is a regular expression pattern. +/// +[AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Field | AttributeTargets.Property)] +public sealed class RegexPatternAttribute : Attribute +{ +} + +/// +/// Language of injected code fragment inside marked by string literal. +/// +public enum InjectedLanguage +{ + CSS, + HTML, + JAVASCRIPT, + JSON, + XML +} + +/// +/// Indicates that the marked parameter, field, or property is accepting a string literal +/// containing code fragment in a language specified by the . +/// +/// +/// +/// void Foo([LanguageInjection(InjectedLanguage.CSS, Prefix = "body{", Suffix = "}")] string cssProps) +/// { +/// // cssProps should only contains a list of CSS properties +/// } +/// +/// +[AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Field | AttributeTargets.Property)] +public sealed class LanguageInjectionAttribute : Attribute +{ + public LanguageInjectionAttribute(InjectedLanguage injectedLanguage) + { + InjectedLanguage = injectedLanguage; + } + + /// Specify a language of injected code fragment. + public InjectedLanguage InjectedLanguage { get; } + + /// Specify a string that "precedes" injected string literal. + [CanBeNull] + public string Prefix { get; set; } + + /// Specify a string that "follows" injected string literal. + [CanBeNull] + public string Suffix { get; set; } +} + +/// +/// Prevents the Member Reordering feature from tossing members of the marked class. +/// +/// +/// The attribute must be mentioned in your member reordering patterns. +/// +[AttributeUsage( + AttributeTargets.Class | AttributeTargets.Interface | AttributeTargets.Struct | AttributeTargets.Enum)] +public sealed class NoReorderAttribute : Attribute +{ +} + +/// +/// XAML attribute. Indicates the type that has ItemsSource property and should be treated +/// as ItemsControl-derived type, to enable inner items DataContext type resolve. +/// +[AttributeUsage(AttributeTargets.Class)] +public sealed class XamlItemsControlAttribute : Attribute +{ +} + +/// +/// XAML attribute. Indicates the property of some BindingBase-derived type, that +/// is used to bind some item of ItemsControl-derived type. This annotation will +/// enable the DataContext type resolve for XAML bindings for such properties. +/// +/// +/// Property should have the tree ancestor of the ItemsControl type or +/// marked with the attribute. +/// +[AttributeUsage(AttributeTargets.Property)] +public sealed class XamlItemBindingOfItemsControlAttribute : Attribute +{ +} + +/// +/// XAML attribute. Indicates the property of some Style-derived type, that +/// is used to style items of ItemsControl-derived type. This annotation will +/// enable the DataContext type resolve for XAML bindings for such properties. +/// +/// +/// Property should have the tree ancestor of the ItemsControl type or +/// marked with the attribute. +/// +[AttributeUsage(AttributeTargets.Property)] +public sealed class XamlItemStyleOfItemsControlAttribute : Attribute +{ +} + +/// +/// XAML attribute. Indicates that DependencyProperty has OneWay binding mode by default. +/// +/// +/// This attribute must be applied to DependencyProperty's CLR accessor property if it is present, to +/// DependencyProperty descriptor field otherwise. +/// +[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)] +public sealed class XamlOneWayBindingModeByDefaultAttribute : Attribute +{ +} + +/// +/// XAML attribute. Indicates that DependencyProperty has TwoWay binding mode by default. +/// +/// +/// This attribute must be applied to DependencyProperty's CLR accessor property if it is present, to +/// DependencyProperty descriptor field otherwise. +/// +[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)] +public sealed class XamlTwoWayBindingModeByDefaultAttribute : Attribute +{ +} + +[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] +public sealed class AspChildControlTypeAttribute : Attribute +{ + public AspChildControlTypeAttribute([NotNull] string tagName, [NotNull] Type controlType) + { + TagName = tagName; + ControlType = controlType; + } + + [NotNull] public string TagName { get; } + + [NotNull] public Type ControlType { get; } +} + +[AttributeUsage(AttributeTargets.Property | AttributeTargets.Method)] +public sealed class AspDataFieldAttribute : Attribute +{ +} + +[AttributeUsage(AttributeTargets.Property | AttributeTargets.Method)] +public sealed class AspDataFieldsAttribute : Attribute +{ +} + +[AttributeUsage(AttributeTargets.Property)] +public sealed class AspMethodPropertyAttribute : Attribute +{ +} + +[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] +public sealed class AspRequiredAttributeAttribute : Attribute +{ + public AspRequiredAttributeAttribute([NotNull] string attribute) + { + Attribute = attribute; + } + + [NotNull] public string Attribute { get; } +} + +[AttributeUsage(AttributeTargets.Property)] +public sealed class AspTypePropertyAttribute : Attribute +{ + public AspTypePropertyAttribute(bool createConstructorReferences) + { + CreateConstructorReferences = createConstructorReferences; + } + + public bool CreateConstructorReferences { get; } +} + +[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] +public sealed class RazorImportNamespaceAttribute : Attribute +{ + public RazorImportNamespaceAttribute([NotNull] string name) + { + Name = name; + } + + [NotNull] public string Name { get; } +} + +[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] +public sealed class RazorInjectionAttribute : Attribute +{ + public RazorInjectionAttribute([NotNull] string type, [NotNull] string fieldName) + { + Type = type; + FieldName = fieldName; + } + + [NotNull] public string Type { get; } + + [NotNull] public string FieldName { get; } +} + +[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] +public sealed class RazorDirectiveAttribute : Attribute +{ + public RazorDirectiveAttribute([NotNull] string directive) + { + Directive = directive; + } + + [NotNull] public string Directive { get; } +} + +[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] +public sealed class RazorPageBaseTypeAttribute : Attribute +{ + public RazorPageBaseTypeAttribute([NotNull] string baseType) + { + BaseType = baseType; + } + + public RazorPageBaseTypeAttribute([NotNull] string baseType, string pageName) + { + BaseType = baseType; + PageName = pageName; + } + + [NotNull] public string BaseType { get; } + [CanBeNull] public string PageName { get; } +} + +[AttributeUsage(AttributeTargets.Method)] +public sealed class RazorHelperCommonAttribute : Attribute +{ +} + +[AttributeUsage(AttributeTargets.Property)] +public sealed class RazorLayoutAttribute : Attribute +{ +} + +[AttributeUsage(AttributeTargets.Method)] +public sealed class RazorWriteLiteralMethodAttribute : Attribute +{ +} + +[AttributeUsage(AttributeTargets.Method)] +public sealed class RazorWriteMethodAttribute : Attribute +{ +} + +[AttributeUsage(AttributeTargets.Parameter)] +public sealed class RazorWriteMethodParameterAttribute : Attribute +{ +} + +/// +/// Indicates that the marked parameter, field, or property is a route template. +/// +/// +/// This attribute allows IDE to recognize the use of web frameworks' route templates +/// to enable syntax highlighting, code completion, navigation, rename and other features in string literals. +/// +[AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Field | AttributeTargets.Property)] +public sealed class RouteTemplateAttribute : Attribute +{ +} + +/// +/// Indicates that the marked type is custom route parameter constraint, +/// which is registered in application's Startup with name ConstraintName +/// +/// +/// You can specify ProposedType if target constraint matches only route parameters of specific type, +/// it will allow IDE to create method's parameter from usage in route template +/// with specified type instead of default System.String +/// and check if constraint's proposed type conflicts with matched parameter's type +/// +[AttributeUsage(AttributeTargets.Class)] +public sealed class RouteParameterConstraintAttribute : Attribute +{ + public RouteParameterConstraintAttribute([NotNull] string constraintName) + { + ConstraintName = constraintName; + } + + [NotNull] public string ConstraintName { get; } + [CanBeNull] public Type ProposedType { get; set; } +} + +/// +/// Indicates that the marked parameter, field, or property is an URI string. +/// +/// +/// This attribute enables code completion, navigation, rename and other features +/// in URI string literals assigned to annotated parameter, field or property. +/// +[AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Field | AttributeTargets.Property)] +public sealed class UriStringAttribute : Attribute +{ + public UriStringAttribute() + { + } + + public UriStringAttribute(string httpVerb) + { + HttpVerb = httpVerb; + } + + [CanBeNull] public string HttpVerb { get; } +} + +/// +/// +/// Defines the code search template using the Structural Search and Replace syntax. +/// It allows you to find and, if necessary, replace blocks of code that match a specific pattern. +/// Search and replace patterns consist of a textual part and placeholders. +/// Textural part must contain only identifiers allowed in the target language and will be matched exactly (white +/// spaces, tabulation characters, and line breaks are ignored). +/// Placeholders allow matching variable parts of the target code blocks. +/// A placeholder has the following format: $placeholder_name$- where placeholder_name is an arbitrary identifier. +/// +/// +/// Available placeholders: +/// +/// $this$ - expression of containing type +/// $thisType$ - containing type +/// $member$ - current member placeholder +/// +/// $qualifier$ - this placeholder is available in the replace pattern and can be used to insert qualifier +/// expression matched by the $member$ placeholder. +/// (Note that if $qualifier$ placeholder is used, then $member$ placeholder will match only qualified +/// references) +/// +/// $expression$ - expression of any type +/// $identifier$ - identifier placeholder +/// $args$ - any number of arguments +/// $arg$ - single argument +/// $arg1$ ... $arg10$ - single argument +/// $stmts$ - any number of statements +/// $stmt$ - single statement +/// $stmt1$ ... $stmt10$ - single statement +/// $name{Expression, 'Namespace.FooType'}$ - expression with 'Namespace.FooType' type +/// $expression{'Namespace.FooType'}$ - expression with 'Namespace.FooType' type +/// $name{Type, 'Namespace.FooType'}$ - 'Namespace.FooType' type +/// $type{'Namespace.FooType'}$ - 'Namespace.FooType' type +/// $statement{1,2}$ - 1 or 2 statements +/// +/// +/// +/// Note that you can also define your own placeholders of the supported types and specify arguments for each +/// placeholder type. +/// This can be done using the following format: $name{type, arguments}$. Where 'name' - is the name of your +/// placeholder, +/// 'type' - is the type of your placeholder (one of the following: Expression, Type, Identifier, Statement, +/// Argument, Member), +/// 'arguments' - arguments list for your placeholder. Each placeholder type supports it's own arguments, check +/// examples below for mode details. +/// Placeholder type may be omitted and determined from the placeholder name, if name has one of the following +/// prefixes: +/// +/// expr, expression - expression placeholder, e.g. $exprPlaceholder{}$, $expressionFoo{}$ +/// arg, argument - argument placeholder, e.g. $argPlaceholder{}$, $argumentFoo{}$ +/// ident, identifier - identifier placeholder, e.g. $identPlaceholder{}$, $identifierFoo{}$ +/// stmt, statement - statement placeholder, e.g. $stmtPlaceholder{}$, $statementFoo{}$ +/// type - type placeholder, e.g. $typePlaceholder{}$, $typeFoo{}$ +/// member - member placeholder, e.g. $memberPlaceholder{}$, $memberFoo{}$ +/// +/// +/// +/// Expression placeholder arguments: +/// +/// +/// expressionType - string value in single quotes, specifies full type name to match (empty string by +/// default) +/// +/// exactType - boolean value, specifies if expression should have exact type match (false by default) +/// +/// Examples: +/// +/// +/// $myExpr{Expression, 'Namespace.FooType', true}$ - defines expression placeholder, matching +/// expressions of the 'Namespace.FooType' type with exact matching. +/// +/// +/// $myExpr{Expression, 'Namespace.FooType'}$ - defines expression placeholder, matching expressions of +/// the 'Namespace.FooType' type or expressions which can be implicitly converted to 'Namespace.FooType'. +/// +/// $myExpr{Expression}$ - defines expression placeholder, matching expressions of any type. +/// +/// $exprFoo{'Namespace.FooType', true}$ - defines expression placeholder, matching expressions of the +/// 'Namespace.FooType' type with exact matching. +/// +/// +/// +/// +/// Type placeholder arguments: +/// +/// type - string value in single quotes, specifies full type name to match (empty string by default) +/// exactType - boolean value, specifies if expression should have exact type match (false by default) +/// +/// Examples: +/// +/// +/// $myType{Type, 'Namespace.FooType', true}$ - defines type placeholder, matching 'Namespace.FooType' +/// types with exact matching. +/// +/// +/// $myType{Type, 'Namespace.FooType'}$ - defines type placeholder, matching 'Namespace.FooType' types or +/// types, which can be implicitly converted to 'Namespace.FooType'. +/// +/// $myType{Type}$ - defines type placeholder, matching any type. +/// +/// $typeFoo{'Namespace.FooType', true}$ - defines types placeholder, matching 'Namespace.FooType' types +/// with exact matching. +/// +/// +/// +/// +/// Identifier placeholder arguments: +/// +/// +/// nameRegex - string value in single quotes, specifies regex to use for matching (empty string by +/// default) +/// +/// nameRegexCaseSensitive - boolean value, specifies if name regex is case sensitive (true by default) +/// type - string value in single quotes, specifies full type name to match (empty string by default) +/// exactType - boolean value, specifies if expression should have exact type match (false by default) +/// +/// Examples: +/// +/// +/// $myIdentifier{Identifier, 'my.*', false, 'Namespace.FooType', true}$ - defines identifier +/// placeholder, matching identifiers (ignoring case) starting with 'my' prefix with 'Namespace.FooType' +/// type. +/// +/// +/// $myIdentifier{Identifier, 'my.*', true, 'Namespace.FooType', true}$ - defines identifier placeholder, +/// matching identifiers (case sensitively) starting with 'my' prefix with 'Namespace.FooType' type. +/// +/// +/// $identFoo{'my.*'}$ - defines identifier placeholder, matching identifiers (case sensitively) starting +/// with 'my' prefix. +/// +/// +/// +/// +/// Statement placeholder arguments: +/// +/// minimalOccurrences - minimal number of statements to match (-1 by default) +/// maximalOccurrences - maximal number of statements to match (-1 by default) +/// +/// Examples: +/// +/// $myStmt{Statement, 1, 2}$ - defines statement placeholder, matching 1 or 2 statements. +/// $myStmt{Statement}$ - defines statement placeholder, matching any number of statements. +/// $stmtFoo{1, 2}$ - defines statement placeholder, matching 1 or 2 statements. +/// +/// +/// +/// Argument placeholder arguments: +/// +/// minimalOccurrences - minimal number of arguments to match (-1 by default) +/// maximalOccurrences - maximal number of arguments to match (-1 by default) +/// +/// Examples: +/// +/// $myArg{Argument, 1, 2}$ - defines argument placeholder, matching 1 or 2 arguments. +/// $myArg{Argument}$ - defines argument placeholder, matching any number of arguments. +/// $argFoo{1, 2}$ - defines argument placeholder, matching 1 or 2 arguments. +/// +/// +/// +/// Member placeholder arguments: +/// +/// +/// docId - string value in single quotes, specifies XML documentation id of the member to match (empty +/// by default) +/// +/// +/// Examples: +/// +/// +/// $myMember{Member, 'M:System.String.IsNullOrEmpty(System.String)'}$ - defines member placeholder, +/// matching 'IsNullOrEmpty' member of the 'System.String' type. +/// +/// +/// $memberFoo{'M:System.String.IsNullOrEmpty(System.String)'}$ - defines member placeholder, matching +/// 'IsNullOrEmpty' member of the 'System.String' type. +/// +/// +/// +/// +/// For more information please refer to the +/// +/// Structural +/// Search and Replace +/// +/// article. +/// +/// +[AttributeUsage( + AttributeTargets.Method + | AttributeTargets.Constructor + | AttributeTargets.Property + | AttributeTargets.Field + | AttributeTargets.Event + | AttributeTargets.Interface + | AttributeTargets.Class + | AttributeTargets.Struct + | AttributeTargets.Enum, + AllowMultiple = true, + Inherited = false)] +public sealed class CodeTemplateAttribute : Attribute +{ + public CodeTemplateAttribute(string searchTemplate) + { + SearchTemplate = searchTemplate; + } + + /// + /// Structural search pattern to use in the code template. + /// Pattern includes textual part, which must contain only identifiers allowed in the target language, + /// and placeholders, which allow matching variable parts of the target code blocks. + /// + public string SearchTemplate { get; } + + /// + /// Message to show when the search pattern was found. + /// You can also prepend the message text with "Error:", "Warning:", "Suggestion:" or "Hint:" prefix to specify the + /// pattern severity. + /// Code patterns with replace template produce suggestions by default. + /// However, if replace template is not provided, then warning severity will be used. + /// + public string Message { get; set; } + + /// + /// Structural search replace pattern to use in code template replacement. + /// + public string ReplaceTemplate { get; set; } + + /// + /// Replace message to show in the light bulb. + /// + public string ReplaceMessage { get; set; } + + /// + /// Apply code formatting after code replacement. + /// + public bool FormatAfterReplace { get; set; } = true; + + /// + /// Whether similar code blocks should be matched. + /// + public bool MatchSimilarConstructs { get; set; } + + /// + /// Automatically insert namespace import directives or remove qualifiers that become redundant after the template is + /// applied. + /// + public bool ShortenReferences { get; set; } + + /// + /// String to use as a suppression key. + /// By default the following suppression key is used 'CodeTemplate_SomeType_SomeMember', + /// where 'SomeType' and 'SomeMember' are names of the associated containing type and member to which this attribute is + /// applied. + /// + public string SuppressionKey { get; set; } +} \ No newline at end of file diff --git a/WAIUA/Properties/Resources.Designer.cs b/WAIUA/Properties/Resources.Designer.cs index 6b05fbe5..bc6e0579 100644 --- a/WAIUA/Properties/Resources.Designer.cs +++ b/WAIUA/Properties/Resources.Designer.cs @@ -60,6 +60,15 @@ internal Resources() { } } + /// + /// Looks up a localized string similar to Account. + /// + public static string Account { + get { + return ResourceManager.GetString("Account", resourceCulture); + } + } + /// /// Looks up a localized string similar to Made By Soneliem. /// @@ -178,11 +187,20 @@ public static string Error { } /// - /// Looks up a localized string similar to You're on this page idiot. + /// Looks up a localized string similar to High Score:. + /// + public static string HighScore { + get { + return ResourceManager.GetString("HighScore", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Home. /// - public static string InfoExplanation { + public static string Home { get { - return ResourceManager.GetString("InfoExplanation", resourceCulture); + return ResourceManager.GetString("Home", resourceCulture); } } @@ -223,29 +241,20 @@ public static string Latestversion { } /// - /// Looks up a localized string similar to Loads live match data if available. This should take less than 10 seconds. - /// - public static string LoadMatchExplanation { - get { - return ResourceManager.GetString("LoadMatchExplanation", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Load Match. + /// Looks up a localized string similar to Login. /// - public static string LoadMatchTitle { + public static string Login { get { - return ResourceManager.GetString("LoadMatchTitle", resourceCulture); + return ResourceManager.GetString("Login", resourceCulture); } } /// - /// Looks up a localized string similar to Login. + /// Looks up a localized string similar to Match. /// - public static string Login { + public static string Match { get { - return ResourceManager.GetString("Login", resourceCulture); + return ResourceManager.GetString("Match", resourceCulture); } } @@ -267,6 +276,33 @@ public static string NoValGame { } } + /// + /// Looks up a localized string similar to Player. + /// + public static string Player { + get { + return ResourceManager.GetString("Player", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Queue Time:. + /// + public static string QueueTime { + get { + return ResourceManager.GetString("QueueTime", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Refresh. + /// + public static string Refresh { + get { + return ResourceManager.GetString("Refresh", resourceCulture); + } + } + /// /// Looks up a localized string similar to Refreshing.... /// @@ -276,6 +312,15 @@ public static string Refreshing { } } + /// + /// Looks up a localized string similar to Refreshing In:. + /// + public static string RefreshingIn { + get { + return ResourceManager.GetString("RefreshingIn", resourceCulture); + } + } + /// /// Looks up a localized string similar to Click To Refresh Match. /// @@ -286,20 +331,20 @@ public static string RefreshMatch { } /// - /// Looks up a localized string similar to Select Language. + /// Looks up a localized string similar to Score:. /// - public static string SelLanguageTitle { + public static string Score { get { - return ResourceManager.GetString("SelLanguageTitle", resourceCulture); + return ResourceManager.GetString("Score", resourceCulture); } } /// - /// Looks up a localized string similar to Find app and account settings here. + /// Looks up a localized string similar to Select Language. /// - public static string SettingsExplanation { + public static string SelLanguageTitle { get { - return ResourceManager.GetString("SettingsExplanation", resourceCulture); + return ResourceManager.GetString("SelLanguageTitle", resourceCulture); } } @@ -339,6 +384,24 @@ public static string SponsorsTitle { } } + /// + /// Looks up a localized string similar to Start Aim Trainer. + /// + public static string StartTrainer { + get { + return ResourceManager.GetString("StartTrainer", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Status. + /// + public static string Status { + get { + return ResourceManager.GetString("Status", resourceCulture); + } + } + /// /// Looks up a localized string similar to Open Tracker.gg Profile. /// @@ -356,5 +419,23 @@ public static string Translator { return ResourceManager.GetString("Translator", resourceCulture); } } + + /// + /// Looks up a localized string similar to Valorant. + /// + public static string Valorant { + get { + return ResourceManager.GetString("Valorant", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Your Party. + /// + public static string YourParty { + get { + return ResourceManager.GetString("YourParty", resourceCulture); + } + } } } diff --git a/WAIUA/Properties/Resources.ar.resx b/WAIUA/Properties/Resources.ar.resx index f91e5e43..4f4fa596 100644 --- a/WAIUA/Properties/Resources.ar.resx +++ b/WAIUA/Properties/Resources.ar.resx @@ -117,106 +117,130 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - حمِّل المُباراة - - - من المفترض ان يحمل بِأقل من عشر ثواني - - معلومات - - - انت على هذه الصفحة غبي… + ملاحظة - ادخل على الديسكورد سيرفر + انضم الى الديسكورد - للمساعدة + للمساعدة، الخ... - مصنوع من Soneliem + صُنع بواسطة Soneliem - احدث اصدار: + أحدث اصدار: - الاصدار الحالي: + الإصدار الحالي: - تأكد لاصدارات حديثة + تحقق من وجود تحديث تسجيل الدخول - تتم جميع الاتصالات المتعلقة ببيانات الاعتماد الخاصة بك مباشرةً مع خوادم ريُت دون تخزين كلمات المرور محليًا أو عبر الإنترنت + جميع المعاملات بخصوص معلومات تسجيل الدخول الخاصة بك تحدث مباشرة من خلال خوادم رايوت، حيث لا يتم تخزين او حفظ اي معلومات خاصة بك. - حالة المصادقة + حالة المصاقة - ادغط تحت لتّحديث + انقر أدناه للنحديث - -تحقق من المصادقة + تحقق من المصادقة - مُسَدق ك: + تمت المصادقة كـ: - الدخول الاوتوماتيكي + تسجيل الدخول التلقائي - ملاحظة: فالورانت يجب ان تكون مفتوحة لِكي يشتغل + ملاحظة: يجب تشغيل فالورانت حتى يعمل هذا - ليسَ موثوق + غير مُصدق - مترجم لللغة العربية من Chica#8321 + تمت الترجمة للغة العربية بواسطة hafyzwithawhy و Chica - ادغط لتحديث المباراة - - - ابحث عن إعدادات التطبيق والحساب هنا + انقر لتحديث المباراة - اعدادات + الإعدادات - تسمح هذه الصفحة تسجيل الدخول يدويًا وتغيير لغة التطبيق وما إلى ذلك. + هذه الصفحة تسمح لك بتسجيل الدخول يدويا، تغيير لغة البرنامج، الخ... - اختر اللغة - - + اختر اللغة خطأ - يحدث... + يتم التحديث... - لا مباراة موجودة... + لم يتم الكشف عن أية مباراة - افتح فالورانت أولًا + الرجاء فتح فالورانت أولا - افتح الملف الشخصي لtracker.gg + افتح الملف الشخصي لـ tracker.gg - تأكد من المحتوى الذي تم تنزيله + تحقق من المحتوى الذي تم تنزيله - تحديث بالغصب + فرض التحديث - المبادرون + الداعمين + + + الصفحة الرئيسية + + + تحديث + + + الحساب + + + المباراة + + + الحالة + + + فالورانت + + + المجموعة + + + وقت الوصول المقدر: + + + سيتم التحديث خلال: + + + النقاط: + + + أعلى نقاط: + + + ابدأ إحماء التصويب + + + اللاعب \ No newline at end of file diff --git a/WAIUA/Properties/Resources.da.resx b/WAIUA/Properties/Resources.da.resx new file mode 100644 index 00000000..e65d4cfb --- /dev/null +++ b/WAIUA/Properties/Resources.da.resx @@ -0,0 +1,246 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Info + + + Min Discord + + + Til støtte, osv. + + + Lavet af Soneliem + + + Seneste version: + + + Nuværende version: + + + Søg efter opdateringer + + + Login + + + Alt kommunikation vedrørende dine login/kodeord kører direkte igennem Riot servere med ingen lagring af dit login/kodeord lokalt eller online. + + + Autenticitet Status + + + Tryk herunder for at opdatere + + + Check Autenticitet + + + Autentificerede som: + + + Auto Login + + + Note: Valorant skal køre for at dette skal virke + + + Ikke Autentificerede + + + Oversat til dansk af r3verse + + + Tryk for at Opdatere Kampen + + + Indstillinger + + + Denne side lader dig logge ind manuelt, ændre app sproget, osv. + + + Vælg Sprog + + + Fejl + + + Genopfrisker... + + + Ingen Kamp Fundet + + + Vær sød at åbne Valorant Først + + + Åben Tracker.gg Profil + + + Check downloadet indhold + + + Gennemtving Opdatering + + + Sponsorater + + + Hjem + + + Genfrisk + + + Konto + + + Kamp + + + Status + + + Valorant + + + Dit Party + + + Queue Tid: + + + Genopfriskning om: + + + Score: + + + Rekord: + + + Start Aim Træning + + + Spiller + + \ No newline at end of file diff --git a/WAIUA/Properties/Resources.de.resx b/WAIUA/Properties/Resources.de.resx index 7c4c5422..5ccd69e1 100644 --- a/WAIUA/Properties/Resources.de.resx +++ b/WAIUA/Properties/Resources.de.resx @@ -117,18 +117,9 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - Lade Match - - - Lad die Matchdaten, wenn verfügbar. Dies sollte weniger als 10 Sekunden dauern - Info - - Du bist auf dieser Seite - Tritt dem Discord bei @@ -152,7 +143,6 @@ Es werden keine Anmeldedaten gespeichert. Die Zugangsdaten werden für die direkte Kommunikation mit den Riot-Servern verwendet. - Fuzzy Anmelde Status @@ -182,9 +172,6 @@ Hier klicken, um Matchdaten neu zu laden - - Hier Findest du die App und Account Einstellungen - Einstellungen @@ -219,4 +206,44 @@ Sponsoren + + Startseite + + + Neu laden + + + Account + + + Match + + + Status + + + Valorant + + + Deine Gruppe + + + Queue Zeit: + + + Aktualisiert in: + + + Punkte: + + + Highscore: + there is literally no german word for this that doesn't sound stupid, everybody says highscore. + + + Aim Trainer Starten + + + Spieler + \ No newline at end of file diff --git a/WAIUA/Properties/Resources.en.resx b/WAIUA/Properties/Resources.en.resx index 57366a14..45959b75 100644 --- a/WAIUA/Properties/Resources.en.resx +++ b/WAIUA/Properties/Resources.en.resx @@ -117,18 +117,9 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - Load Match - - - Loads live match data if available. This should take less than 10 seconds - Info - - You're on this page idiot - Join my Discord @@ -139,10 +130,10 @@ Made By Soneliem - Latest Version: + Latest Version: - Current Version: + Current Version: Check for Updates @@ -176,13 +167,11 @@ Translated into English By Soneliem + Fuzzy Click To Refresh Match - - Find app and account settings here - Settings @@ -216,4 +205,43 @@ Sponsors + + Home + + + Refresh + + + Account + + + Match + + + Status + + + Valorant + + + Your Party + + + Queue Time: + + + Refreshing In: + + + Score: + + + High Score: + + + Start Aim Trainer + + + Player + \ No newline at end of file diff --git a/WAIUA/Properties/Resources.es.resx b/WAIUA/Properties/Resources.es.resx index 16f5cfd7..46ba86bb 100644 --- a/WAIUA/Properties/Resources.es.resx +++ b/WAIUA/Properties/Resources.es.resx @@ -117,18 +117,9 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - Cargar Partida - - - Cargar los datos de partida en vivo si están disponibles. Debería tomar menos de 10 segundos. - Información - - Ya estás en esta página, idiota - Únete a mi Discord @@ -180,9 +171,6 @@ Haz clic aquí para actualizar el partido - - Aquí se encuentra la configuración de la aplicación y de cuenta - Configuración @@ -216,4 +204,43 @@ Sponsors + + Home + + + Refresh + + + Account + + + Match + + + Status + + + Valorant + + + Your Party + + + Queue Time: + + + Refreshing In: + + + Score: + + + High Score: + + + Start Aim Trainer + + + Player + \ No newline at end of file diff --git a/WAIUA/Properties/Resources.fa.resx b/WAIUA/Properties/Resources.fa.resx new file mode 100644 index 00000000..fd6f31d6 --- /dev/null +++ b/WAIUA/Properties/Resources.fa.resx @@ -0,0 +1,246 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + اطلاعات + + + به دیسکورد من متصل شوید + + + پشتیبانی, و غیره. + + + درست شده توسط Soneliem + + + جدیدترین ورژن: + + + ورژن فعلی: + + + بررسی برای به روز رسانی + + + وارد شوید + + + تمام ارتباطات مربوط به اعتبار شما مستقیما توسط سرور Riot بدون ذخیره رمز عبوردر کامپیوتر یا آنلاین انجام شده است. + + + بررسی وضعیت هویت + + + برای به روز رسانی در پایین کلیک کنید + + + بررسی برای هویت + + + هویت شما + + + بصورت خودکار وارد شوید + + + توجه: ولورانت باید باز باشد تا کار کند + + + هویت مشخص نیست + + + ترجمه شده به فارسی توسط 1798#Kourosh + + + برای تازه کردن مسابقه اینجا کلیک کنید + + + تنظیمات + + + این صفحه به شما اجازه میدهد که به صورت دستی وارد شوید, زبان برنامه را تغییردهید, و غیره + + + زبان را انتخاب کنید + + + خطا + + + در حال تازه کردن... + + + هیچ بازی یافت نشد + + + لطفا ابتدا ولورانت را باز کنید + + + مشخصات Tracker.gg را باز کنید + + + محتوای دانلود را بررسی کنید + + + به اجبار به روز رسانی کنید + + + حامیان مالی + + + خانه + + + تازه کنید + + + حساب + + + بازی + + + وضعیت + + + ولورانت + + + گروه شما + + + زمان صف: + + + تازه کردن در: + + + امتیاز: + + + بالاترین امتیاز: + + + آموزش هدف گیری را شروع کنید + + + بازیکن + + \ No newline at end of file diff --git a/WAIUA/Properties/Resources.fr.resx b/WAIUA/Properties/Resources.fr.resx index 02a38fc3..badbfc71 100644 --- a/WAIUA/Properties/Resources.fr.resx +++ b/WAIUA/Properties/Resources.fr.resx @@ -117,18 +117,9 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - Charger Match - - - Charge les données du match actuel si disponible. Cela devrait prendre moins de 10 secondes - Info - - Vous êtes sur cette page idiot - Rejoignez notre Discord @@ -139,13 +130,13 @@ Fait par Soneliem - Dernière Version: + Dernière version: - Version Actuelle: + Version actuelle: - Rechercher des Mises à Jour + Rechercher des mises à jour Connexion @@ -154,13 +145,13 @@ Toute communication de vos identifiants sont faits directement avec les serveurs Riot sans aucun stockage de mots de passe localement ou en ligne. - Statut Authentification + Statut authentification Cliquer ci-dessous pour mettre à jour - Vérifier Authentification + Vérifier authentification Authentifié comme: @@ -172,16 +163,13 @@ Note: Valorant doit être en cours d'exécution pour que cela fonctionne - Non Authentifié + Non authentifié - Traduit en Français Par Rayjacker + Traduit en Français par Rayjacker - Cliquer Pour Rafraîchir le Match - - - Trouvez les paramètres de l'application et de compte ici + Cliquer ici pour rafraîchir le match Paramètres @@ -190,7 +178,7 @@ Cette page vous permet de vous connecter, changer la langue de l'appli, etc. - Sélectionner Language + Sélectionner le language Erreur @@ -199,21 +187,60 @@ Rafraîchissement... - Aucun Match Détecté + Aucun match détecté Merci d'ouvrir Valorant d'abord - Ouvrir le Profil Tracker.gg + Ouvrir le profil Tracker.gg - Vérifier Contenu Téléchargé + Vérifier le contenu téléchargé - Forcer Mise à Jour + Forcer une mise à jour Sponsors + + Accueil + + + Rafraîchir + + + Compte + + + Match + + + Statut + + + Valorant + + + Votre groupe + + + Temps queue: + + + Rafraîchissement dans: + + + Score: + + + Meilleur Score: + + + Commencer l'exercice de visée + + + Joueur + \ No newline at end of file diff --git a/WAIUA/Properties/Resources.hi.resx b/WAIUA/Properties/Resources.hi.resx index 9aa14944..d1a2cc42 100644 --- a/WAIUA/Properties/Resources.hi.resx +++ b/WAIUA/Properties/Resources.hi.resx @@ -117,18 +117,9 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - लोड मैच - - - यदि उपलब्ध हो तो Live match डेटा लोड करता है।. इसमें 10 सेकंड से कम समय लगना चाहिए - जानकारी - - इस ही पेज पर हो बेवकुफ - मेरे Discord से जुड़ें @@ -180,9 +171,6 @@ मैच को ताज़ा करने के लिए क्लिक करें - - यहां app और account सेटिंग ढूंढें - सेटिंग @@ -216,4 +204,43 @@ स्पॉन्सर + + घर + + + ताज़ा + + + खाता + + + Match + + + दर्जा + + + Valorant + + + आपकी टोली + + + कतार का समय + + + Refreshing In: + + + स्कोर: + + + हाईस्कोर: + + + Aim Trainer शुरू करें + + + खिलाड़ी + \ No newline at end of file diff --git a/WAIUA/Properties/Resources.it.resx b/WAIUA/Properties/Resources.it.resx index 33d16d00..29b1e0cb 100644 --- a/WAIUA/Properties/Resources.it.resx +++ b/WAIUA/Properties/Resources.it.resx @@ -117,23 +117,14 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - Caricamento partita - - - Caricamendo informazioni partita diretta se disponibile. Dovrebbe richiedere meno di 10 secondi - - Info - - - Sei su questa pagina idiota + Informazioni Entra sul mio Discord - Per aiuto, eccetera. + Per supporto, eccetera. Creato da Soneliem @@ -145,19 +136,19 @@ Versione attuale: - Verifica i tuoi aggiornamenti + Verifica se ci sono aggiornamenti - Login + Accesso - Tutte le comunicazioni riguardanti le tue credenziali sono effettuate direttamente con i server Riot con nessuna memorizzazzione delle password effettuata localmente o online. + Tutte le comunicazioni riguardanti le tue credenziali sono effettuate direttamente con i server Riot con nessuna memorizzazione delle password effettuata localmente o online. - Stato di autenticazione + Stato dell'autenticazione - Clicca sotto per aggiornare + Clicca qui sotto per aggiornare Verifica autenticazione @@ -166,54 +157,90 @@ Autenticato come: - Auto login + Accesso Automatico - Nota: Valorant deve essere avviato per fare in modo che ciò possa funzionare + Nota: Valorant deve essere avviato per fare in modo che questo possa funzionare Non autenticato - Tradotto in italiano da SimpleBonsai + Tradotto in italiano da CyberKoreTv - Clicca per riaggiornare la tua partita - - - Qui potrai trovare le impostazioni del tuo account + Clicca per aggiornare la tua partita Impostazioni - Questa pagina ti permette di fare il sign manualmente, cambiare la lingua dell'app, eccetera. + Questa pagina ti permette di fare l'accesso manualmente, cambiare la lingua dell'app, eccetera. - Selezionare linguaggio + Seleziona lingua Errore - Aggiornando... + Sto Aggiornando... Nessuna partita rilevata - Per favore, avvia Valorant in primo luogo + Per favore, prima avvia Valorant Apri Profilo Tracker.gg - Check Downloaded Content + Controllo download contenuti - Force Update + Forza Aggiornamento - Sponsors + Sponsor + + + Home + + + Aggiorna + + + Account + + + Partita + + + Stato + + + Valorant + + + Il tuo Party + + + Tempo Coda + + + Aggiorno in: + + + Punteggio + + + Mio record + + + Avvia Aim trainer + + + Giocatore \ No newline at end of file diff --git a/WAIUA/Properties/Resources.ja.resx b/WAIUA/Properties/Resources.ja.resx index cd62ad98..65cbd5ea 100644 --- a/WAIUA/Properties/Resources.ja.resx +++ b/WAIUA/Properties/Resources.ja.resx @@ -117,18 +117,9 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - 試合をロード - - - 可能であれば試合のデータをロードします。10秒以内には終わるはずです。 - 情報 - - このページだよバーカ - Discordに参加 @@ -180,9 +171,6 @@ クリックで試合を更新 - - アプリとアカウントの設定 - 設定 @@ -216,4 +204,43 @@ スポンサー + + Home + + + Refresh + + + Account + + + Match + + + Status + + + Valorant + + + Your Party + + + Queue Time: + + + Refreshing In: + + + Score: + + + High Score: + + + Start Aim Trainer + + + Player + \ No newline at end of file diff --git a/WAIUA/Properties/Resources.ko.resx b/WAIUA/Properties/Resources.ko.resx new file mode 100644 index 00000000..753e74bb --- /dev/null +++ b/WAIUA/Properties/Resources.ko.resx @@ -0,0 +1,246 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 정보 + + + 디스코드 들어오기 + + + 도움이 필요하거나 문제있으면 디스코드 들어오세요. + + + 개발자 Soneliem + + + 가장 최근 버전: + + + 현재 버전: + + + 업데이트있는지 체크하기 + + + 로그인 + + + 이 엡은 라이엇 서버에서 불러오는걸로 비밀번호나 게인정보를 수집하지 않습니다. + + + 엡 인증 상태 + + + 업데이트할려면 클릭 + + + 인증 체크 + + + 인증: + + + 자동 로그인 + + + 주의: WAIUA를 사용할려면 발로란트가 실행중이어야 합니다. + + + 인증 실패 + + + 한국어 변역 ramon + + + 게임 새로고침하기 + + + 설정 + + + 이 페이지에서는 로그인과, 엡에 언어를 바꾸고, 다른 많은것들을 할수있습니다. + + + 언어를 선택해주세요 + + + 오류 + + + 새로고침중... + + + 현재 진행되고 있는 게임이 없습니다 + + + 발로란트를 먼저 실행해주세요 + + + Tracker.gg 프로필 체크하기 + + + 다운로드된 콘탠츠 체크하기 + + + 강제 업데이트 + + + 스폰서 + + + 메인 + + + 새로고침 + + + 계정 + + + 메치 + + + 상태 + + + 발로란트 + + + 파티 + + + 대전 찾는시간: + + + 새로고침까지 시간: + + + Score: + + + High Score: + + + Start Aim Trainer + + + Player + + \ No newline at end of file diff --git a/WAIUA/Properties/Resources.nl.resx b/WAIUA/Properties/Resources.nl.resx new file mode 100644 index 00000000..c47f7fa1 --- /dev/null +++ b/WAIUA/Properties/Resources.nl.resx @@ -0,0 +1,246 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Info + + + Volg mijn Discord + + + Voor hulp, etc. + + + Gemaakt door Soneliem + + + Laatste Versie: + + + Huidige Versie: + + + Controleer op Updates + + + Aanmelden + + + Alle communicatie betreffende jouw aanmeldgegevens gaat rechtstreeks naar de Riot servers zonder opslag van jouw paswoord lokaal of online. + + + Authenticatie Status + + + Klik hieronder om te updaten + + + Controleer Authenticatie + + + Geauthenticeerd als: + + + Automatisch Aanmelden + + + Notitie: Valorant moet geopend zijn voordat dit werkt + + + Niet Geauthenticeerd + + + Vertaald in het Nederlands door Jeff + + + Klik om Match te Herladen + + + Instellingen + + + Deze pagina laat jou manueel aanmelden, de applicatie taal veranderen, etc. + + + Selecteer Taal + + + Fout + + + Herladen... + + + Geen Spel Gevonden + + + Open Valorant eerst AUB + + + Open Tracker.gg Profiel + + + Controleer gedownloade inhoud + + + Update Forceren + + + Sponsoren + + + Startpagina + + + Herladen + + + Account + + + Spel + + + Status + + + Valorant + + + Jouw Party + + + Wachttijd: + + + Herladen In: + + + Score: + + + Hoogste Score: + + + Start Aim Training + + + Speler + + \ No newline at end of file diff --git a/WAIUA/Properties/Resources.pt.resx b/WAIUA/Properties/Resources.pt.resx index e0d666d7..3d328087 100644 --- a/WAIUA/Properties/Resources.pt.resx +++ b/WAIUA/Properties/Resources.pt.resx @@ -117,18 +117,9 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - Carregar Partida - - - Carrega dados ao vivo da partida, se disponível. Isso deve levar menos de 10 segundos - Info - - Você tá nessa página, idiota - Entre no meu Discord @@ -145,22 +136,22 @@ Versão atual: - Checar por autalizações + Procurar por autalizações Login - Toda comunicação em relação à suas credenciais é feita diretamente com os servidores da Riot com nenhuma senha armazenada localmente ou online. + Toda comunicação em relação às suas credenciais é feita diretamente com os servidores da Riot e nenhuma senha é armazenada localmente ou online. - Status de autenticação + Estado de autenticação Clique abaixo para atualizar - Checar autenticação + Verificar autenticação Autenticado como: @@ -169,25 +160,22 @@ Login automático - Nota: O Valorant precisa estar rodando pra esse programa funcionar + Nota: O Valorant precisa estar aberto para funcionar Não autenticado - Traduzido pro Português por janinha + Traduzido para Português por castrom4 e janinha Clique para recarregar a partida - - Encontre as definições do app e conta aqui - Definições - Essa página te deixa logar manualmente, mudar o idioma, etc. + Esta página deixa-te fazer o login manualmente, mudar o idioma, etc. Selecionar idioma @@ -196,7 +184,7 @@ Erro - Recarregando.. + Atualizando... Nenhuma partida detectada @@ -208,12 +196,51 @@ Abrir perfil do tracker.gg - Check Downloaded Content + Verificar conteúdo descarregado - Force Update + Forçar atualização - Sponsors + Patrocinadores + + + Início + + + Atualizar + + + Conta + + + Partida + + + Estado + + + Valorant + + + O teu grupo + + + Tempo de espera: + + + Atualiza em: + + + Score: + + + High Score: + + + Start Aim Trainer + + + Player \ No newline at end of file diff --git a/WAIUA/Properties/Resources.resx b/WAIUA/Properties/Resources.resx index 92f7fdb8..9e184906 100644 --- a/WAIUA/Properties/Resources.resx +++ b/WAIUA/Properties/Resources.resx @@ -117,18 +117,9 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - Load Match - - - Loads live match data if available. This should take less than 10 seconds - Info - - You're on this page idiot - Join my Discord @@ -180,9 +171,6 @@ Settings - - Find app and account settings here - Select Language @@ -216,4 +204,43 @@ Sponsors + + Home + + + Your Party + + + Valorant + + + Match + + + Account + + + Status + + + Refresh + + + Queue Time: + + + Refreshing In: + + + Player + + + Start Aim Trainer + + + High Score: + + + Score: + \ No newline at end of file diff --git a/WAIUA/Properties/Resources.ru.resx b/WAIUA/Properties/Resources.ru.resx index 25453050..cb24e9fd 100644 --- a/WAIUA/Properties/Resources.ru.resx +++ b/WAIUA/Properties/Resources.ru.resx @@ -117,18 +117,9 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - Загрузить матч - - - Загружает данные о матчах в реальном времени, если таковые имеются. Это должно занять менее 10 секунд. - Информация - - Ты уже на этой странице, идиот - Присоединяйтесь к моему дискорд серверу @@ -180,9 +171,6 @@ Нажмите, чтобы обновить матч - - Настройки приложения и учетной записи можно найти здесь - Настройки @@ -216,4 +204,43 @@ Sponsors + + Home + + + Refresh + + + Account + + + Match + + + Status + + + Valorant + + + Your Party + + + Queue Time: + + + Refreshing In: + + + Score: + + + High Score: + + + Start Aim Trainer + + + Player + \ No newline at end of file diff --git a/WAIUA/Properties/Resources.sr.resx b/WAIUA/Properties/Resources.sr.resx new file mode 100644 index 00000000..b55a403e --- /dev/null +++ b/WAIUA/Properties/Resources.sr.resx @@ -0,0 +1,246 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Informacije + + + Uđi u moj discord + + + Za podršku, itd. + + + Napravio: Soneliem + + + Najnovija verzija + + + Trenutna verzija + + + Proveriti ažuriranja + + + Prijavite se + + + Sve komunikacije u pogledu tvojih akreditiva obavlja se direktno sa Riot serverima bez skladištenja lozinki lokalno ili onlajn. + + + Status autentikacije + + + Kliknite ispod da biste ažurirali + + + Proverite autentifikaciju + + + Autentifikovan kao: + + + Automatsko prijavljivanje + + + Napomena: Valorant treba da je pokrenut kako bi ovo radilo + + + Nije autentifikovan + + + Prevedeno na Engleski od strane Soneliem + + + Klikni da osvežiš meč + + + Podešavanja + + + Ova stranica vam omogućava da se ručno prijavite, da promenite jezik aplikacije, itd. + + + Izaberite jezik + + + Greška + + + Osveživanje + + + Meč nije otkriven + + + Molim vas prvo otvorite Valorant + + + Otvorite tracker.gg profil + + + Proverite preuzeti sadržaj + + + Prisilno ažuriranje + + + Sponzori + + + Kuća + + + Osvežite + + + Nalog + + + Meč + + + Status + + + Valorant + + + Tvoja grupa + + + Vreme queue-a + + + Osvežavanje za: + + + Ocena: + + + Najviša ocena: + + + Započnite aim trening + + + Igrač + + \ No newline at end of file diff --git a/WAIUA/Properties/Resources.vi.resx b/WAIUA/Properties/Resources.vi.resx new file mode 100644 index 00000000..27057d2f --- /dev/null +++ b/WAIUA/Properties/Resources.vi.resx @@ -0,0 +1,246 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Thông tin + + + Gia nhập Discord + + + Ủng hộ chúng tôi + + + Tác giả Soneliem + + + Phiên bản mới nhất: + + + Phiên bản hiện tại: + + + Kiểm tra cập nhật + + + Đăng nhập + + + Tất cả dữ liệu về tài khoản sẽ được chuyển trực tiếp về máy chủ Riot, ứng dụng và tác giả không lưu trữ bất kỳ thông tin nào về tài khoản của bạn. + + + Tình trạng xác thực + + + Nhấn nút bên dưới để cập nhật + + + Kiểm tra tình trạng xác thực + + + Đăng nhập dưới tên: + + + Tự động đăng nhập + + + Chú ý: Tính năng này cần phải bật Valorant trước + + + Xác thực thất bại + + + Dịch sang tiếng Việt bởi Ozymo + + + Làm mới ngay + + + Cài đặt + + + Trang này dùng để đăng nhập thủ công, thay đổi ngôn ngữ,... + + + Chọn ngôn ngữ + + + Lỗi + + + Đang làm mới + + + Không tìm thấy trận đấu + + + Hãy mở Valorant trước + + + Mở hồ sơ Tracker.gg + + + Kiểm tra các nội dung đã tải + + + Buộc cập nhật + + + Những người ủng hộ + + + Trang chủ + + + Làm mới + + + Tài khoản + + + Trận đấu + + + Trạng thái + + + Valorant + + + Tổ đội của bạn + + + Đang tìm trận: + + + Làm mới trong: + + + Điểm: + + + Điểm cao nhất: + + + Bắt đầu luyện aim + + + Người chơi + + \ No newline at end of file diff --git a/WAIUA/Properties/Resources.zh.resx b/WAIUA/Properties/Resources.zh.resx new file mode 100644 index 00000000..9f84c983 --- /dev/null +++ b/WAIUA/Properties/Resources.zh.resx @@ -0,0 +1,246 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 质询 + + + 加入我的Discord + + + 为寻求帮助,其他。 + + + 作者是Soneliem + + + 最新版本 + + + 目前版本 + + + 检查更新 + + + 登录 + + + 所有您的信息是直接通过RIOT服务器的,不会在本地或网上储存密码。 + + + 登录状态 + + + 点击下面来更新 + + + 检查登录状态 + + + 登录为: + + + 自动登录 + + + 注: 需特战英豪为运行中才有用 + + + 未登录 + + + Translated into Chinese By zDragone + + + 点击以更新比赛 + + + 设置 + + + 这个页面会让你手动登录,切换软件语言,其他。 + + + 选择语言 + + + 错误 + + + 更新中... + + + 没检测到比赛 + + + 请先运行特战英豪 + + + 打开 tracker.gg 账号 + + + 检查下载过的内容 + + + 强制更新 + + + 赞助 + + + 主页 + + + 刷新 + + + 账号 + + + 比赛 + + + 状况 + + + 特战英豪 + + + 你的团队 + + + 排队时间: + + + 刷新中。。。 + + + Score: + + + High Score: + + + Start Aim Trainer + + + Player + + \ No newline at end of file diff --git a/WAIUA/Properties/Settings.Designer.cs b/WAIUA/Properties/Settings.Designer.cs index 093bbc92..00e242b3 100644 --- a/WAIUA/Properties/Settings.Designer.cs +++ b/WAIUA/Properties/Settings.Designer.cs @@ -12,7 +12,7 @@ namespace WAIUA.Properties { [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.0.3.0")] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.2.0.0")] public sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); @@ -25,73 +25,25 @@ public static Settings Default { [global::System.Configuration.UserScopedSettingAttribute()] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Configuration.DefaultSettingValueAttribute("0")] - public double Left { + [global::System.Configuration.DefaultSettingValueAttribute("")] + public string Language { get { - return ((double)(this["Left"])); + return ((string)(this["Language"])); } set { - this["Left"] = value; + this["Language"] = value; } } [global::System.Configuration.UserScopedSettingAttribute()] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Configuration.DefaultSettingValueAttribute("0")] - public double Top { - get { - return ((double)(this["Top"])); - } - set { - this["Top"] = value; - } - } - - [global::System.Configuration.UserScopedSettingAttribute()] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Configuration.DefaultSettingValueAttribute("1536")] - public double Width { - get { - return ((double)(this["Width"])); - } - set { - this["Width"] = value; - } - } - - [global::System.Configuration.UserScopedSettingAttribute()] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Configuration.DefaultSettingValueAttribute("754")] - public double Height { + public int AimScore { get { - return ((double)(this["Height"])); + return ((int)(this["AimScore"])); } set { - this["Height"] = value; - } - } - - [global::System.Configuration.UserScopedSettingAttribute()] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Configuration.DefaultSettingValueAttribute("Maximized")] - public string WindowState { - get { - return ((string)(this["WindowState"])); - } - set { - this["WindowState"] = value; - } - } - - [global::System.Configuration.UserScopedSettingAttribute()] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Configuration.DefaultSettingValueAttribute("")] - public string Language { - get { - return ((string)(this["Language"])); - } - set { - this["Language"] = value; + this["AimScore"] = value; } } } diff --git a/WAIUA/Properties/Settings.settings b/WAIUA/Properties/Settings.settings index f63987b5..6cd7e84f 100644 --- a/WAIUA/Properties/Settings.settings +++ b/WAIUA/Properties/Settings.settings @@ -1,25 +1,12 @@  - - - - - 0 - - - 0 - - - 1536 - - - 754 - - - Maximized - - - - - + + + + + + + + 0 + + \ No newline at end of file diff --git a/WAIUA/Properties/launchSettings.json b/WAIUA/Properties/launchSettings.json index b4947d3e..5beab976 100644 --- a/WAIUA/Properties/launchSettings.json +++ b/WAIUA/Properties/launchSettings.json @@ -1,7 +1,7 @@ { - "profiles": { - "WAIUA": { - "commandName": "Project" - } - } + "profiles": { + "WAIUA": { + "commandName": "Project" + } + } } \ No newline at end of file diff --git a/WAIUA/Settings.cs b/WAIUA/Settings.cs new file mode 100644 index 00000000..8bd2877a --- /dev/null +++ b/WAIUA/Settings.cs @@ -0,0 +1,22 @@ +using System.ComponentModel; +using System.Configuration; + +namespace WAIUA.Properties; + +// This class allows you to handle specific events on the settings class: +// The SettingChanging event is raised before a setting's value is changed. +// The PropertyChanged event is raised after a setting's value is changed. +// The SettingsLoaded event is raised after the setting values are loaded. +// The SettingsSaving event is raised before the setting values are saved. +public sealed partial class Settings +{ + private void SettingChangingEventHandler(object sender, SettingChangingEventArgs e) + { + // Add code to handle the SettingChangingEvent event here. + } + + private void SettingsSavingEventHandler(object sender, CancelEventArgs e) + { + // Add code to handle the SettingsSaving event here. + } +} \ No newline at end of file diff --git a/WAIUA/ValAPI/ValAPI.cs b/WAIUA/ValAPI/ValAPI.cs deleted file mode 100644 index 487e92c6..00000000 --- a/WAIUA/ValAPI/ValAPI.cs +++ /dev/null @@ -1,192 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.IO; -using System.Linq; -using System.Net; -using System.Reflection; -using System.Threading.Tasks; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; -using RestSharp; -using WAIUA.Properties; - -namespace WAIUA.ValAPI -{ - public class ValAPI - { - private static List _urls; - - public static readonly Dictionary ValApiLanguages = new() - { - { "ar", "ar-AE" }, - { "de", "de-DE" }, - { "en", "en-US" }, - { "es", "es-ES" }, - { "fr", "fr-FR" }, - { "id", "id-ID" }, - { "it", "it-IT" }, - { "ja", "ja-JP" }, - { "ko", "ko-KR" }, - { "pl", "pl-PL" }, - { "pt", "pt-BR" }, - { "ru", "ru-RU" }, - { "th", "th-TH" }, - { "tr", "tr-TR" }, - { "vi", "vi-VN" }, - { "zh", "zh-CN" }, - { "hi", "en-US" } - }; - - private static async Task GetValApiVersion() - { - RestClient client = new(new Uri("https://valorant-api.com/v1/version")); - RestRequest request = new(Method.GET); - var response = await client.ExecuteGetAsync(request); - var content = response.Content; - var responsevar = JsonConvert.DeserializeObject(content); - JToken responseObj = JObject.FromObject(responsevar); - return responseObj["data"]["version"].Value(); - } - - private static async Task GetLocalValApiVersion(string currentPath) - { - string content; - using (var r = new StreamReader(currentPath + "\\ValAPI\\version.json")) - { - content = await r.ReadToEndAsync(); - } - - var responsevar = JsonConvert.DeserializeObject(content); - JToken responseObj = JObject.FromObject(responsevar); - return responseObj["data"]["version"].Value(); - } - - private static Task GetUrls(string currentPath) - { - string language = ValApiLanguages.GetValueOrDefault(Settings.Default.Language); - _urls = new List - { - new() { - Filepath = currentPath + "\\ValAPI\\version.json", - Url = "https://valorant-api.com/v1/version" - }, - new() - { - Filepath = currentPath + "\\ValAPI\\competitivetiers.json", - Url = $"https://valorant-api.com/v1/competitivetiers?language={language}" - }, - new() { - Filepath = currentPath + "\\ValAPI\\playercards.json", - Url = "https://valorant-api.com/v1/playercards" - }, - new() - { - Filepath = currentPath + "\\ValAPI\\skinchromas.json", - Url = $"https://valorant-api.com/v1/weapons/skinchromas?language={language}" - }, - new() - { - Filepath = currentPath + "\\ValAPI\\agents.json", - Url = $"https://valorant-api.com/v1/agents?language={language}" - } - }; - return Task.CompletedTask; - } - - public static async Task UpdateJson(string currentPath) - { - try - { - await GetUrls(currentPath); - if (!Directory.Exists(currentPath + "\\ValAPI")) - Directory.CreateDirectory(currentPath + "\\ValAPI"); - - var tasks = _urls.Select(async url => - { - RestClient client = new(new Uri(url.Url)); - RestRequest request = new(Method.GET); - var response = await client.ExecuteGetAsync(request); - var content = response.Content; - await File.WriteAllTextAsync(url.Filepath, content); - }); - await Task.WhenAll(tasks); - - var content = await LoadJsonFromFile("\\ValAPI\\competitivetiers.json"); - var content2 = await LoadJsonFromFile("\\ValAPI\\agents.json"); - - if (!Directory.Exists(currentPath + "\\ValAPI\\agentsimg")) - Directory.CreateDirectory(currentPath + "\\ValAPI\\agentsimg"); - foreach (var agent in content2.data) - { - string uuid = agent.uuid; - var client = new WebClient(); - string url = agent.killfeedPortrait; - Uri uri = new(url); - var fileName = currentPath + $"\\ValAPI\\agentsimg\\{uuid}.png"; - client.DownloadFile(uri, fileName); - } - - if (!Directory.Exists(currentPath + "\\ValAPI\\ranksimg")) - Directory.CreateDirectory(currentPath + "\\ValAPI\\ranksimg"); - foreach (var rank in content.data[3].tiers) - { - int currentrank = rank.tier; - string url2; - var client2 = new WebClient(); - if (currentrank == 0) - url2 = rank.smallIcon; - else if (currentrank is 1 or 2) - continue; - else - url2 = rank.largeIcon; - Uri uri2 = new(url2); - var fileName = currentPath + $"\\ValAPI\\ranksimg\\{currentrank}.png"; - client2.DownloadFile(uri2, fileName); - } - } - catch (Exception) - { - } - } - - public static async Task LoadJsonFromFile(string filepath) - { - string currentPath = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) + "\\WAIUA"; - string content; - using (var r = new StreamReader(currentPath + filepath)) - { - content = await r.ReadToEndAsync(); - } - - dynamic response = JsonConvert.DeserializeObject(content); - return response; - } - - public static async Task CheckAndUpdateJson() - { - try - { - string currentPath = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) + "\\WAIUA"; - await GetUrls(currentPath); - foreach (var path in _urls) - { - if (!File.Exists(path.Filepath)) - { - await UpdateJson(currentPath); - } - } - if (await GetValApiVersion() != await GetLocalValApiVersion(currentPath)) await UpdateJson(currentPath); - } - catch (Exception) - { - } - } - - private class Urls - { - public string Filepath { get; init; } - public string Url { get; init; } - } - } -} \ No newline at end of file diff --git a/WAIUA/ViewFactory.cs b/WAIUA/ViewFactory.cs new file mode 100644 index 00000000..c02aacbb --- /dev/null +++ b/WAIUA/ViewFactory.cs @@ -0,0 +1,45 @@ +using System; +using System.Linq; +using System.Windows; + +namespace WAIUA; +// public class MappingViewFactory : IViewFactory +// { +// private readonly Dictionary _mapping = new(); +// +// public FrameworkElement? ResolveView(object viewModel) +// { +// if (!_mapping.ContainsKey(viewModel.GetType())) +// { +// return null; +// } +// +// var viewType = _mapping[viewModel.GetType()]; +// return (FrameworkElement?)Activator.CreateInstance(viewType); +// } +// +// public MappingViewFactory Register() +// where TView : DependencyObject +// where TViewModel : ObservableObject +// { +// _mapping[typeof(TViewModel)] = typeof(TView); +// +// return this; +// } +// } + +public class NamingConventionViewFactory : IViewFactory +{ + public FrameworkElement? ResolveView(object viewModel) + { + var vmName = viewModel.GetType().Name; + var viewName = vmName.Contains("Page") + ? vmName.Replace("PageViewModel", "View") + : vmName.Replace("ViewModel", ""); + var viewType = typeof(App).Assembly.DefinedTypes.Where(x => x.Name == viewName).FirstOrDefault(); + if (viewType == null) return null; + + var view = Activator.CreateInstance(viewType); + return (FrameworkElement?) view; + } +} \ No newline at end of file diff --git a/WAIUA/ViewModelPresenter.cs b/WAIUA/ViewModelPresenter.cs new file mode 100644 index 00000000..42220c4b --- /dev/null +++ b/WAIUA/ViewModelPresenter.cs @@ -0,0 +1,53 @@ +using System.Windows; +using System.Windows.Controls; +using Microsoft.Toolkit.Mvvm.DependencyInjection; + +namespace WAIUA; + +public class ViewModelPresenter : ContentControl +{ + public static readonly DependencyProperty ViewModelProperty = + DependencyProperty.Register("ViewModel", typeof(object), typeof(ViewModelPresenter), + new PropertyMetadata(null, OnViewModelChanged)); + + public ViewModelPresenter() + { + HorizontalContentAlignment = HorizontalAlignment.Stretch; + VerticalContentAlignment = VerticalAlignment.Stretch; + } + + public object ViewModel + { + get => GetValue(ViewModelProperty); + set => SetValue(ViewModelProperty, value); + } + + private static void OnViewModelChanged(DependencyObject changedObject, DependencyPropertyChangedEventArgs args) + { + var contentControl = (ViewModelPresenter) changedObject; + contentControl.RefreshContentPresenter(); + } + + private void RefreshContentPresenter() + { + if (ViewModel == null) + { + Content = null; + + return; + } + + var viewFactory = Ioc.Default.GetRequiredService(); + var view = viewFactory.ResolveView(ViewModel); + + if (view != null) + { + view.DataContext = ViewModel; + Content = view; + } + else + { + Content = null; + } + } +} \ No newline at end of file diff --git a/WAIUA/ViewModels/HomeViewModel.cs b/WAIUA/ViewModels/HomeViewModel.cs index 1d6d4dec..acbbf514 100644 --- a/WAIUA/ViewModels/HomeViewModel.cs +++ b/WAIUA/ViewModels/HomeViewModel.cs @@ -1,200 +1,221 @@ using System; using System.Collections.Generic; -using System.Runtime.CompilerServices; using System.Threading.Tasks; -using System.Windows.Input; -using MVVMEssentials.Commands; -using MVVMEssentials.Services; -using MVVMEssentials.ViewModels; -using WAIUA.Commands; - -namespace WAIUA.ViewModels +using System.Windows; +using System.Windows.Media; +using System.Windows.Threading; +using FontAwesome6; +using Microsoft.Toolkit.Mvvm.ComponentModel; +using Microsoft.Toolkit.Mvvm.Input; +using WAIUA.Helpers; +using WAIUA.Objects; +using WAIUA.Views; +using static WAIUA.Helpers.Login; + +namespace WAIUA.ViewModels; + +public partial class HomeViewModel : ObservableObject { - public class HomeViewModel : ViewModelBase - { - private string[] _player0Prop; - - private string[] _player1Prop; - - private string[] _player2Prop; - - private string[] _player3Prop; - - private string[] _player4Prop; - - private string[] _player5Prop; - - private string[] _player6Prop; - - private string[] _player7Prop; - - private string[] _player8Prop; - - private string[] _player9Prop; - - public HomeViewModel(INavigationService homeNavigationService, INavigationService infoNavigationService, - INavigationService settingsNavigationService) - { - Mouse.OverrideCursor = Cursors.Wait; - if (GetPlayerInfo()) - { - _player0Prop = Player.Player0; - _player1Prop = Player.Player1; - _player2Prop = Player.Player2; - _player3Prop = Player.Player3; - _player4Prop = Player.Player4; - _player5Prop = Player.Player5; - _player6Prop = Player.Player6; - _player7Prop = Player.Player7; - _player8Prop = Player.Player8; - _player9Prop = Player.Player9; - } - - NavigateHomeCommand = new NavigateCommand(homeNavigationService); - NavigateInfoCommand = new NavigateCommand(infoNavigationService); - NavigateSettingsCommand = new NavigateCommand(settingsNavigationService); - Mouse.OverrideCursor = Cursors.Arrow; - } - - public string[] Player0 - { - get => _player0Prop; - set => SetProperty(ref _player0Prop, value, nameof(Player0)); - } - - public string[] Player1 - { - get => _player1Prop; - set => SetProperty(ref _player1Prop, value, nameof(Player1)); - } - - public string[] Player2 - { - get => _player2Prop; - set => SetProperty(ref _player2Prop, value, nameof(Player2)); - } - - public string[] Player3 - { - get => _player3Prop; - set => SetProperty(ref _player3Prop, value, nameof(Player3)); - } - - public string[] Player4 - { - get => _player4Prop; - set => SetProperty(ref _player4Prop, value, nameof(Player4)); - } - - public string[] Player5 - { - get => _player5Prop; - set => SetProperty(ref _player5Prop, value, nameof(Player5)); - } - - public string[] Player6 - { - get => _player6Prop; - set => SetProperty(ref _player6Prop, value, nameof(Player6)); - } - - public string[] Player7 - { - get => _player7Prop; - set => SetProperty(ref _player7Prop, value, nameof(Player7)); - } - - public string[] Player8 - { - get => _player8Prop; - set => SetProperty(ref _player8Prop, value, nameof(Player8)); - } - - public string[] Player9 - { - get => _player9Prop; - set => SetProperty(ref _player9Prop, value, nameof(Player9)); - } - - public ICommand NavigateHomeCommand { get; } - public ICommand NavigateInfoCommand { get; } - public ICommand NavigateSettingsCommand { get; } - - private bool GetPlayerInfo() - { - var output = false; - try - { - var newMatch = new Main(); - Parallel.For(0, 10, i => { Player.players[i].Data = null; }); - - if (newMatch.LiveMatchChecks()) - { - try - { - Parallel.For(0, 10, i => { Player.players[i].Data = newMatch.LiveMatchOutput((sbyte)i); }); - - var colours = new List - {"Red", "Green", "DarkOrange", "White", "DeepSkyBlue", "MediumPurple", "SaddleBrown"}; - for (var i = 0; i < Player.players.Length; i++) - { - var colourused = false; - var id = Player.players[i].Data[28]; - for (var j = i + 1; j < Player.players.Length; j++) - if (Player.players[j].Data[28] == id && Player.players[j].Data[28].Length >= 13) - { - Player.players[i].Data[28] = Player.players[j].Data[28] = colours[0]; - colourused = true; - } - - if (colourused) colours.RemoveAt(0); - } - - for (var i = 0; i < Player.players.Length; i++) - if (Player.players[i].Data[28].Length >= 13) - Player.players[i].Data[28] = "Transparent"; - } - catch (Exception) - { - } - - output = true; - } - } - catch (Exception) - { - } - - return output; - } - - private void SetProperty(ref T field, T newValue, [CallerMemberName] string propertyName = null) - { - field = newValue; - OnPropertyChanged(propertyName); - } - - public class Player - { - public static Player[] players; - public string[] Data; - - static Player() - { - players = new Player[10]; - for (sbyte x = 0; x < 10; x++) players[x] = new Player(); - } - - public static string[] Player0 => players[0].Data; - public static string[] Player1 => players[1].Data; - public static string[] Player2 => players[2].Data; - public static string[] Player3 => players[3].Data; - public static string[] Player4 => players[4].Data; - public static string[] Player5 => players[5].Data; - public static string[] Player6 => players[6].Data; - public static string[] Player7 => players[7].Data; - public static string[] Player8 => players[8].Data; - public static string[] Player9 => players[9].Data; - } - } + public delegate void EventAction(); + + [ObservableProperty] private int _countdownTime = 20; + [ObservableProperty] private DispatcherTimer _countTimer; + [ObservableProperty] private List _playerList; + [ObservableProperty] private string _refreshTime = "-"; + private int _cycle = 3; + + public event EventAction GoMatchEvent; + + public HomeViewModel() + { + _countTimer = new DispatcherTimer(); + _countTimer.Tick += UpdateTimersAsync; + _countTimer.Interval = new TimeSpan(0, 0, 1); + } + + [ICommand] + private async Task LoadNowAsync() + { + CountdownTime = 20; + await UpdateChecksAsync(true).ConfigureAwait(false); + } + + [ICommand] + private async Task PassiveLoadAsync() + { + if (!_countTimer.IsEnabled) + { + _countTimer.Start(); + await UpdateChecksAsync(true).ConfigureAwait(false); + } + + } + + [ICommand] + private Task StopPassiveLoadAsync() + { + CountTimer?.Stop(); + RefreshTime = "-"; + CountdownTime = 20; + return Task.CompletedTask; + } + + + private async void UpdateTimersAsync(object sender, EventArgs e) + { + RefreshTime = CountdownTime + "s"; + if (CountdownTime == 0) + { + CountdownTime = 15; + await UpdateChecksAsync(false).ConfigureAwait(false); + } + CountdownTime--; + } + + + [ICommand] + private async Task UpdateChecksAsync(bool forcePartyUpdate) + { + Application.Current.Dispatcher.Invoke(() => + { + Home.ValorantStatus.Icon = EFontAwesomeIcon.Solid_Question; + Home.ValorantStatus.Foreground = new SolidColorBrush(Color.FromRgb(0, 126, 249)); + Home.AccountStatus.Icon = EFontAwesomeIcon.Solid_Question; + Home.AccountStatus.Foreground = new SolidColorBrush(Color.FromRgb(0, 126, 249)); + Home.MatchStatus.Icon = EFontAwesomeIcon.Solid_Question; + Home.MatchStatus.Foreground = new SolidColorBrush(Color.FromRgb(0, 126, 249)); + }); + + if (await Checks.CheckLocalAsync().ConfigureAwait(false)) + { + Application.Current.Dispatcher.Invoke(() => + { + Home.ValorantStatus.Icon = EFontAwesomeIcon.Solid_Check; + Home.ValorantStatus.Foreground = new SolidColorBrush(Color.FromRgb(50, 226, 178)); + }); + if (await Checks.CheckLoginAsync().ConfigureAwait(false)) + { + Application.Current.Dispatcher.Invoke(() => + { + Home.AccountStatus.Icon = EFontAwesomeIcon.Solid_Check; + Home.AccountStatus.Foreground = new SolidColorBrush(Color.FromRgb(50, 226, 178)); + }); + if (await Checks.CheckMatchAsync().ConfigureAwait(false)) + { + Application.Current.Dispatcher.Invoke(() => + { + Home.MatchStatus.Icon = EFontAwesomeIcon.Solid_Check; + Home.MatchStatus.Foreground = new SolidColorBrush(Color.FromRgb(50, 226, 178)); + }); + CountTimer?.Stop(); + GoMatchEvent?.Invoke(); + } + else + { + Application.Current.Dispatcher.Invoke(() => + { + Home.MatchStatus.Icon = EFontAwesomeIcon.Solid_Xmark; + Home.MatchStatus.Foreground = new SolidColorBrush(Color.FromRgb(255, 70, 84)); + }); + if (forcePartyUpdate) + { + _cycle++; + await GetPartyPlayerInfoAsync().ConfigureAwait(false); + } + else + { + if (_cycle == 0) + { + await GetPartyPlayerInfoAsync().ConfigureAwait(false); + _cycle = 3; + } + _cycle--; + } + } + } + else + { + await LocalLoginAsync().ConfigureAwait(false); + await LocalRegionAsync().ConfigureAwait(false); + if (await Checks.CheckLoginAsync().ConfigureAwait(false)) + { + Application.Current.Dispatcher.Invoke(() => + { + Home.AccountStatus.Icon = EFontAwesomeIcon.Solid_Check; + Home.AccountStatus.Foreground = new SolidColorBrush(Color.FromRgb(50, 226, 178)); + }); + if (await Checks.CheckMatchAsync().ConfigureAwait(false)) + { + Application.Current.Dispatcher.Invoke(() => + { + Home.MatchStatus.Icon = EFontAwesomeIcon.Solid_Check; + Home.MatchStatus.Foreground = new SolidColorBrush(Color.FromRgb(50, 226, 178)); + }); + CountTimer?.Stop(); + GoMatchEvent?.Invoke(); + } + else + { + Application.Current.Dispatcher.Invoke(() => + { + Home.MatchStatus.Icon = EFontAwesomeIcon.Solid_Xmark; + Home.MatchStatus.Foreground = new SolidColorBrush(Color.FromRgb(255, 70, 84)); + }); + if (forcePartyUpdate) + { + _cycle++; + await GetPartyPlayerInfoAsync().ConfigureAwait(false); + } + else + { + if (_cycle == 0) + { + await GetPartyPlayerInfoAsync().ConfigureAwait(false); + _cycle = 3; + } + _cycle--; + } + } + } + else + { + Application.Current.Dispatcher.Invoke(() => + { + Home.AccountStatus.Icon = EFontAwesomeIcon.Solid_Xmark; + Home.AccountStatus.Foreground = new SolidColorBrush(Color.FromRgb(255, 70, 84)); + Home.MatchStatus.Icon = EFontAwesomeIcon.Solid_Xmark; + Home.MatchStatus.Foreground = new SolidColorBrush(Color.FromRgb(255, 70, 84)); + }); + } + } + } + else + { + Application.Current.Dispatcher.Invoke(() => + { + Home.ValorantStatus.Icon = EFontAwesomeIcon.Solid_Xmark; + Home.ValorantStatus.Foreground = new SolidColorBrush(Color.FromRgb(255, 70, 84)); + Home.AccountStatus.Icon = EFontAwesomeIcon.Solid_Xmark; + Home.AccountStatus.Foreground = new SolidColorBrush(Color.FromRgb(255, 70, 84)); + Home.MatchStatus.Icon = EFontAwesomeIcon.Solid_Xmark; + Home.MatchStatus.Foreground = new SolidColorBrush(Color.FromRgb(255, 70, 84)); + }); + } + } + + [ICommand] + private async Task GetPartyPlayerInfoAsync() + { + try + { + LiveMatch newLiveMatch = new(); + if (await newLiveMatch.CheckAndSetPartyIdAsync().ConfigureAwait(false)) PlayerList = await newLiveMatch.PartyOutputAsync().ConfigureAwait(false); + } + catch (Exception) + { + // ignored + } + + GC.Collect(); + } } \ No newline at end of file diff --git a/WAIUA/ViewModels/InfoViewModel.cs b/WAIUA/ViewModels/InfoViewModel.cs index 60865372..8472ea69 100644 --- a/WAIUA/ViewModels/InfoViewModel.cs +++ b/WAIUA/ViewModels/InfoViewModel.cs @@ -1,22 +1,7 @@ -using System.Windows.Input; -using MVVMEssentials.Commands; -using MVVMEssentials.Services; -using MVVMEssentials.ViewModels; +using Microsoft.Toolkit.Mvvm.ComponentModel; -namespace WAIUA.ViewModels -{ - internal class InfoViewModel : ViewModelBase - { - public InfoViewModel(INavigationService homeNavigationService, INavigationService infoNavigationService, - INavigationService settingsNavigationService) - { - NavigateHomeCommand = new NavigateCommand(homeNavigationService); - NavigateInfoCommand = new NavigateCommand(infoNavigationService); - NavigateSettingsCommand = new NavigateCommand(settingsNavigationService); - } +namespace WAIUA.ViewModels; - public ICommand NavigateHomeCommand { get; } - public ICommand NavigateInfoCommand { get; } - public ICommand NavigateSettingsCommand { get; } - } +internal class InfoViewModel : ObservableObject +{ } \ No newline at end of file diff --git a/WAIUA/ViewModels/MainViewModel.cs b/WAIUA/ViewModels/MainViewModel.cs new file mode 100644 index 00000000..8f046628 --- /dev/null +++ b/WAIUA/ViewModels/MainViewModel.cs @@ -0,0 +1,39 @@ +using Microsoft.Toolkit.Mvvm.ComponentModel; +using Microsoft.Toolkit.Mvvm.DependencyInjection; +using Microsoft.Toolkit.Mvvm.Input; + +namespace WAIUA.ViewModels; + +public partial class MainViewModel : ObservableObject +{ + [ObservableProperty] private ObservableObject? _selectedViewModel; + + public MainViewModel() + { + SelectedViewModel = Ioc.Default.GetRequiredService(); + } + + [ICommand] + public void NavigateHome() + { + SelectedViewModel = Ioc.Default.GetRequiredService(); + } + + [ICommand] + public void NavigateInfo() + { + SelectedViewModel = Ioc.Default.GetRequiredService(); + } + + [ICommand] + public void NavigateSettings() + { + SelectedViewModel = Ioc.Default.GetRequiredService(); + } + + [ICommand] + public void NavigateMatch() + { + SelectedViewModel = Ioc.Default.GetRequiredService(); + } +} \ No newline at end of file diff --git a/WAIUA/ViewModels/MatchViewModel.cs b/WAIUA/ViewModels/MatchViewModel.cs new file mode 100644 index 00000000..8d215581 --- /dev/null +++ b/WAIUA/ViewModels/MatchViewModel.cs @@ -0,0 +1,168 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using System.Windows.Threading; +using Microsoft.Toolkit.Mvvm.ComponentModel; +using Microsoft.Toolkit.Mvvm.Input; +using WAIUA.Helpers; +using WAIUA.Objects; + +namespace WAIUA.ViewModels; + +public partial class MatchViewModel : ObservableObject +{ + public delegate void EventAction(); + + [ObservableProperty] private int _countdownTime = 80; + [ObservableProperty] private DispatcherTimer _countTimer; + [ObservableProperty] private List _leftPlayerList; + [ObservableProperty] private List _rightPlayerList; + [ObservableProperty] private MatchDetails _match; + [ObservableProperty] private LoadingOverlay _overlay; + [ObservableProperty] private string _refreshTime = "-"; + private int _resettime = 80; + + public MatchViewModel() + { + _countTimer = new DispatcherTimer(); + _countTimer.Tick += UpdateTimersAsync; + _countTimer.Interval = new TimeSpan(0, 0, 1); + + Match = new MatchDetails(); + Overlay = new LoadingOverlay + { + Header = "Loading", + Content = "Getting Match Details", + IsBusy = false + }; + + LeftPlayerList = new List(); + RightPlayerList = new List(); + } + + public event EventAction GoHomeEvent; + + [ICommand] + private async Task PassiveLoadAsync() + { + if (!_countTimer.IsEnabled) + { + _countTimer.Start(); + await GetMatchInfoAsync().ConfigureAwait(false); + } + + } + + [ICommand] + private Task StopPassiveLoadAsync() + { + CountTimer?.Stop(); + RefreshTime = "-"; + CountdownTime = 15; + return Task.CompletedTask; + } + + private async void UpdateTimersAsync(object sender, EventArgs e) + { + RefreshTime = CountdownTime + "s"; + if (CountdownTime <= 0) + { + CountdownTime = _resettime; + await GetMatchInfoAsync().ConfigureAwait(false); + } + CountdownTime--; + } + + [ICommand] + private async Task GetMatchInfoAsync() + { + Overlay = new LoadingOverlay + { + IsBusy = true, + Header = "Loading", + Progress = 0 + }; + + try + { + LiveMatch newLiveMatch = new(); + if (await LiveMatch.LiveMatchChecksAsync().ConfigureAwait(false)) + { + var AllPlayers = new List(); + Overlay.Content = "Getting Player Details"; + AllPlayers = await newLiveMatch.LiveMatchOutputAsync(UpdatePercentage).ConfigureAwait(false); + + if (newLiveMatch.Status != "PREGAME") + { + _resettime = 120; + CountdownTime = 120; + } + + if (newLiveMatch.QueueId == "deathmatch" || AllPlayers.Count > 10) + { + var mid = AllPlayers.Count / 2; + LeftPlayerList = AllPlayers.Take(mid).ToList(); + RightPlayerList = AllPlayers.Skip(mid).ToList(); + } + else + { + LeftPlayerList.Clear(); + RightPlayerList.Clear(); + foreach (var player in AllPlayers) + switch (player.TeamId) + { + case "Blue": + LeftPlayerList.Add(player); + break; + case "Red": + RightPlayerList.Add(player); + break; + } + + LeftPlayerList = LeftPlayerList.ToList(); + RightPlayerList = RightPlayerList.ToList(); + } + + AllPlayers.Clear(); + + if (newLiveMatch.MatchInfo != null) + Match = newLiveMatch.MatchInfo; + + UpdateStats(); + + Overlay.IsBusy = false; + } + else + { + CountTimer?.Stop(); + GoHomeEvent?.Invoke(); + } + } + catch (Exception) + { + // ignored + } + finally + { + Overlay.IsBusy = false; + } + + GC.Collect(); + } + + private async void UpdateStats() + { + // List tasks = new(); + var AllPlayers = LeftPlayerList.Concat(RightPlayerList).ToList(); + foreach (var player in AllPlayers) + // var t1 = LiveMatch.GetMatchHistoryAsync(player.PlayerUiData.Puuid); + // player.MatchHistoryData = t1.Result; + player.MatchHistoryData = await LiveMatch.GetMatchHistoryAsync(player.PlayerUiData.Puuid).ConfigureAwait(false); + } + + private void UpdatePercentage(int percentage) + { + Overlay.Progress = percentage; + } +} \ No newline at end of file diff --git a/WAIUA/ViewModels/SettingsViewModel.cs b/WAIUA/ViewModels/SettingsViewModel.cs index 0f2259fd..e47c0fd0 100644 --- a/WAIUA/ViewModels/SettingsViewModel.cs +++ b/WAIUA/ViewModels/SettingsViewModel.cs @@ -1,22 +1,7 @@ -using System.Windows.Input; -using MVVMEssentials.Commands; -using MVVMEssentials.Services; -using MVVMEssentials.ViewModels; +using Microsoft.Toolkit.Mvvm.ComponentModel; -namespace WAIUA.ViewModels -{ - internal class SettingsViewModel : ViewModelBase - { - public SettingsViewModel(INavigationService homeNavigationService, INavigationService infoNavigationService, - INavigationService settingsNavigationService) - { - NavigateHomeCommand = new NavigateCommand(homeNavigationService); - NavigateInfoCommand = new NavigateCommand(infoNavigationService); - NavigateSettingsCommand = new NavigateCommand(settingsNavigationService); - } +namespace WAIUA.ViewModels; - public ICommand NavigateHomeCommand { get; } - public ICommand NavigateInfoCommand { get; } - public ICommand NavigateSettingsCommand { get; } - } +public class SettingsViewModel : ObservableObject +{ } \ No newline at end of file diff --git a/WAIUA/Views/Home.xaml b/WAIUA/Views/Home.xaml index 7a0cfc06..667f8857 100644 --- a/WAIUA/Views/Home.xaml +++ b/WAIUA/Views/Home.xaml @@ -5,440 +5,320 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:c="clr-namespace:WAIUA.Controls" - xmlns:p="clr-namespace:WAIUA.Properties" xmlns:viewmodels="clr-namespace:WAIUA.ViewModels" + xmlns:i="http://schemas.microsoft.com/xaml/behaviors" + xmlns:p="clr-namespace:WAIUA.Properties" + xmlns:fa="http://schemas.fontawesome.com/icons/fonts" d:DataContext="{d:DesignInstance Type=viewmodels:HomeViewModel}" d:DesignHeight="754" d:DesignWidth="1536" - Background="#2E3349" mc:Ignorable="d"> + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + - - - - - + - - - + + + + + - - + Grid.Column="0" x:Name="GoMatch" + Command="{Binding DataContext.NavigateMatchCommand, RelativeSource={RelativeSource AncestorType=Window}}" + Visibility="Collapsed" /> + + + - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + - - - - - + + - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/WAIUA/Views/Home.xaml.cs b/WAIUA/Views/Home.xaml.cs index 03b38ced..84954553 100644 --- a/WAIUA/Views/Home.xaml.cs +++ b/WAIUA/Views/Home.xaml.cs @@ -1,12 +1,156 @@ -using System.Windows.Controls; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Shapes; +using System.Windows.Threading; +using FontAwesome6.Fonts; +using WAIUA.ViewModels; -namespace WAIUA.Views +namespace WAIUA.Views; + +public partial class Home : UserControl { - public partial class Home : UserControl - { - public Home() - { - InitializeComponent(); - } - } + public static ImageAwesome ValorantStatus; + public static ImageAwesome AccountStatus; + public static ImageAwesome MatchStatus; + private readonly DispatcherTimer _gameTimer = new(); + private readonly Random _rand = new(); + private readonly List _removeThis = new(); + private int _currentRate; + private int _health = 350; + private int _posX; + private int _posY; + private int _score; + private int _spawnRate = 60; + + + public Home() + { + InitializeComponent(); + DataContextChanged += DataContextChangedHandler; + + _gameTimer.Tick += GameLoop; + _gameTimer.Interval = TimeSpan.FromMilliseconds(20); + + ValorantStatus = ValorantStatusView; + AccountStatus = AccountStatusView; + MatchStatus = MatchStatusView; + } + + + private void DataContextChangedHandler(object sender, DependencyPropertyChangedEventArgs e) + { + if (e.NewValue is HomeViewModel viewModel) + viewModel.GoMatchEvent += () => + { + Dispatcher.Invoke(() => + { + if (GoMatch.Command.CanExecute(null)) GoMatch.Command.Execute(null); + }); + }; + } + + private void GameLoop(object sender, EventArgs e) // Heavily modified from https://www.mooict.com/wpf-c-tutorial-create-a-simple-clicking-game-in-visual-studio/ + { + txtScore.Content = _score; + txtLastScore.Content = Properties.Settings.Default.AimScore; + _currentRate -= 2; + + if (_currentRate < 1) + { + _currentRate = _spawnRate; + + _posX = _rand.Next(15, (int) MyCanvas.ActualWidth - 15); + _posY = _rand.Next(50, (int) MyCanvas.ActualHeight - 15); + + var circle = new Ellipse + { + Tag = "circle", + Height = 5, + Width = 5, + Fill = new SolidColorBrush(Color.FromRgb(255, 70, 84)) + }; + + Canvas.SetLeft(circle, _posX); + Canvas.SetTop(circle, _posY); + MyCanvas.Children.Add(circle); + } + + foreach (var x in MyCanvas.Children.OfType()) + { + x.RenderTransformOrigin = new Point(0.5, 0.5); + x.Height += 0.6; + x.Width += 0.6; + + if (!(x.Width > 70)) continue; + + _removeThis.Add(x); + _health -= 15; + } + + if (_health > 1) + healthBar.Width = _health; + else + GameOverFunction(); + + foreach (var i in _removeThis) + MyCanvas.Children.Remove(i); + + _spawnRate = _score switch + { + < 5 => 60, + < 20 => 50, + < 35 => 40, + < 50 => 30, + < 65 => 20, + _ => _spawnRate + }; + } + + private void ClickOnCanvas(object sender, MouseButtonEventArgs e) + { + if (e.OriginalSource is not Ellipse) + { + _health -= 10; + return; + } + + var circle = (Ellipse) e.OriginalSource; + MyCanvas.Children.Remove(circle); + _score++; + } + + private void GameOverFunction() + { + _gameTimer.Stop(); + foreach (var y in MyCanvas.Children.OfType()) + _removeThis.Add(y); + foreach (var i in _removeThis) MyCanvas.Children.Remove(i); + _spawnRate = 60; + Properties.Settings.Default.AimScore = _score; + Properties.Settings.Default.Save(); + _score = 0; + _currentRate = 5; + _health = 350; + _removeThis.Clear(); + + TrainerWindow.Visibility = Visibility.Collapsed; + Grid.RowDefinitions[1].Height = GridLength.Auto; + Grid.RowDefinitions[0].Height = new GridLength(0.5, GridUnitType.Star); + TrainerDialog.Visibility = Visibility.Visible; + } + + private void StartAimTrainerButton(object sender, RoutedEventArgs e) + { + _gameTimer.Start(); + _currentRate = _spawnRate; + TrainerWindow.Visibility = Visibility.Visible; + Grid.RowDefinitions[0].Height = GridLength.Auto; + Grid.RowDefinitions[1].Height = new GridLength(0.5, GridUnitType.Star); + TrainerDialog.Visibility = Visibility.Collapsed; + } } \ No newline at end of file diff --git a/WAIUA/Views/Info.xaml b/WAIUA/Views/Info.xaml index f0c67e90..e91af838 100644 --- a/WAIUA/Views/Info.xaml +++ b/WAIUA/Views/Info.xaml @@ -5,58 +5,41 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:p="clr-namespace:WAIUA.Properties" + xmlns:viewModels="clr-namespace:WAIUA.ViewModels" + xmlns:fa="http://schemas.fontawesome.com/icons/fonts" d:DesignHeight="754" d:DesignWidth="1536" - Background="#2E3349" UseLayoutRounding="True" - mc:Ignorable="d"> + mc:Ignorable="d" + d:DataContext="{d:DesignInstance Type=viewModels:InfoViewModel}"> - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + - + + @@ -65,27 +48,29 @@ - + - + - + - - - - - - - - - + @@ -163,6 +128,7 @@ - - - - - - + + + WAIUA @@ -220,16 +169,18 @@ HorizontalAlignment="Center" FontSize="25" FontWeight="DemiBold" + FontFamily="{StaticResource Nunito}" Foreground="#32e2b2" Text="Who Am I Up Against?" TextWrapping="Wrap" /> - + @@ -237,52 +188,27 @@ + + + - - @@ -291,44 +217,20 @@ + ToolTipService.InitialShowDelay="0" + ToolTip="BrUnKx"> + + + - - - - - - + - - - - - - - + - + @@ -355,6 +262,7 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/WAIUA/Views/Match.xaml.cs b/WAIUA/Views/Match.xaml.cs new file mode 100644 index 00000000..d268b433 --- /dev/null +++ b/WAIUA/Views/Match.xaml.cs @@ -0,0 +1,31 @@ +using System.Windows; +using System.Windows.Controls; +using WAIUA.ViewModels; + +namespace WAIUA.Views; + +/// +/// Interaction logic for Match.xaml +/// +public partial class Match : UserControl +{ + public Match() + { + InitializeComponent(); + DataContextChanged += DataContextChangedHandler; + } + + private void DataContextChangedHandler(object sender, DependencyPropertyChangedEventArgs e) + { + var viewModel = e.NewValue as MatchViewModel; + + if (viewModel != null) + viewModel.GoHomeEvent += () => + { + Dispatcher.Invoke(() => + { + if (GoHome.Command.CanExecute(null)) GoHome.Command.Execute(null); + }); + }; + } +} \ No newline at end of file diff --git a/WAIUA/Views/Settings.xaml b/WAIUA/Views/Settings.xaml index a97de36a..ceb7757c 100644 --- a/WAIUA/Views/Settings.xaml +++ b/WAIUA/Views/Settings.xaml @@ -6,10 +6,12 @@ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:p="clr-namespace:WAIUA.Properties" xmlns:viewmodels="clr-namespace:WAIUA.ViewModels" + xmlns:fa="http://schemas.fontawesome.com/icons/fonts" d:DataContext="{d:DesignInstance Type=viewmodels:SettingsViewModel}" d:DesignHeight="754" d:DesignWidth="1536" mc:Ignorable="d"> + @@ -39,20 +41,6 @@ Data="M0,0 L0,2 L4,6 L8,2 L8,0 L4,4 z" Fill="White" /> - @@ -96,6 +84,7 @@ Margin="3,3,23,3" HorizontalAlignment="Left" VerticalAlignment="Center" + FontFamily="{StaticResource Nunito}" Background="#FF3F3F3F" Focusable="True" Foreground="Green" @@ -154,7 +143,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + - + @@ -223,33 +190,26 @@ - + - + - + - + - + @@ -280,9 +239,12 @@ Grid.Row="1" Grid.RowSpan="2" Grid.Column="0" - Margin="25" + Margin="0 25 25 25" Background="#252A40" CornerRadius="20"> + + + @@ -294,6 +256,7 @@ HorizontalAlignment="Center" VerticalAlignment="Center" FontWeight="DemiBold" + FontFamily="{StaticResource Nunito}" Foreground="White" Text="{x:Static p:Resources.SelLanguageTitle}" TextAlignment="Center" @@ -310,8 +273,8 @@ HorizontalContentAlignment="Center" Background="Transparent" BorderThickness="0" - DropDownOpened="LanguageList_OnDropDownOpened" - SelectionChanged="ListBox_Selected" /> + DropDownOpened="LanguageList_OnDropDownOpenedAsync" + SelectionChanged="ListBox_SelectedAsync" /> @@ -321,9 +284,12 @@ Grid.Row="3" Grid.RowSpan="2" Grid.Column="0" - Margin="25" + Margin="0 25 25 0" Background="#252A40" CornerRadius="20"> + + + @@ -336,6 +302,7 @@ VerticalAlignment="Center" FontSize="30" FontWeight="DemiBold" + FontFamily="{StaticResource Nunito}" Foreground="White" Text="{x:Static p:Resources.CheckDownloadTitle}" TextWrapping="Wrap" /> @@ -344,13 +311,14 @@ Margin="10" HorizontalAlignment="Center" VerticalAlignment="Center" - Click="Button_Click5" + Click="Button_Click5Async" Template="{StaticResource ButtonTemplate}"> @@ -363,13 +331,14 @@ Margin="10" HorizontalAlignment="Center" VerticalAlignment="Center" - Click="Button_Click4" + Click="Button_Click4Async" Template="{StaticResource ButtonTemplate}"> @@ -386,6 +355,9 @@ Margin="25" Background="#252A40" CornerRadius="20"> + + + @@ -397,6 +369,7 @@ HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="30" + FontFamily="{StaticResource Nunito}" FontWeight="DemiBold" Foreground="White" Text="{x:Static p:Resources.InfoTitle}" @@ -408,6 +381,7 @@ Background="Transparent" FontSize="25" FontWeight="Light" + FontFamily="{StaticResource Nunito}" Foreground="White" Opacity="0.7" Text="{x:Static p:Resources.SettingsInfoExplanation1}" @@ -422,6 +396,7 @@ FontSize="25" FontWeight="Normal" Foreground="White" + FontFamily="{StaticResource Nunito}" Opacity="0.2" Text="{x:Static p:Resources.SettingsInfoExplanation2}" TextAlignment="Center" @@ -434,9 +409,12 @@ Grid.Row="1" Grid.RowSpan="2" Grid.Column="2" - Margin="25" + Margin="25 25 0 25" Background="#252A40" CornerRadius="20"> + + + @@ -447,6 +425,7 @@ Grid.Row="0" HorizontalAlignment="Center" VerticalAlignment="Center" + FontFamily="{StaticResource Nunito}" FontSize="30" FontWeight="DemiBold" Foreground="White" @@ -458,6 +437,7 @@ Margin="25,5" Background="Transparent" FontSize="25" + FontFamily="{StaticResource Nunito}" FontWeight="Normal" Foreground="White" Opacity="0.7" @@ -470,7 +450,7 @@ Margin="10" HorizontalAlignment="Center" VerticalAlignment="Center" - Click="Button_Click3" + Click="Button_Click3Async" Template="{StaticResource ButtonTemplate}"> @@ -489,9 +470,12 @@ + + + @@ -503,6 +487,7 @@ HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="30" + FontFamily="{StaticResource Nunito}" FontWeight="DemiBold" Foreground="White" Text="{x:Static p:Resources.CheckUpdates}" @@ -512,6 +497,7 @@ @@ -531,12 +518,14 @@ FontSize="20" Foreground="White" Opacity="0.7" + FontFamily="{StaticResource Nunito}" Text="{x:Static p:Resources.CurrentVersion}" TextAlignment="Left" TextWrapping="Wrap" /> + + + @@ -585,6 +578,7 @@ VerticalAlignment="Center" FontSize="30" FontWeight="DemiBold" + FontFamily="{StaticResource Nunito}" Foreground="White" Text="{x:Static p:Resources.AuthStatusTitle}" TextWrapping="Wrap" /> @@ -593,6 +587,7 @@ x:Name="AuthStatusBox" Margin="25,5" Background="Transparent" + FontFamily="{StaticResource Nunito}" FontSize="10" FontWeight="Normal" Foreground="#32e2b2" @@ -606,7 +601,7 @@ Margin="30,00" HorizontalAlignment="Center" VerticalAlignment="Top" - Click="Button_Click2" + Click="Button_Click2Async" Template="{StaticResource ButtonTemplate}"> @@ -614,6 +609,7 @@ Padding="5" HorizontalAlignment="Center" VerticalAlignment="Center" + FontFamily="{StaticResource Nunito}" FontWeight="Normal" Foreground="#007EF9" Text="{x:Static p:Resources.AuthStatusButton}" /> diff --git a/WAIUA/Views/Settings.xaml.cs b/WAIUA/Views/Settings.xaml.cs index 6691dbc5..e3e907b2 100644 --- a/WAIUA/Views/Settings.xaml.cs +++ b/WAIUA/Views/Settings.xaml.cs @@ -10,132 +10,127 @@ using System.Windows.Input; using System.Xml; using AutoUpdaterDotNET; +using WAIUA.Helpers; using WAIUA.Properties; -using static WAIUA.Commands.Main; -using static WAIUA.ValAPI.ValAPI; +using static WAIUA.Helpers.Login; +using static WAIUA.Helpers.ValApi; -namespace WAIUA.Views +namespace WAIUA.Views; + +public partial class Settings : UserControl { - public partial class Settings : UserControl - { - private readonly List LanguageList = new(); - - public Settings() - { - InitializeComponent(); - } - - private void CheckAuth() - { - Mouse.OverrideCursor = Cursors.Wait; - AuthStatusBox.Text = Properties.Resources.Refreshing; - if (!GetSetPPUUID()) - AuthStatusBox.Text = Properties.Resources.AuthStatusFail; - else AuthStatusBox.Text = $"{Properties.Resources.AuthStatusAuthAs} {GetIGUsername(PPUUID)}"; - Mouse.OverrideCursor = Cursors.Arrow; - } - - private async void Button_Click1(object sender, RoutedEventArgs e) - { - Mouse.OverrideCursor = Cursors.Wait; - CurrentVersion.Text = Assembly.GetExecutingAssembly().GetName().Version.ToString(); - LatestVersion.Text = await Task.Run(GetLatestVersion); - AutoUpdater.Start("https://raw.githubusercontent.com/Soneliem/WAIUA/master/WAIUA/VersionInfo.xml"); - await CheckAndUpdateJson(); - Mouse.OverrideCursor = Cursors.Arrow; - } - - private static string GetLatestVersion() - { - var xml = new XmlDocument(); - xml.Load("https://raw.githubusercontent.com/Soneliem/WAIUA/master/WAIUA/VersionInfo.xml"); - var result = xml.GetElementsByTagName("version"); - return result[0].InnerText; - } - - private void Button_Click2(object sender, RoutedEventArgs e) - { - Mouse.OverrideCursor = Cursors.Wait; - CheckAuth(); - Mouse.OverrideCursor = Cursors.Arrow; - } - - private void Button_Click3(object sender, RoutedEventArgs e) - { - Mouse.OverrideCursor = Cursors.Wait; - if (CheckLocal()) - { - LocalLogin(); - LocalRegion(); - CheckAuth(); - } - else - { - AuthStatusBox.Text = Properties.Resources.NoValGame; - } - - Mouse.OverrideCursor = Cursors.Arrow; - } - - private async void Button_Click4(object sender, RoutedEventArgs e) - { - Mouse.OverrideCursor = Cursors.Wait; - await CheckAndUpdateJson(); - Mouse.OverrideCursor = Cursors.Arrow; - } - - private async void Button_Click5(object sender, RoutedEventArgs e) - { - Mouse.OverrideCursor = Cursors.Wait; - await UpdateJson(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) + "\\WAIUA"); - Mouse.OverrideCursor = Cursors.Arrow; - } - - private async void ListBox_Selected(object sender, SelectionChangedEventArgs e) - { - Mouse.OverrideCursor = Cursors.Wait; - var combo = (ComboBox)sender; - var index = combo.SelectedIndex; - Thread.CurrentThread.CurrentCulture = LanguageList[index]; - Thread.CurrentThread.CurrentUICulture = LanguageList[index]; - Properties.Settings.Default.Language = LanguageList[index].TwoLetterISOLanguageName; - await UpdateJson(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) + "\\WAIUA"); - Mouse.OverrideCursor = Cursors.Arrow; - } - - private static IEnumerable GetAvailableCultures() - { - var result = new List(); - var rm = new ResourceManager(typeof(Resources)); - - var cultures = CultureInfo.GetCultures(CultureTypes.AllCultures); - foreach (var culture in cultures) - try - { - if (culture.Equals(CultureInfo.InvariantCulture)) continue; - - var rs = rm.GetResourceSet(culture, true, false); - if (rs != null) - result.Add(culture); - } - catch (CultureNotFoundException) - { - } - - return result; - } - - private void LanguageList_OnDropDownOpened(object sender, EventArgs e) - { - Mouse.OverrideCursor = Cursors.Wait; - if (LanguageCombo.Items.Count == 0) - foreach (var language in GetAvailableCultures()) - { - LanguageCombo.Items.Add(language.NativeName); - LanguageList.Add(language); - } - - Mouse.OverrideCursor = Cursors.Arrow; - } - } + private readonly List _languageList = new(); + + public Settings() + { + InitializeComponent(); + } + + private async Task CheckAuthAsync() + { + Mouse.OverrideCursor = Cursors.Wait; + AuthStatusBox.Text = Properties.Resources.Refreshing; + if (!await Checks.CheckLoginAsync().ConfigureAwait(false)) + AuthStatusBox.Text = Properties.Resources.AuthStatusFail; + else AuthStatusBox.Text = $"{Properties.Resources.AuthStatusAuthAs} {await GetNameServiceGetUsernameAsync(Constants.Ppuuid).ConfigureAwait(false)}"; + Mouse.OverrideCursor = Cursors.Arrow; + } + + private async void Button_Click1Async(object sender, RoutedEventArgs e) + { + Mouse.OverrideCursor = Cursors.Wait; + CurrentVersion.Text = Assembly.GetExecutingAssembly().GetName().Version.ToString(); + LatestVersion.Text = await GetLatestVersionAsync().ConfigureAwait(false); + AutoUpdater.Start("https://raw.githubusercontent.com/Soneliem/WAIUA/master/WAIUA/VersionInfo.xml"); + await CheckAndUpdateJsonAsync().ConfigureAwait(false); + Mouse.OverrideCursor = Cursors.Arrow; + } + + private static Task GetLatestVersionAsync() + { + var xml = new XmlDocument(); + xml.Load("https://raw.githubusercontent.com/Soneliem/WAIUA/master/WAIUA/VersionInfo.xml"); + var result = xml.GetElementsByTagName("version"); + return Task.FromResult(result[0].InnerText); + } + + private async void Button_Click2Async(object sender, RoutedEventArgs e) + { + Mouse.OverrideCursor = Cursors.Wait; + await CheckAuthAsync().ConfigureAwait(false); + Mouse.OverrideCursor = Cursors.Arrow; + } + + private async void Button_Click3Async(object sender, RoutedEventArgs e) + { + Mouse.OverrideCursor = Cursors.Wait; + if (await Checks.CheckLocalAsync().ConfigureAwait(false)) + { + await LocalLoginAsync().ConfigureAwait(false); + await LocalRegionAsync().ConfigureAwait(false); + await CheckAuthAsync().ConfigureAwait(false); + } + else + { + AuthStatusBox.Text = Properties.Resources.NoValGame; + } + + Mouse.OverrideCursor = Cursors.Arrow; + } + + private async void Button_Click4Async(object sender, RoutedEventArgs e) + { + await CheckAndUpdateJsonAsync().ConfigureAwait(false); + } + + private async void Button_Click5Async(object sender, RoutedEventArgs e) + { + await UpdateFilesAsync().ConfigureAwait(false); + } + + private async void ListBox_SelectedAsync(object sender, SelectionChangedEventArgs e) + { + var combo = (ComboBox) sender; + var index = combo.SelectedIndex; + Thread.CurrentThread.CurrentCulture = _languageList[index]; + Thread.CurrentThread.CurrentUICulture = _languageList[index]; + Properties.Settings.Default.Language = _languageList[index].TwoLetterISOLanguageName; + await UpdateFilesAsync().ConfigureAwait(false); + } + + private static Task> GetAvailableCulturesAsync() + { + var result = new List(); + var rm = new ResourceManager(typeof(Resources)); + + var cultures = CultureInfo.GetCultures(CultureTypes.AllCultures); + foreach (var culture in cultures) + try + { + if (culture.Equals(CultureInfo.InvariantCulture)) continue; + + var rs = rm.GetResourceSet(culture, true, false); + if (rs != null) + result.Add(culture); + } + catch (CultureNotFoundException) + { + } + + rm.ReleaseAllResources(); + return Task.FromResult>(result); + } + + private async void LanguageList_OnDropDownOpenedAsync(object sender, EventArgs e) + { + Mouse.OverrideCursor = Cursors.Wait; + if (LanguageCombo.Items.Count == 0) + foreach (var language in await GetAvailableCulturesAsync().ConfigureAwait(false)) + { + LanguageCombo.Items.Add(language.NativeName); + _languageList.Add(language); + } + + Mouse.OverrideCursor = Cursors.Arrow; + } } \ No newline at end of file diff --git a/WAIUA/WAIUA.csproj b/WAIUA/WAIUA.csproj index 76379872..97aaa3b4 100644 --- a/WAIUA/WAIUA.csproj +++ b/WAIUA/WAIUA.csproj @@ -1,11 +1,11 @@ - + WinExe - net5.0-windows10.0.22000.0 + net6.0-windows true logo.ico - 1.4.0.2 + 2.0.0.0 True WAIUA.App A Windows app to view player ranks and stats in a live Valorant Match @@ -19,11 +19,11 @@ Soneliem false - 7.0 README.md git - 1.4.0.2 - 1.4.0.2 + 2.0.0.0 + 2.0.0.0 + AnyCPU @@ -37,10 +37,10 @@ - - - - + + + + @@ -80,6 +80,15 @@ PublicResXFileCodeGenerator + + Resources.zh-Hant-TW.resx + + + Resources.resx + + + Resources.resx + True True @@ -88,43 +97,41 @@ - - + + - + - + - - PreserveNewest - - - PreserveNewest + + PreserveNewest - - PreserveNewest + + PreserveNewest + + PreserveNewest + PreserveNewest PreserveNewest + PreserveNewest PreserveNewest - - PreserveNewest - PreserveNewest @@ -139,10 +146,16 @@ - - - - + + + + + + + + + + @@ -154,7 +167,7 @@ - + Never @@ -163,9 +176,4 @@ - - - - - diff --git a/docs/css/styles.css b/docs/css/styles.css index 3b277c2e..9e354b4c 100644 --- a/docs/css/styles.css +++ b/docs/css/styles.css @@ -60,10 +60,14 @@ h2 { } h3 { color: #484848; -} -h3 { font-weight: 700; } +th{ + font-size: large; +} +td, th { + color: #d0cfcf; +} .custom-btn { background: #eee; color: #5b5b5b; diff --git a/docs/images/card.png b/docs/images/card.png index 411dbf02..c26d11e9 100644 Binary files a/docs/images/card.png and b/docs/images/card.png differ diff --git a/docs/images/history.png b/docs/images/history.png index 9fef3d12..98f517c0 100644 Binary files a/docs/images/history.png and b/docs/images/history.png differ diff --git a/docs/images/main.png b/docs/images/main.png index b94f386a..152e2b89 100644 Binary files a/docs/images/main.png and b/docs/images/main.png differ diff --git a/docs/images/mode.png b/docs/images/mode.png new file mode 100644 index 00000000..6c1bb6b4 Binary files /dev/null and b/docs/images/mode.png differ diff --git a/docs/images/name.png b/docs/images/name.png index 1f1ac339..71942d63 100644 Binary files a/docs/images/name.png and b/docs/images/name.png differ diff --git a/docs/images/party.png b/docs/images/party.png index 18b19f70..30b5b081 100644 Binary files a/docs/images/party.png and b/docs/images/party.png differ diff --git a/docs/images/pranks.png b/docs/images/pranks.png index 3dbae1d2..18ffb203 100644 Binary files a/docs/images/pranks.png and b/docs/images/pranks.png differ diff --git a/docs/images/rank.png b/docs/images/rank.png index 0e4638f6..9bf93ba9 100644 Binary files a/docs/images/rank.png and b/docs/images/rank.png differ diff --git a/docs/images/refresh.png b/docs/images/refresh.png new file mode 100644 index 00000000..421e04e4 Binary files /dev/null and b/docs/images/refresh.png differ diff --git a/docs/images/skin.png b/docs/images/skin.png index efb6f4fb..dc8a11c5 100644 Binary files a/docs/images/skin.png and b/docs/images/skin.png differ diff --git a/docs/images/trainer.png b/docs/images/trainer.png new file mode 100644 index 00000000..bcc738b4 Binary files /dev/null and b/docs/images/trainer.png differ diff --git a/docs/index.html b/docs/index.html index 0d897690..7c330447 100644 --- a/docs/index.html +++ b/docs/index.html @@ -1,18 +1,21 @@ - + + - + WAIUA - + @@ -25,7 +28,7 @@ - + @@ -34,16 +37,17 @@ - - + + +