diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml
new file mode 100644
index 00000000..207c3da5
--- /dev/null
+++ b/.github/FUNDING.yml
@@ -0,0 +1,3 @@
+# These are supported funding model platforms
+
+github: Soneliem
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
new file mode 100644
index 00000000..e990092e
--- /dev/null
+++ b/.github/workflows/build.yml
@@ -0,0 +1,72 @@
+name: Build and release
+
+on:
+ push:
+ tags:
+ - "v*.*.*"
+ workflow_call:
+ inputs:
+ tag:
+ required: true
+ type: string
+ workflow_dispatch:
+ inputs:
+ tag:
+ required: true
+ type: string
+
+jobs:
+ build:
+ runs-on: windows-latest
+ env:
+ TAG: ${{ inputs.tag || github.ref_name }}
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v3
+ with:
+ submodules: true
+ ref: ${{ env.TAG }}
+ - name: Setup .NET Core SDK 6.0.400
+ uses: actions/setup-dotnet@v3
+ with:
+ dotnet-version: 6.0.400
+ - name: Install dependencies
+ run: dotnet restore
+ - name: Build
+ run: >
+ dotnet publish .\NOWT\NOWT.csproj
+ --configuration Release
+ -p:PublishSingleFile=true
+ --self-contained false -r win-x64
+ -o ./inno
+ - name: Download netcorecheck
+ shell: pwsh
+ run: |
+ Invoke-WebRequest -URI https://go.microsoft.com/fwlink/?linkid=2135256 -OutFile .\inno\netcorecheck.exe
+ Invoke-WebRequest -URI https://go.microsoft.com/fwlink/?linkid=2135504 -OutFile .\inno\netcorecheck_x64.exe
+ - name: Download InnoSetup
+ uses: pwall2222/inno-setup-download@v0.0.4
+ - name: Package application
+ run: ISCC.exe ./NOWT.iss
+ - name: Rename installer
+ shell: pwsh
+ run: |
+ Rename-Item ./inno/out/NOWT.exe NOWT-Installer.exe
+ - name: Get CHANGELOG
+ id: changelog
+ uses: requarks/changelog-action@v1.8.1
+ with:
+ token: ${{ github.token }}
+ tag: ${{ env.TAG }}
+ writeToFile: false
+ excludeTypes: chore,ci,build,docs,style
+ - name: Release
+ uses: softprops/action-gh-release@v1
+ with:
+ files: |
+ ./inno/out/NOWT-Installer.exe
+ ./inno/NOWT.exe
+ tag_name: ${{ env.TAG }}
+ body: |
+ 
+ ${{ steps.changelog.outputs.changes }}
diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml
new file mode 100644
index 00000000..3f700cf6
--- /dev/null
+++ b/.github/workflows/codeql-analysis.yml
@@ -0,0 +1,71 @@
+# For most projects, this workflow file will not need changing; you simply need
+# to commit it to your repository.
+#
+# You may wish to alter this file to override the set of languages analyzed,
+# or to provide custom queries or build logic.
+#
+# ******** NOTE ********
+# We have attempted to detect the languages in your repository. Please check
+# the `language` matrix defined below to confirm you have the correct set of
+# supported CodeQL languages.
+#
+name: "CodeQL"
+
+on:
+ workflow_dispatch:
+ # push:
+ # branches: [ main ]
+ # pull_request:
+ # # The branches below must be a subset of the branches above
+ # branches: [ main ]
+ # schedule:
+ # - cron: '35 7 * * 4'
+
+jobs:
+ analyze:
+ name: Analyze
+ runs-on: ubuntu-latest
+ permissions:
+ actions: read
+ contents: read
+ security-events: write
+
+ strategy:
+ fail-fast: false
+ matrix:
+ language: [ 'csharp' ]
+ # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
+ # Learn more about CodeQL language support at https://git.io/codeql-language-support
+
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v2
+
+ # Initializes the CodeQL tools for scanning.
+ - name: Initialize CodeQL
+ uses: github/codeql-action/init@v2
+ with:
+ languages: ${{ matrix.language }}
+ # If you wish to specify custom queries, you can do so here or in a config file.
+ # By default, queries listed here will override any specified in a config file.
+ # Prefix the list here with "+" to use these queries and those in the config file.
+ # queries: ./path/to/local/query, your-org/your-repo/queries@main
+
+ # Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
+ # If this step fails, then you should remove it and run the build manually (see below)
+ - name: Autobuild
+ uses: github/codeql-action/autobuild@v2
+
+ # ℹ️ Command-line programs to run using the OS shell.
+ # 📚 https://git.io/JvXDl
+
+ # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
+ # and modify them (or add more) to build your code if your project
+ # uses a compiled language
+
+ #- run: |
+ # make bootstrap
+ # make release
+
+ - name: Perform CodeQL Analysis
+ uses: github/codeql-action/analyze@v2
diff --git a/.github/workflows/semver.yml b/.github/workflows/semver.yml
new file mode 100644
index 00000000..ed9974a6
--- /dev/null
+++ b/.github/workflows/semver.yml
@@ -0,0 +1,47 @@
+name: Semver
+
+on:
+ push:
+
+jobs:
+ bump:
+ runs-on: ubuntu-latest
+ outputs:
+ next: ${{ steps.semver.outputs.next }}
+ current: ${{ steps.semver.outputs.current }}
+
+ steps:
+ - name: Checkout Code
+ uses: actions/checkout@v3
+ - name: Get Next Version
+ id: semver
+ uses: ietf-tools/semver-action@v1
+ with:
+ token: ${{ github.token }}
+ branch: main
+ noVersionBumpBehavior: current
+ skipInvalidTags: true
+ - name: Replace version
+ if: steps.semver.outputs.next != steps.semver.outputs.current
+ run: |
+ sed -i "s/\(MyAppVersion\) '.*'/\1 '$next'/" NOWT.iss
+ sed -i "s/\(\).*\1$major.0.0" NOWT/NOWT.csproj
+ sed -i "s/\(\).*\1$next" NOWT/NOWT.csproj
+ sed -i "s/\(\).*\1$next" NOWT/NOWT.csproj
+ sed -i "s/\(\).*\1$next" NOWT/VersionInfo.xml
+ env:
+ next: ${{ steps.semver.outputs.nextStrict }}
+ major: ${{ steps.semver.outputs.nextMajorStrict }}
+ - name: Push new version to repo
+ if: steps.semver.outputs.next != steps.semver.outputs.current
+ uses: stefanzweifel/git-auto-commit-action@v4
+ with:
+ commit_message: "chore: bump version to ${{ steps.semver.outputs.next }}"
+ file_pattern: "*.csproj *.xml *.iss"
+ tagging_message: ${{ steps.semver.outputs.next }}
+ build:
+ needs: bump
+ uses: ./.github/workflows/build.yml
+ if: needs.bump.outputs.current != needs.bump.outputs.next
+ with:
+ tag: ${{ needs.bump.outputs.next }}
diff --git a/.github/workflows/sponsors.yml b/.github/workflows/sponsors.yml
new file mode 100644
index 00000000..ad078b23
--- /dev/null
+++ b/.github/workflows/sponsors.yml
@@ -0,0 +1,19 @@
+name: Generate Sponsors README
+
+on:
+ push:
+ branches:
+ - master
+ - development-branch
+jobs:
+ deploy:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout 🛎️
+ uses: actions/checkout@v2
+
+ - name: Add GitHub Sponsors to Readme
+ uses: JamesIves/github-sponsors-readme-action@v1.1.0
+ with:
+ token: ${{ secrets.SECRETS }}
+ file: 'README.md'
diff --git a/.gitignore b/.gitignore
index 04da49d6..dc3d04f5 100644
--- a/.gitignore
+++ b/.gitignore
@@ -29,7 +29,6 @@ x86/
bld/
[Bb]in/
[Oo]bj/
-[Oo]ut/
[Ll]og/
[Ll]ogs/
@@ -91,6 +90,7 @@ StyleCopReport.xml
*.tmp_proj
*_wpftmp.csproj
*.log
+*.tlog
*.vspscc
*.vssscc
.builds
@@ -206,6 +206,9 @@ PublishScripts/
*.nuget.props
*.nuget.targets
+# Nuget personal access tokens and Credentials
+# nuget.config
+
# Microsoft Azure Build Output
csx/
*.build.csdef
@@ -362,5 +365,27 @@ MigrationBackup/
# Fody - auto-generated XML schema
FodyWeavers.xsd
-.editorconfig
-
+# VS Code files for those working on multiple tools
+.vscode/*
+#!.vscode/settings.json
+#!.vscode/tasks.json
+#!.vscode/launch.json
+#!.vscode/extensions.json
+*.code-workspace
+
+# Local History for Visual Studio Code
+.history/
+
+# Windows Installer files from build outputs
+*.cab
+*.msi
+*.msix
+*.msm
+*.msp
+
+# JetBrains Rider
+.idea/
+*.sln.iml
+
+# Inno Setup
+inno/
diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 00000000..3cad8ec0
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,3 @@
+[submodule "InnoDependencyInstaller"]
+ path = InnoDependencyInstaller
+ url = https://github.com/DomGries/InnoDependencyInstaller.git
diff --git a/.mailmap b/.mailmap
new file mode 100644
index 00000000..ef31b9b8
--- /dev/null
+++ b/.mailmap
@@ -0,0 +1 @@
+Sonel <24221762+Soneliem@users.noreply.github.com>
\ No newline at end of file
diff --git a/InnoDependencyInstaller b/InnoDependencyInstaller
new file mode 160000
index 00000000..46a15102
--- /dev/null
+++ b/InnoDependencyInstaller
@@ -0,0 +1 @@
+Subproject commit 46a1510260e0381f655b60bcc68d242cdfbf6785
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 00000000..babebbae
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2021 Soneliem
+
+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.
diff --git a/Localization.md b/Localization.md
new file mode 100644
index 00000000..15a5a0cf
--- /dev/null
+++ b/Localization.md
@@ -0,0 +1,86 @@
+# Localization
+WAIUA has full localization support and any number of languages can be added and changed natively. By default, the app changes its language based on the user's system language.
+
+### Guidelines/Tips for adding Translations:
+- Only add translations for things that you are 100% sure on. Partially translating files is ok as long as you put in some effort
+- One of the keys is named: "Translator" and has an English translation of:
+`Translated into English By Soneliem`
+Change this to:
+`Translated into [language-you-are-translating-to] By [your-name/username]`
+If there is already a name there, simply add yours to the end.
+- Please try to only add generic languages such as English(en) rather than English-United States(en-US)
+
+## How to Contribute using [POEditor](https://poeditor.com/join/project?hash=eDxQpoYC9q)
+POEditor lets people collaboratively edit translations, supports auto-translations, quality checks, etc. It's very easy to use and lets me monitor/help people.
+### Steps:
+- Access the website [here](https://poeditor.com/join/project?hash=eDxQpoYC9q)
+- Select the languages you want to help translate and press "Join Translation"
+ - If it re-directs you to the home page click on "WAIUA"
+ - You can add another language by requesting it (It automatically accepts)
+- The first column is the English reference with the second column being what you can edit
+ - You can change English to another language with the "Set Reference Language" button towards the top right
+- Changes are auto saved
+- After being proof-read, your changes will be pushed to the GitHub repo and included in the next release
+
+## Credits:
+**German:**
+- CemsA
+- NNebus
+
+**Arabic:**
+- Chica
+- iHafez
+
+**Japanese:**
+- Aron
+- nepixjp
+
+**Russian:**
+- ZzyzxFox
+- DXGames
+
+**Spanish:**
+- ZzyzxFox
+- FamiTom
+
+**Hindi:**
+- cheemonster
+
+**Italian:**
+- SimpleBonsai
+- CyberKoreTv
+
+**Portuguese:**
+- castrom4
+- janinha
+
+**French:**
+- Rayjacker
+- SeifB_
+
+**Korean:**
+- Ramon
+
+**Dutch:**
+- Jeff
+
+**Danish:**
+- r3verse
+
+**Persian:**
+- Kourosh
+
+**Serbian:**
+- icedancer
+
+**Vietnamese:**
+- Ozymo
+
+**Chinese:**
+- zDragone
+
+**Swedish:**
+- Xosiation
+
+**Turkish:**
+- void
\ No newline at end of file
diff --git a/NOWT.iss b/NOWT.iss
new file mode 100644
index 00000000..c03c512c
--- /dev/null
+++ b/NOWT.iss
@@ -0,0 +1,68 @@
+#define public Dependency_NoExampleSetup
+#include ".\InnoDependencyInstaller\CodeDependencies.iss"
+
+[Setup]
+#define MyAppSetupName 'WAIUA'
+#define MyAppVersion '2.0.1.5'
+#define MyAppPublisher 'Soneliem'
+#define MyAppCopyright 'Soneliem'
+#define MyAppURL 'https://github.com/WAIUA/WAIUA'
+
+AppName={#MyAppSetupName}
+AppVersion={#MyAppVersion}
+AppVerName={#MyAppSetupName} {#MyAppVersion}
+AppCopyright={#MyAppCopyright}
+VersionInfoVersion={#MyAppVersion}
+VersionInfoCompany={#MyAppPublisher}
+AppPublisher={#MyAppPublisher}
+AppPublisherURL={#MyAppURL}
+AppUpdatesURL={#MyAppURL}
+OutputBaseFilename={#MyAppSetupName}
+DefaultGroupName={#MyAppSetupName}
+DefaultDirName={autopf}\{#MyAppSetupName}
+UninstallDisplayIcon=..\NOWT\Assets\logo.ico
+SetupIconFile=..\NOWT\Assets\logo.ico
+SourceDir=inno
+OutputDir=out
+AllowNoIcons=yes
+PrivilegesRequired=lowest
+PrivilegesRequiredOverridesAllowed=dialog
+
+; remove next line if you only deploy 32-bit binaries and dependencies
+ArchitecturesInstallIn64BitMode=x64
+
+[Languages]
+Name: en; MessagesFile: "compiler:Default.isl"
+
+[Files]
+; #ifdef UseNetCoreCheck
+; download netcorecheck.exe: https://go.microsoft.com/fwlink/?linkid=2135256
+; download netcorecheck_x64.exe: https://go.microsoft.com/fwlink/?linkid=2135504
+Source: "netcorecheck.exe"; Flags: dontcopy noencryption
+Source: "netcorecheck_x64.exe"; Flags: dontcopy noencryption
+; #endif
+
+;#ifdef UseDirectX
+;Source: "dxwebsetup.exe"; Flags: dontcopy noencryption
+;#endif
+
+Source: "WAIUA.exe"; DestDir: "{app}"; DestName: "WAIUA.exe"; Check: Dependency_IsX64; Flags: ignoreversion
+Source: "WebView2Loader.dll"; DestDir: "{app}"; DestName: "WebView2Loader.dll"; Flags: ignoreversion
+[Icons]
+Name: "{group}\{#MyAppSetupName}"; Filename: "{app}\WAIUA.exe"
+Name: "{group}\{cm:UninstallProgram,{#MyAppSetupName}}"; Filename: "{uninstallexe}"
+Name: "{userdesktop}\{#MyAppSetupName}"; Filename: "{app}\WAIUA.exe"; Tasks: desktopicon
+
+[Tasks]
+Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; Flags: unchecked
+
+[Run]
+Filename: "{app}\WAIUA.exe"; Description: "{cm:LaunchProgram,{#MyAppSetupName}}"; Flags: nowait postinstall skipifsilent
+
+[Code]
+function InitializeSetup: Boolean;
+begin
+ ExtractTemporaryFile('netcorecheck_x64.exe');
+ Dependency_AddDotNet60Desktop;
+ Result := True;
+end;
diff --git a/NOWT.sln b/NOWT.sln
new file mode 100644
index 00000000..aee4a010
--- /dev/null
+++ b/NOWT.sln
@@ -0,0 +1,50 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.0.31903.59
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NOTW", "NOWT\NOWT.csproj", "{AF25112C-91B9-4735-AE9B-C7CE963A30A4}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{13E3F6B6-D516-4741-9317-407D36E7B34F}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Debug|x64 = Debug|x64
+ Debug|x86 = Debug|x86
+ Release|Any CPU = Release|Any CPU
+ Release|x64 = Release|x64
+ Release|x86 = Release|x86
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {AF25112C-91B9-4735-AE9B-C7CE963A30A4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {AF25112C-91B9-4735-AE9B-C7CE963A30A4}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {AF25112C-91B9-4735-AE9B-C7CE963A30A4}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {AF25112C-91B9-4735-AE9B-C7CE963A30A4}.Debug|x64.Build.0 = Debug|Any CPU
+ {AF25112C-91B9-4735-AE9B-C7CE963A30A4}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {AF25112C-91B9-4735-AE9B-C7CE963A30A4}.Debug|x86.Build.0 = Debug|Any CPU
+ {AF25112C-91B9-4735-AE9B-C7CE963A30A4}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {AF25112C-91B9-4735-AE9B-C7CE963A30A4}.Release|Any CPU.Build.0 = Release|Any CPU
+ {AF25112C-91B9-4735-AE9B-C7CE963A30A4}.Release|x64.ActiveCfg = Release|Any CPU
+ {AF25112C-91B9-4735-AE9B-C7CE963A30A4}.Release|x64.Build.0 = Release|Any CPU
+ {AF25112C-91B9-4735-AE9B-C7CE963A30A4}.Release|x86.ActiveCfg = Release|Any CPU
+ {AF25112C-91B9-4735-AE9B-C7CE963A30A4}.Release|x86.Build.0 = Release|Any CPU
+ {A72C8C52-4BA8-4FBD-959A-4057ED65E529}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {A72C8C52-4BA8-4FBD-959A-4057ED65E529}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {A72C8C52-4BA8-4FBD-959A-4057ED65E529}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {A72C8C52-4BA8-4FBD-959A-4057ED65E529}.Debug|x64.Build.0 = Debug|Any CPU
+ {A72C8C52-4BA8-4FBD-959A-4057ED65E529}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {A72C8C52-4BA8-4FBD-959A-4057ED65E529}.Debug|x86.Build.0 = Debug|Any CPU
+ {A72C8C52-4BA8-4FBD-959A-4057ED65E529}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {A72C8C52-4BA8-4FBD-959A-4057ED65E529}.Release|Any CPU.Build.0 = Release|Any CPU
+ {A72C8C52-4BA8-4FBD-959A-4057ED65E529}.Release|x64.ActiveCfg = Release|Any CPU
+ {A72C8C52-4BA8-4FBD-959A-4057ED65E529}.Release|x86.ActiveCfg = Release|Any CPU
+ {A72C8C52-4BA8-4FBD-959A-4057ED65E529}.Release|x86.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {F05DC966-85E4-423F-85FE-52ECD226D937}
+ EndGlobalSection
+EndGlobal
diff --git a/NOWT.sln.DotSettings b/NOWT.sln.DotSettings
new file mode 100644
index 00000000..c2446703
--- /dev/null
+++ b/NOWT.sln.DotSettings
@@ -0,0 +1,3 @@
+
+ True
+ RR
\ No newline at end of file
diff --git a/NOWT/App.xaml b/NOWT/App.xaml
new file mode 100644
index 00000000..c64d8f46
--- /dev/null
+++ b/NOWT/App.xaml
@@ -0,0 +1,184 @@
+
+
+ /Assets/#Nunito
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/NOWT/App.xaml.cs b/NOWT/App.xaml.cs
new file mode 100644
index 00000000..4cf65aa5
--- /dev/null
+++ b/NOWT/App.xaml.cs
@@ -0,0 +1,112 @@
+using System;
+using System.Globalization;
+using System.Reflection;
+using System.Threading;
+using System.Windows;
+using System.Windows.Threading;
+using AutoUpdaterDotNET;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Toolkit.Mvvm.DependencyInjection;
+using RestoreWindowPlace;
+using Serilog;
+using NOWT.Helpers;
+using NOWT.Properties;
+using NOWT.ViewModels;
+using static NOWT.Helpers.ValApi;
+
+namespace NOWT;
+
+public partial class App : Application
+{
+ public App()
+ {
+ Dispatcher.UnhandledException += OnDispatcherUnhandledException;
+
+ WindowPlace = new WindowPlace(
+ Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData)
+ + "\\NOWT\\placement.config"
+ );
+
+ if (string.IsNullOrEmpty(Settings.Default.Language))
+ {
+ Thread.CurrentThread.CurrentCulture = CultureInfo.InstalledUICulture;
+ Thread.CurrentThread.CurrentUICulture = CultureInfo.InstalledUICulture;
+ Settings.Default.Language = CultureInfo.InstalledUICulture.TwoLetterISOLanguageName;
+ }
+ else
+ {
+ Thread.CurrentThread.CurrentCulture = new CultureInfo(Settings.Default.Language);
+ Thread.CurrentThread.CurrentUICulture = new CultureInfo(Settings.Default.Language);
+ }
+
+ Settings.Default.Save();
+ }
+
+ public WindowPlace WindowPlace { get; }
+
+ private static void OnDispatcherUnhandledException(
+ object sender,
+ DispatcherUnhandledExceptionEventArgs e
+ )
+ {
+ Constants.Log.Error(
+ "Unhandled Exception: {Message}, {Stacktrace}",
+ e.Exception.Message,
+ e.Exception.StackTrace
+ );
+ e.Handled = true;
+ }
+
+ protected override void OnStartup(StartupEventArgs e)
+ {
+ base.OnStartup(e);
+
+ var version = Assembly.GetExecutingAssembly().GetName().Version.ToString();
+ var update_url =
+ "https://raw.githubusercontent.com/WAIUA/WAIUA/master/NOWT/VersionInfo.xml";
+
+ Constants.LocalAppDataPath =
+ Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) + "\\NOWT";
+ Constants.Log = new LoggerConfiguration().MinimumLevel
+ .Debug()
+ .WriteTo.Async(
+ a =>
+ a.File(
+ Constants.LocalAppDataPath + "\\logs\\log.txt",
+ shared: true,
+ rollingInterval: RollingInterval.Day
+ )
+ )
+ .CreateLogger();
+ Constants.Log.Information("Application Start. Version: {Version}", version);
+
+ CheckAndUpdateJsonAsync().ConfigureAwait(false);
+
+ var conventionViewFactory = new NamingConventionViewFactory();
+
+ Ioc.Default.ConfigureServices(
+ new ServiceCollection()
+ .AddTransient()
+ .AddTransient()
+ .AddTransient()
+ .AddTransient()
+ .AddSingleton()
+ .AddSingleton(conventionViewFactory)
+ .BuildServiceProvider()
+ );
+
+ AutoUpdater.ShowSkipButton = false;
+ AutoUpdater.InstalledVersion = new Version(System.Windows.Forms.Application.ProductVersion);
+ AutoUpdater.Start(update_url);
+
+ MainWindow = new MainWindow();
+ MainWindow.Show();
+ }
+
+ private void Application_Exit(object sender, ExitEventArgs e)
+ {
+ Constants.Log.Information("Application Stop");
+ Settings.Default.Save();
+ WindowPlace.Save();
+ }
+}
diff --git a/NOWT/AssemblyInfo.cs b/NOWT/AssemblyInfo.cs
new file mode 100644
index 00000000..7ff2abeb
--- /dev/null
+++ b/NOWT/AssemblyInfo.cs
@@ -0,0 +1,16 @@
+using System.Windows;
+
+[assembly: ThemeInfo(
+ /*
+ where theme specific resource dictionaries are located
+ (used if a resource is not found in the page,
+ or application resource dictionaries)
+ */
+ ResourceDictionaryLocation.None,
+ /*
+ 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.SourceAssembly
+)]
diff --git a/NOWT/Assets/0.png b/NOWT/Assets/0.png
new file mode 100644
index 00000000..8ec9320c
Binary files /dev/null and b/NOWT/Assets/0.png differ
diff --git a/NOWT/Assets/Nunito-Regular.ttf b/NOWT/Assets/Nunito-Regular.ttf
new file mode 100644
index 00000000..7b7f73a5
Binary files /dev/null and b/NOWT/Assets/Nunito-Regular.ttf differ
diff --git a/NOWT/Assets/Soneliem.png b/NOWT/Assets/Soneliem.png
new file mode 100644
index 00000000..5eba8c83
Binary files /dev/null and b/NOWT/Assets/Soneliem.png differ
diff --git a/NOWT/Assets/empty.png b/NOWT/Assets/empty.png
new file mode 100644
index 00000000..909c66db
Binary files /dev/null and b/NOWT/Assets/empty.png differ
diff --git a/WAIUA/Assets/logo.ico b/NOWT/Assets/logo.ico
similarity index 100%
rename from WAIUA/Assets/logo.ico
rename to NOWT/Assets/logo.ico
diff --git a/NOWT/Assets/logo.png b/NOWT/Assets/logo.png
new file mode 100644
index 00000000..12607232
Binary files /dev/null and b/NOWT/Assets/logo.png differ
diff --git a/NOWT/Assets/phantom.png b/NOWT/Assets/phantom.png
new file mode 100644
index 00000000..824dd3ab
Binary files /dev/null and b/NOWT/Assets/phantom.png differ
diff --git a/NOWT/Assets/splash.png b/NOWT/Assets/splash.png
new file mode 100644
index 00000000..728fce69
Binary files /dev/null and b/NOWT/Assets/splash.png differ
diff --git a/NOWT/Assets/vandal.png b/NOWT/Assets/vandal.png
new file mode 100644
index 00000000..cb7174c0
Binary files /dev/null and b/NOWT/Assets/vandal.png differ
diff --git a/NOWT/Controls/InventoryControl.xaml b/NOWT/Controls/InventoryControl.xaml
new file mode 100644
index 00000000..1bb89695
--- /dev/null
+++ b/NOWT/Controls/InventoryControl.xaml
@@ -0,0 +1,155 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/NOWT/Controls/InventoryControl.xaml.cs b/NOWT/Controls/InventoryControl.xaml.cs
new file mode 100644
index 00000000..74e407dc
--- /dev/null
+++ b/NOWT/Controls/InventoryControl.xaml.cs
@@ -0,0 +1,59 @@
+using System.Windows;
+using System.Windows.Controls;
+using NOWT.Objects;
+
+namespace NOWT.Controls;
+
+public partial class InventoryControl : UserControl
+{
+ public static readonly DependencyProperty SkinDataProperty = DependencyProperty.Register(
+ "SkinDataObject",
+ typeof(SkinData),
+ typeof(InventoryControl),
+ new PropertyMetadata(new SkinData())
+ );
+
+ public static readonly DependencyProperty UsernameProperty = DependencyProperty.Register(
+ "Username",
+ typeof(string),
+ typeof(InventoryControl),
+ new PropertyMetadata(null)
+ );
+
+ public static readonly RoutedEvent CloseButtonEvent = EventManager.RegisterRoutedEvent(
+ "SettingConfirmedEvent",
+ RoutingStrategy.Bubble,
+ typeof(RoutedEventHandler),
+ typeof(InventoryControl)
+ );
+
+ public InventoryControl(SkinData skinData, string username)
+ {
+ InitializeComponent();
+ SkinDataObject = skinData;
+ Username = username;
+ }
+
+ public SkinData SkinDataObject
+ {
+ get => (SkinData)GetValue(SkinDataProperty);
+ set => SetValue(SkinDataProperty, value);
+ }
+
+ public string Username
+ {
+ get => (string)GetValue(UsernameProperty);
+ set => SetValue(UsernameProperty, value);
+ }
+
+ public event RoutedEventHandler CloseButton
+ {
+ add => AddHandler(CloseButtonEvent, value);
+ remove => RemoveHandler(CloseButtonEvent, value);
+ }
+
+ private void CloseBtnClick(object sender, RoutedEventArgs e)
+ {
+ RaiseEvent(new RoutedEventArgs(CloseButtonEvent));
+ }
+}
diff --git a/NOWT/Controls/InventoryEntryControl.xaml b/NOWT/Controls/InventoryEntryControl.xaml
new file mode 100644
index 00000000..1998e617
--- /dev/null
+++ b/NOWT/Controls/InventoryEntryControl.xaml
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/NOWT/Controls/InventoryEntryControl.xaml.cs b/NOWT/Controls/InventoryEntryControl.xaml.cs
new file mode 100644
index 00000000..de4a2102
--- /dev/null
+++ b/NOWT/Controls/InventoryEntryControl.xaml.cs
@@ -0,0 +1,39 @@
+using System;
+using System.Windows;
+using System.Windows.Controls;
+
+namespace NOWT.Controls;
+
+public partial class InventoryEntryControl : UserControl
+{
+ public static readonly DependencyProperty TooltipNameProperty = DependencyProperty.Register(
+ "TooltipName",
+ typeof(string),
+ typeof(InventoryEntryControl),
+ new PropertyMetadata(null)
+ );
+
+ public static readonly DependencyProperty ImageProperty = DependencyProperty.Register(
+ "Image",
+ typeof(Uri),
+ typeof(InventoryEntryControl),
+ new PropertyMetadata(null)
+ );
+
+ public InventoryEntryControl()
+ {
+ InitializeComponent();
+ }
+
+ public Uri Image
+ {
+ get => (Uri)GetValue(ImageProperty);
+ set => SetValue(ImageProperty, value);
+ }
+
+ public string TooltipName
+ {
+ get => (string)GetValue(NameProperty);
+ set => SetValue(TooltipNameProperty, value);
+ }
+}
diff --git a/NOWT/Controls/OverlayControl.xaml b/NOWT/Controls/OverlayControl.xaml
new file mode 100644
index 00000000..ef3ba8da
--- /dev/null
+++ b/NOWT/Controls/OverlayControl.xaml
@@ -0,0 +1,121 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/NOWT/Controls/OverlayControl.xaml.cs b/NOWT/Controls/OverlayControl.xaml.cs
new file mode 100644
index 00000000..b8cfe6fd
--- /dev/null
+++ b/NOWT/Controls/OverlayControl.xaml.cs
@@ -0,0 +1,37 @@
+using System.Diagnostics;
+using System.Windows;
+using System.Windows.Controls;
+using NOWT.Objects;
+
+namespace NOWT.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;
+ }
+}
diff --git a/NOWT/Controls/PlayerControl.xaml b/NOWT/Controls/PlayerControl.xaml
new file mode 100644
index 00000000..f186a0c1
--- /dev/null
+++ b/NOWT/Controls/PlayerControl.xaml
@@ -0,0 +1,348 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/NOWT/Controls/PlayerControl.xaml.cs b/NOWT/Controls/PlayerControl.xaml.cs
new file mode 100644
index 00000000..1ae4896f
--- /dev/null
+++ b/NOWT/Controls/PlayerControl.xaml.cs
@@ -0,0 +1,60 @@
+using System.Diagnostics;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Documents;
+using System.Windows.Input;
+using System.Windows.Navigation;
+using NOWT.Objects;
+
+namespace NOWT.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();
+ AddHandler(
+ InventoryControl.CloseButtonEvent,
+ new RoutedEventHandler(ClosePopupEventHandlerMethod)
+ );
+ }
+
+ 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;
+ }
+
+ private void ButtonUpHandler(object sender, MouseButtonEventArgs e)
+ {
+ var s = sender as FrameworkElement;
+ var player = s.DataContext as Player;
+ if (player.IgnData.Username == "----")
+ popup.Child = new InventoryControl(player.SkinData, player.IdentityData.Name);
+ else
+ popup.Child = new InventoryControl(player.SkinData, player.IgnData.Username);
+ popup.IsOpen = true;
+ e.Handled = true;
+ }
+
+ private void ClosePopupEventHandlerMethod(object sender, RoutedEventArgs e)
+ {
+ popup.IsOpen = false;
+ e.Handled = true;
+ }
+}
diff --git a/NOWT/Converters/InverseBooleanConverter.cs b/NOWT/Converters/InverseBooleanConverter.cs
new file mode 100644
index 00000000..d0c35ab6
--- /dev/null
+++ b/NOWT/Converters/InverseBooleanConverter.cs
@@ -0,0 +1,26 @@
+using System;
+using System.Globalization;
+using System.Windows.Data;
+
+namespace NOWT.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
+}
diff --git a/NOWT/Converters/IsStringEmptyToVisibilityConverter.cs b/NOWT/Converters/IsStringEmptyToVisibilityConverter.cs
new file mode 100644
index 00000000..594a79ae
--- /dev/null
+++ b/NOWT/Converters/IsStringEmptyToVisibilityConverter.cs
@@ -0,0 +1,25 @@
+using System;
+using System.Globalization;
+using System.Windows;
+using System.Windows.Data;
+using System.Windows.Markup;
+
+namespace NOWT.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;
+ }
+}
diff --git a/NOWT/Helpers/Checks.cs b/NOWT/Helpers/Checks.cs
new file mode 100644
index 00000000..896200d3
--- /dev/null
+++ b/NOWT/Helpers/Checks.cs
@@ -0,0 +1,89 @@
+using System;
+using System.IO;
+using System.Text;
+using System.Threading.Tasks;
+using RestSharp;
+
+namespace NOWT.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)
+ .AddHeader("X-Riot-ClientPlatform", Constants.Platform)
+ .AddHeader("X-Riot-ClientVersion", Constants.Version);
+ 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}");
+ request.AddHeader("X-Riot-ClientPlatform", Constants.Platform);
+ request.AddHeader("X-Riot-ClientVersion", Constants.Version);
+ 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;
+ }
+}
diff --git a/NOWT/Helpers/Constants.cs b/NOWT/Helpers/Constants.cs
new file mode 100644
index 00000000..ddc57933
--- /dev/null
+++ b/NOWT/Helpers/Constants.cs
@@ -0,0 +1,51 @@
+using System;
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+using RestSharp;
+using Serilog.Core;
+
+namespace NOWT.Helpers;
+
+public static class Constants
+{
+ public static ConcurrentDictionary UrlToBody = new();
+
+ public static readonly List BeforeAscendantSeasons =
+ new()
+ {
+ new Guid("0df5adb9-4dcb-6899-1306-3e9860661dd3"),
+ new Guid("3f61c772-4560-cd3f-5d3f-a7ab5abda6b3"),
+ new Guid("0530b9c4-4980-f2ee-df5d-09864cd00542"),
+ new Guid("46ea6166-4573-1128-9cea-60a15640059b"),
+ new Guid("fcf2c8f4-4324-e50b-2e23-718e4a3ab046"),
+ new Guid("97b6e739-44cc-ffa7-49ad-398ba502ceb0"),
+ new Guid("ab57ef51-4e59-da91-cc8d-51a5a2b9b8ff"),
+ new Guid("52e9749a-429b-7060-99fe-4595426a0cf7"),
+ new Guid("71c81c67-4fae-ceb1-844c-aab2bb8710fa"),
+ new Guid("2a27e5d2-4d30-c9e2-b15a-93b8909a442c"),
+ new Guid("4cb622e1-4244-6da3-7276-8daaf1c01be2"),
+ new Guid("a16955a5-4ad0-f761-5e9e-389df1c892fb"),
+ new Guid("97b39124-46ce-8b55-8fd1-7cbf7ffe173f"),
+ new Guid("573f53ac-41a5-3a7d-d9ce-d6a6298e5704"),
+ new Guid("d929bc38-4ab6-7da4-94f0-ee84f8ac141e"),
+ new Guid("3e47230a-463c-a301-eb7d-67bb60357d4f"),
+ new Guid("808202d6-4f2b-a8ff-1feb-b3a0590ad79f")
+ };
+
+ public static string Platform =
+ "ew0KCSJwbGF0Zm9ybVR5cGUiOiAiUEMiLA0KCSJwbGF0Zm9ybU9TIjogIldpbmRvd3MiLA0KCSJwbGF0Zm9ybU9TVmVyc2lvbiI6ICIxMC4wLjE5MDQyLjEuMjU2LjY0Yml0IiwNCgkicGxhdGZvcm1DaGlwc2V0IjogIlVua25vd24iDQp9";
+
+ 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; }
+}
diff --git a/NOWT/Helpers/LiveMatch.cs b/NOWT/Helpers/LiveMatch.cs
new file mode 100644
index 00000000..26da13f4
--- /dev/null
+++ b/NOWT/Helpers/LiveMatch.cs
@@ -0,0 +1,1320 @@
+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 NOWT.Objects;
+using NOWT.Properties;
+using static NOWT.Helpers.Login;
+
+namespace NOWT.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}");
+ request.AddHeader("X-Riot-ClientPlatform", Constants.Platform);
+ request.AddHeader("X-Riot-ClientVersion", Constants.Version);
+ 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-ClientPlatform", Constants.Platform);
+ 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}");
+ request.AddHeader("X-Riot-ClientPlatform", Constants.Platform);
+ request.AddHeader("X-Riot-ClientVersion", Constants.Version);
+ 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}");
+ request.AddHeader("X-Riot-ClientPlatform", Constants.Platform);
+ request.AddHeader("X-Riot-ClientVersion", Constants.Version);
+ 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}");
+ request.AddHeader("X-Riot-ClientPlatform", Constants.Platform);
+ request.AddHeader("X-Riot-ClientVersion", Constants.Version);
+ 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 async Task GetPrePlayerInfo(
+ RiotPrePlayer riotPlayer,
+ sbyte index,
+ Guid[] seasonData,
+ PresencesResponse presencesResponse
+ )
+ {
+ Player player = new();
+ try
+ {
+ var cardTask = GetCardAsync(riotPlayer.PlayerIdentity.PlayerCardId, index);
+ var historyTask = GetPlayerHistoryAsync(riotPlayer.Subject, seasonData);
+ var presenceTask = GetPresenceInfoAsync(riotPlayer.Subject, presencesResponse);
+
+ await Task.WhenAll(cardTask, historyTask, presenceTask).ConfigureAwait(false);
+
+ player.IdentityData = cardTask.Result;
+ player.RankData = historyTask.Result;
+ player.PlayerUiData = presenceTask.Result;
+ player.IgnData = await GetIgcUsernameAsync(
+ riotPlayer.Subject,
+ riotPlayer.PlayerIdentity.Incognito,
+ false
+ )
+ .ConfigureAwait(false);
+ player.AccountLevel = !riotPlayer.PlayerIdentity.HideAccountLevel
+ ? riotPlayer.PlayerIdentity.AccountLevel.ToString()
+ : "-";
+ player.TeamId = "Blue";
+ player.Active = Visibility.Visible;
+ }
+ catch (Exception e)
+ {
+ Constants.Log.Error("GetPlayerInfo() (PRE) failed for player {index}: {e}", index, e);
+ }
+
+ return player;
+ }
+
+ private async Task GetLivePlayerInfo(
+ RiotLivePlayer riotPlayer,
+ sbyte index,
+ Guid[] seasonData,
+ PresencesResponse presencesResponse
+ )
+ {
+ Player player = new();
+ try
+ {
+ var agentTask = GetAgentInfoAsync(riotPlayer.CharacterId);
+ var playerTask = GetPlayerHistoryAsync(riotPlayer.Subject, seasonData);
+ var skinTask = GetMatchSkinInfoAsync(index, riotPlayer.PlayerIdentity.PlayerCardId);
+ var presenceTask = GetPresenceInfoAsync(riotPlayer.Subject, presencesResponse);
+
+ await Task.WhenAll(agentTask, playerTask, skinTask, presenceTask).ConfigureAwait(false);
+
+ player.IdentityData = agentTask.Result;
+ player.RankData = playerTask.Result;
+ player.SkinData = skinTask.Result;
+ player.PlayerUiData = presenceTask.Result;
+ player.IgnData = await GetIgcUsernameAsync(
+ riotPlayer.Subject,
+ riotPlayer.PlayerIdentity.Incognito,
+ false
+ )
+ .ConfigureAwait(false);
+ player.AccountLevel = !riotPlayer.PlayerIdentity.HideAccountLevel
+ ? riotPlayer.PlayerIdentity.AccountLevel.ToString()
+ : "-";
+ player.TeamId = riotPlayer.TeamId;
+ player.Active = Visibility.Visible;
+ }
+ catch (Exception e)
+ {
+ Constants.Log.Error("GetPlayerInfo() (LIVE) failed for player {index}: {e}", index, e);
+ }
+
+ return player;
+ }
+
+ private async Task GetPrePlayers(
+ List> playerTasks,
+ PreMatchResponse matchIdInfo,
+ Guid[] seasonData,
+ PresencesResponse presencesResponse
+ )
+ {
+ 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)
+ {
+ playerTasks.Add(GetPrePlayerInfo(riotPlayer, index, seasonData, presencesResponse));
+ index++;
+ }
+ }
+
+ private async Task GetLivePlayers(
+ List> playerTasks,
+ LiveMatchResponse matchIdInfo,
+ Guid[] seasonData,
+ PresencesResponse presencesResponse
+ )
+ {
+ 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)
+ continue;
+
+ playerTasks.Add(GetLivePlayerInfo(riotPlayer, index, seasonData, presencesResponse));
+
+ index++;
+ }
+ }
+
+ private async Task GetMatchResponse()
+ {
+ if (Stage == "pre")
+ {
+ return await GetPreMatchDetailsAsync().ConfigureAwait(false);
+ }
+ return await GetLiveMatchDetailsAsync().ConfigureAwait(false);
+ }
+
+ private void SetServer(dynamic matchIdInfo)
+ {
+ var gamePodId = matchIdInfo.GamePodId;
+ var pods = JsonSerializer.Deserialize>(
+ File.ReadAllText(Constants.LocalAppDataPath + "\\ValAPI\\gamepods.json")
+ );
+ var nameAvailable = pods.TryGetValue(gamePodId, out string serverName);
+ if (!nameAvailable)
+ return;
+ MatchInfo.Server = "🌍 " + serverName;
+ }
+
+ private async Task GetPlayers(
+ UpdateProgress updateProgress,
+ List> playerTasks,
+ Guid[] seasonData,
+ PresencesResponse presencesResponse
+ )
+ {
+ var matchIdInfo = await GetMatchResponse();
+ updateProgress(10);
+
+ if (matchIdInfo == null)
+ return;
+
+ SetServer(matchIdInfo);
+
+ if (Stage == "pre")
+ {
+ await GetPrePlayers(playerTasks, matchIdInfo, seasonData, presencesResponse);
+ return;
+ }
+ await GetLivePlayers(playerTasks, matchIdInfo, seasonData, presencesResponse);
+ }
+
+ private void AddPlayerParties(List playerList)
+ {
+ var playerPartyColors = new List
+ {
+ "Red",
+ "#32e2b2",
+ "DarkOrange",
+ "White",
+ "DeepSkyBlue",
+ "MediumPurple",
+ "SaddleBrown"
+ };
+ List newArray = new();
+ newArray.AddRange(Enumerable.Repeat("Transparent", playerList.Count));
+
+ 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] = playerPartyColors[0];
+ colourused = true;
+ }
+
+ if (!colourused)
+ continue;
+ newArray[i] = playerPartyColors[0];
+ playerPartyColors.RemoveAt(0);
+ }
+ for (var i = 0; i < playerList.Count; i++)
+ playerList[i].PlayerUiData.PartyColour = newArray[i];
+ }
+
+ public async Task> LiveMatchOutputAsync(UpdateProgress updateProgress)
+ {
+ var playerList = new List();
+ var playerTasks = new List>();
+ var seasonData = new Guid[4];
+ var presencesResponse = new PresencesResponse();
+
+ await GetPlayers(updateProgress, playerTasks, seasonData, presencesResponse);
+
+ playerList.AddRange(await Task.WhenAll(playerTasks).ConfigureAwait(false));
+ updateProgress(75);
+
+ try
+ {
+ AddPlayerParties(playerList);
+ updateProgress(100);
+ }
+ catch (Exception e)
+ {
+ Constants.Log.Error("LiveMatchOutputAsync() party colour failed: {e}", e);
+ }
+
+ return playerList;
+ }
+
+ private async Task GetPartyPlayerInfo(Member riotPlayer, sbyte index, Guid[] seasonData)
+ {
+ Player player = new();
+
+ var cardTask = GetCardAsync(riotPlayer.PlayerIdentity.PlayerCardId, index);
+ var historyTask = GetMatchHistoryAsync(riotPlayer.Subject);
+ var playerTask = GetPlayerHistoryAsync(riotPlayer.Subject, seasonData);
+
+ await Task.WhenAll(cardTask, historyTask, playerTask).ConfigureAwait(false);
+
+ player.IdentityData = cardTask.Result;
+ player.MatchHistoryData = historyTask.Result;
+ player.RankData = playerTask.Result;
+ player.PlayerUiData = new PlayerUIData
+ {
+ BackgroundColour = "#252A40",
+ PartyUuid = Partyid,
+ PartyColour = "Transparent",
+ Puuid = riotPlayer.PlayerIdentity.Subject
+ };
+ player.IgnData = await GetIgcUsernameAsync(riotPlayer.Subject, false, true)
+ .ConfigureAwait(false);
+ player.AccountLevel = !riotPlayer.PlayerIdentity.HideAccountLevel
+ ? riotPlayer.PlayerIdentity.AccountLevel.ToString()
+ : "-";
+ player.TeamId = "Blue";
+ player.Active = Visibility.Visible;
+ return player;
+ }
+
+ private async Task GetPartyPlayers(PartyResponse partyInfo, List> playerTasks)
+ {
+ if (partyInfo == null)
+ return;
+
+ var seasonData = await GetSeasonsAsync().ConfigureAwait(false);
+ sbyte index = 0;
+
+ foreach (var riotPlayer in partyInfo.Members)
+ {
+ playerTasks.Add(GetPartyPlayerInfo(riotPlayer, index, seasonData));
+ index++;
+ }
+ }
+
+ public async Task> PartyOutputAsync()
+ {
+ var playerList = new List();
+ var playerTasks = new List>();
+ var partyInfo = await GetPartyDetailsAsync().ConfigureAwait(false);
+
+ await GetPartyPlayers(partyInfo, playerTasks);
+
+ playerList.AddRange(await Task.WhenAll(playerTasks).ConfigureAwait(false));
+
+ return playerList;
+ }
+
+ private static async Task GetIgcUsernameAsync(
+ Guid puuid,
+ bool isIncognito,
+ bool inParty
+ )
+ {
+ IgnData ignData = new();
+ ignData.TrackerEnabled = Visibility.Hidden;
+ ignData.TrackerDisabled = Visibility.Visible;
+
+ if (isIncognito && !inParty)
+ {
+ ignData.Username = "----";
+ return ignData;
+ }
+
+ ignData.Username = await GetNameServiceGetUsernameAsync(puuid).ConfigureAwait(false);
+
+ var trackerUri = await TrackerAsync(ignData.Username).ConfigureAwait(false);
+
+ if (trackerUri != null)
+ {
+ ignData.TrackerEnabled = Visibility.Visible;
+ ignData.TrackerDisabled = Visibility.Collapsed;
+ ignData.TrackerUri = trackerUri;
+ ignData.Username = ignData.Username + " 🔗";
+ }
+
+ return ignData;
+ }
+
+ private static async Task GetAgentInfoAsync(Guid agentid)
+ {
+ IdentityData identityData = new();
+
+ if (agentid == Guid.Empty)
+ {
+ Constants.Log.Error("GetAgentInfoAsync Failed: AgentID is empty");
+ identityData.Image = null;
+ identityData.Name = "";
+ return identityData;
+ }
+
+ identityData.Image = new Uri(
+ Constants.LocalAppDataPath + $"\\ValAPI\\agentsimg\\{agentid}.png"
+ );
+ var agents = JsonSerializer.Deserialize>(
+ await File.ReadAllTextAsync(Constants.LocalAppDataPath + "\\ValAPI\\agents.json")
+ .ConfigureAwait(false)
+ );
+ agents.TryGetValue(agentid, out var agentName);
+ identityData.Name = agentName;
+ return identityData;
+ }
+
+ private static async Task GetCardAsync(Guid cardid, sbyte index)
+ {
+ if (cardid != Guid.Empty)
+ {
+ var cards = JsonSerializer.Deserialize>(
+ await File.ReadAllTextAsync(Constants.LocalAppDataPath + "\\ValAPI\\cards.json")
+ .ConfigureAwait(false)
+ );
+ cards.TryGetValue(cardid, out var card);
+ return new IdentityData
+ {
+ Image = card.Image,
+ Name = Resources.Player + " " + (index + 1)
+ };
+ }
+
+ Constants.Log.Error("GetCardAsync Failed: CardID is empty");
+ return new IdentityData();
+ }
+
+ private static async Task GetMatchSkinInfoAsync(sbyte playerno, Guid cardid)
+ {
+ 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);
+ return await GetSkinInfoAsync(content.Loadouts[playerno].Loadout, cardid)
+ .ConfigureAwait(false);
+ }
+
+ Constants.Log.Error("GetMatchSkinInfoAsync Failed: {e}", response.ErrorException);
+ return new SkinData();
+ }
+
+ private static async Task GetPreSkinInfoAsync(sbyte playerno, Guid cardid)
+ {
+ 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
+ );
+ return await GetSkinInfoAsync(content.Loadouts[playerno], cardid);
+ }
+ catch
+ {
+ // ignored
+ }
+
+ Constants.Log.Error("GetPreSkinInfoAsync Failed: {e}", response.ErrorException);
+ return new SkinData();
+ }
+
+ private static async Task GetSkinInfoAsync(LoadoutLoadout loadout, Guid cardid)
+ {
+ Dictionary cards = null;
+ Dictionary sprays = null;
+ Dictionary skins = null;
+ try
+ {
+ skins = JsonSerializer.Deserialize>(
+ await File.ReadAllTextAsync(
+ Constants.LocalAppDataPath + "\\ValAPI\\skinchromas.json"
+ )
+ .ConfigureAwait(false)
+ );
+ cards = JsonSerializer.Deserialize>(
+ await File.ReadAllTextAsync(Constants.LocalAppDataPath + "\\ValAPI\\cards.json")
+ .ConfigureAwait(false)
+ );
+ sprays = JsonSerializer.Deserialize>(
+ await File.ReadAllTextAsync(Constants.LocalAppDataPath + "\\ValAPI\\sprays.json")
+ .ConfigureAwait(false)
+ );
+ }
+ catch (Exception e)
+ {
+ Constants.Log.Error("GetSkinInfoAsync failed: {e}", e);
+ }
+
+ var skinData = new SkinData
+ {
+ CardImage = cards[cardid].Image,
+ LargeCardImage = cards[cardid].FullImage,
+ CardName = cards[cardid].Name,
+ Spray1Image = sprays[loadout.Sprays.SpraySelections[0].SprayId].Image,
+ Spray1Name = sprays[loadout.Sprays.SpraySelections[0].SprayId].Name,
+ Spray2Image = sprays[loadout.Sprays.SpraySelections[1].SprayId].Image,
+ Spray2Name = sprays[loadout.Sprays.SpraySelections[1].SprayId].Name,
+ Spray3Image = sprays[loadout.Sprays.SpraySelections[2].SprayId].Image,
+ Spray3Name = sprays[loadout.Sprays.SpraySelections[2].SprayId].Name,
+ Spray4Image = sprays[loadout.Sprays.SpraySelections[3].SprayId].Image,
+ Spray4Name = sprays[loadout.Sprays.SpraySelections[3].SprayId].Name,
+ ClassicImage = skins[
+ loadout.Items["29a0cfab-485b-f5d5-779a-b59f85e204a8"].Sockets[
+ "3ad1b2b2-acdb-4524-852f-954a76ddae0a"
+ ]
+ .Item
+ .Id
+ ].Image,
+ ClassicName = skins[
+ loadout.Items["29a0cfab-485b-f5d5-779a-b59f85e204a8"].Sockets[
+ "3ad1b2b2-acdb-4524-852f-954a76ddae0a"
+ ]
+ .Item
+ .Id
+ ].Name,
+ ShortyImage = skins[
+ loadout.Items["42da8ccc-40d5-affc-beec-15aa47b42eda"].Sockets[
+ "3ad1b2b2-acdb-4524-852f-954a76ddae0a"
+ ]
+ .Item
+ .Id
+ ].Image,
+ ShortyName = skins[
+ loadout.Items["42da8ccc-40d5-affc-beec-15aa47b42eda"].Sockets[
+ "3ad1b2b2-acdb-4524-852f-954a76ddae0a"
+ ]
+ .Item
+ .Id
+ ].Name,
+ FrenzyImage = skins[
+ loadout.Items["44d4e95c-4157-0037-81b2-17841bf2e8e3"].Sockets[
+ "3ad1b2b2-acdb-4524-852f-954a76ddae0a"
+ ]
+ .Item
+ .Id
+ ].Image,
+ FrenzyName = skins[
+ loadout.Items["44d4e95c-4157-0037-81b2-17841bf2e8e3"].Sockets[
+ "3ad1b2b2-acdb-4524-852f-954a76ddae0a"
+ ]
+ .Item
+ .Id
+ ].Name,
+ GhostImage = skins[
+ loadout.Items["1baa85b4-4c70-1284-64bb-6481dfc3bb4e"].Sockets[
+ "3ad1b2b2-acdb-4524-852f-954a76ddae0a"
+ ]
+ .Item
+ .Id
+ ].Image,
+ GhostName = skins[
+ loadout.Items["1baa85b4-4c70-1284-64bb-6481dfc3bb4e"].Sockets[
+ "3ad1b2b2-acdb-4524-852f-954a76ddae0a"
+ ]
+ .Item
+ .Id
+ ].Name,
+ SheriffImage = skins[
+ loadout.Items["e336c6b8-418d-9340-d77f-7a9e4cfe0702"].Sockets[
+ "3ad1b2b2-acdb-4524-852f-954a76ddae0a"
+ ]
+ .Item
+ .Id
+ ].Image,
+ SheriffName = skins[
+ loadout.Items["e336c6b8-418d-9340-d77f-7a9e4cfe0702"].Sockets[
+ "3ad1b2b2-acdb-4524-852f-954a76ddae0a"
+ ]
+ .Item
+ .Id
+ ].Name,
+ StingerImage = skins[
+ loadout.Items["f7e1b454-4ad4-1063-ec0a-159e56b58941"].Sockets[
+ "3ad1b2b2-acdb-4524-852f-954a76ddae0a"
+ ]
+ .Item
+ .Id
+ ].Image,
+ StingerName = skins[
+ loadout.Items["f7e1b454-4ad4-1063-ec0a-159e56b58941"].Sockets[
+ "3ad1b2b2-acdb-4524-852f-954a76ddae0a"
+ ]
+ .Item
+ .Id
+ ].Name,
+ SpectreImage = skins[
+ loadout.Items["462080d1-4035-2937-7c09-27aa2a5c27a7"].Sockets[
+ "3ad1b2b2-acdb-4524-852f-954a76ddae0a"
+ ]
+ .Item
+ .Id
+ ].Image,
+ SpectreName = skins[
+ loadout.Items["462080d1-4035-2937-7c09-27aa2a5c27a7"].Sockets[
+ "3ad1b2b2-acdb-4524-852f-954a76ddae0a"
+ ]
+ .Item
+ .Id
+ ].Name,
+ BuckyImage = skins[
+ loadout.Items["910be174-449b-c412-ab22-d0873436b21b"].Sockets[
+ "3ad1b2b2-acdb-4524-852f-954a76ddae0a"
+ ]
+ .Item
+ .Id
+ ].Image,
+ BuckyName = skins[
+ loadout.Items["910be174-449b-c412-ab22-d0873436b21b"].Sockets[
+ "3ad1b2b2-acdb-4524-852f-954a76ddae0a"
+ ]
+ .Item
+ .Id
+ ].Name,
+ JudgeImage = skins[
+ loadout.Items["ec845bf4-4f79-ddda-a3da-0db3774b2794"].Sockets[
+ "3ad1b2b2-acdb-4524-852f-954a76ddae0a"
+ ]
+ .Item
+ .Id
+ ].Image,
+ JudgeName = skins[
+ loadout.Items["ec845bf4-4f79-ddda-a3da-0db3774b2794"].Sockets[
+ "3ad1b2b2-acdb-4524-852f-954a76ddae0a"
+ ]
+ .Item
+ .Id
+ ].Name,
+ BulldogImage = skins[
+ loadout.Items["ae3de142-4d85-2547-dd26-4e90bed35cf7"].Sockets[
+ "3ad1b2b2-acdb-4524-852f-954a76ddae0a"
+ ]
+ .Item
+ .Id
+ ].Image,
+ BulldogName = skins[
+ loadout.Items["ae3de142-4d85-2547-dd26-4e90bed35cf7"].Sockets[
+ "3ad1b2b2-acdb-4524-852f-954a76ddae0a"
+ ]
+ .Item
+ .Id
+ ].Name,
+ GuardianImage = skins[
+ loadout.Items["4ade7faa-4cf1-8376-95ef-39884480959b"].Sockets[
+ "3ad1b2b2-acdb-4524-852f-954a76ddae0a"
+ ]
+ .Item
+ .Id
+ ].Image,
+ GuardianName = skins[
+ loadout.Items["4ade7faa-4cf1-8376-95ef-39884480959b"].Sockets[
+ "3ad1b2b2-acdb-4524-852f-954a76ddae0a"
+ ]
+ .Item
+ .Id
+ ].Name,
+ PhantomImage = skins[
+ loadout.Items["ee8e8d15-496b-07ac-e5f6-8fae5d4c7b1a"].Sockets[
+ "3ad1b2b2-acdb-4524-852f-954a76ddae0a"
+ ]
+ .Item
+ .Id
+ ].Image,
+ PhantomName = skins[
+ loadout.Items["ee8e8d15-496b-07ac-e5f6-8fae5d4c7b1a"].Sockets[
+ "3ad1b2b2-acdb-4524-852f-954a76ddae0a"
+ ]
+ .Item
+ .Id
+ ].Name,
+ VandalImage = skins[
+ loadout.Items["9c82e19d-4575-0200-1a81-3eacf00cf872"].Sockets[
+ "3ad1b2b2-acdb-4524-852f-954a76ddae0a"
+ ]
+ .Item
+ .Id
+ ].Image,
+ VandalName = skins[
+ loadout.Items["9c82e19d-4575-0200-1a81-3eacf00cf872"].Sockets[
+ "3ad1b2b2-acdb-4524-852f-954a76ddae0a"
+ ]
+ .Item
+ .Id
+ ].Name,
+ MarshalImage = skins[
+ loadout.Items["c4883e50-4494-202c-3ec3-6b8a9284f00b"].Sockets[
+ "3ad1b2b2-acdb-4524-852f-954a76ddae0a"
+ ]
+ .Item
+ .Id
+ ].Image,
+ MarshalName = skins[
+ loadout.Items["c4883e50-4494-202c-3ec3-6b8a9284f00b"].Sockets[
+ "3ad1b2b2-acdb-4524-852f-954a76ddae0a"
+ ]
+ .Item
+ .Id
+ ].Name,
+ OutlawImage = skins[
+ loadout.Items["5f0aaf7a-4289-3998-d5ff-eb9a5cf7ef5c"].Sockets[
+ "3ad1b2b2-acdb-4524-852f-954a76ddae0a"
+ ]
+ .Item
+ .Id
+ ].Image,
+ OutlawName = skins[
+ loadout.Items["5f0aaf7a-4289-3998-d5ff-eb9a5cf7ef5c"].Sockets[
+ "3ad1b2b2-acdb-4524-852f-954a76ddae0a"
+ ]
+ .Item
+ .Id
+ ].Name,
+ OperatorImage = skins[
+ loadout.Items["a03b24d3-4319-996d-0f8c-94bbfba1dfc7"].Sockets[
+ "3ad1b2b2-acdb-4524-852f-954a76ddae0a"
+ ]
+ .Item
+ .Id
+ ].Image,
+ OperatorName = skins[
+ loadout.Items["a03b24d3-4319-996d-0f8c-94bbfba1dfc7"].Sockets[
+ "3ad1b2b2-acdb-4524-852f-954a76ddae0a"
+ ]
+ .Item
+ .Id
+ ].Name,
+ AresImage = skins[
+ loadout.Items["55d8a0f4-4274-ca67-fe2c-06ab45efdf58"].Sockets[
+ "3ad1b2b2-acdb-4524-852f-954a76ddae0a"
+ ]
+ .Item
+ .Id
+ ].Image,
+ AresName = skins[
+ loadout.Items["55d8a0f4-4274-ca67-fe2c-06ab45efdf58"].Sockets[
+ "3ad1b2b2-acdb-4524-852f-954a76ddae0a"
+ ]
+ .Item
+ .Id
+ ].Name,
+ OdinImage = skins[
+ loadout.Items["63e6c2b6-4a8e-869c-3d4c-e38355226584"].Sockets[
+ "3ad1b2b2-acdb-4524-852f-954a76ddae0a"
+ ]
+ .Item
+ .Id
+ ].Image,
+ OdinName = skins[
+ loadout.Items["63e6c2b6-4a8e-869c-3d4c-e38355226584"].Sockets[
+ "3ad1b2b2-acdb-4524-852f-954a76ddae0a"
+ ]
+ .Item
+ .Id
+ ].Name,
+ MeleeImage = skins[
+ loadout.Items["2f59173c-4bed-b6c3-2191-dea9b58be9c7"].Sockets[
+ "3ad1b2b2-acdb-4524-852f-954a76ddae0a"
+ ]
+ .Item
+ .Id
+ ].Image,
+ MeleeName = skins[
+ loadout.Items["2f59173c-4bed-b6c3-2191-dea9b58be9c7"].Sockets[
+ "3ad1b2b2-acdb-4524-852f-954a76ddae0a"
+ ]
+ .Item
+ .Id
+ ].Name
+ };
+ if (skinData == null)
+ Constants.Log.Error("GetSkinInfoAsync failed: skinData is null");
+
+ return skinData;
+ }
+
+ public static async Task GetMatchHistoryAsync(Guid puuid)
+ {
+ MatchHistoryData history =
+ new()
+ {
+ PreviousGameColours = new string[3] { "#7f7f7f", "#7f7f7f", "#7f7f7f" },
+ PreviousGames = new int[3]
+ };
+
+ try
+ {
+ if (puuid == Guid.Empty)
+ {
+ Constants.Log.Error("GetMatchHistoryAsync: Puuid is null");
+ return history;
+ }
+ var response = await DoCachedRequestAsync(
+ Method.Get,
+ $"https://pd.{Constants.Region}.a.pvp.net/mmr/v1/players/{puuid}/competitiveupdates?queue=competitive",
+ true
+ )
+ .ConfigureAwait(false);
+ if (!response.IsSuccessful)
+ {
+ Constants.Log.Error(
+ "GetMatchHistoryAsync 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)
+ {
+ return history;
+ }
+
+ history.RankProgress = content.Matches[0].RankedRatingAfterUpdate;
+
+ for (int i = 0; i < 3; i++)
+ {
+ if (i > content.Matches.Length)
+ break;
+ var match = content.Matches[i].RankedRatingEarned;
+ history.PreviousGames[i] = Math.Abs(match);
+ history.PreviousGameColours[i] = match switch
+ {
+ > 0 => "#32e2b2",
+ < 0 => "#ff4654",
+ _ => "#7f7f7f"
+ };
+ }
+ }
+ catch (Exception e)
+ {
+ Constants.Log.Error("GetMatchHistoryAsync failed: {e}", e);
+ }
+
+ return history;
+ }
+
+ private static async Task GetPlayerHistoryAsync(Guid puuid, Guid[] seasonData)
+ {
+ var rankData = new RankData();
+ var ranks = new int[4];
+
+ rankData.RankImages = new Uri[ranks.Length];
+ rankData.RankNames = new string[ranks.Length];
+ Array.Fill(
+ rankData.RankImages,
+ new Uri(Constants.LocalAppDataPath + $"\\ValAPI\\ranksimg\\0.png")
+ );
+ Array.Fill(rankData.RankNames, "UNRATED");
+
+ if (puuid == Guid.Empty)
+ {
+ Constants.Log.Error("GetPlayerHistoryAsync Failed: PUUID is empty");
+ return rankData;
+ }
+ var response = await DoCachedRequestAsync(
+ Method.Get,
+ $"https://pd.{Constants.Region}.a.pvp.net/mmr/v1/players/{puuid}",
+ true
+ )
+ .ConfigureAwait(false);
+
+ if (!response.IsSuccessful && response.Content != null)
+ {
+ Constants.Log.Error("GetPlayerHistoryAsync Failed: {e}", response.ErrorException);
+ return rankData;
+ }
+
+ var options = new JsonSerializerOptions
+ {
+ DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingDefault
+ };
+ var content = JsonSerializer.Deserialize(response.Content, options);
+
+ if (content.QueueSkills.Competitive.SeasonalInfoBySeasonId is null)
+ {
+ Constants.Log.Error("GetPlayerHistoryAsync Failed; seasonInfoById is null");
+ return rankData;
+ }
+
+ var SeasonInfo = content.QueueSkills.Competitive.SeasonalInfoBySeasonId.Act;
+
+ for (int i = 0; i < ranks.Length; i++)
+ {
+ if (!SeasonInfo.TryGetValue(seasonData[i].ToString(), out var currentActJsonElement))
+ continue;
+
+ var act = currentActJsonElement.Deserialize();
+ var rank = act.CompetitiveTier;
+
+ if (rank is 1 or 2)
+ rank = 0;
+ if (Constants.BeforeAscendantSeasons.Contains(seasonData[i]))
+ rank += 3;
+
+ ranks[i] = rank;
+ }
+
+ if (ranks[0] >= 24)
+ {
+ var leaderboardResponse = await DoCachedRequestAsync(
+ Method.Get,
+ $"https://pd.{Constants.Shard}.a.pvp.net/mmr/v1/leaderboards/affinity/{Constants.Region}/queue/competitive/season/{seasonData[0]}?startIndex=0&size=0",
+ true
+ )
+ .ConfigureAwait(false);
+ if (leaderboardResponse.Content != null && leaderboardResponse.IsSuccessful)
+ {
+ var leaderboardcontent = JsonSerializer.Deserialize(
+ leaderboardResponse.Content
+ );
+ try
+ {
+ rankData.MaxRr = leaderboardcontent.TierDetails[
+ ranks[0].ToString()
+ ].RankedRatingThreshold;
+ }
+ catch (Exception e)
+ {
+ Constants.Log.Error(
+ "GetPlayerHistoryAsync Failed; leaderboardcontent error: {e}",
+ e
+ );
+ }
+ }
+ else
+ {
+ Constants.Log.Error(
+ "GetPlayerHistoryAsync Failed; leaderboardResponse error: {e}",
+ leaderboardResponse.ErrorException
+ );
+ }
+ }
+
+ try
+ {
+ var rankNames = JsonSerializer.Deserialize>(
+ await File.ReadAllTextAsync(
+ Constants.LocalAppDataPath + "\\ValAPI\\competitivetiers.json"
+ )
+ .ConfigureAwait(false)
+ );
+
+ for (int i = 0; i < ranks.Length; i++)
+ {
+ rankNames.TryGetValue(ranks[i], out var rank);
+ rankData.RankImages[i] = new Uri(
+ Constants.LocalAppDataPath + $"\\ValAPI\\ranksimg\\{ranks[i]}.png"
+ );
+ rankData.RankNames[i] = rank;
+ }
+ }
+ catch (Exception e)
+ {
+ Constants.Log.Error("GetPlayerHistoryAsync Failed; rank dictionary error: {e}", e);
+ }
+
+ return rankData;
+ }
+
+ private static async Task GetSeasonsAsync()
+ {
+ var seasonData = new Guid[4];
+ try
+ {
+ var response = await DoCachedRequestAsync(
+ Method.Get,
+ $"https://shared.{Constants.Region}.a.pvp.net/content-service/v3/content",
+ true
+ );
+
+ if (!response.IsSuccessful)
+ {
+ Constants.Log.Error("GetSeasonsAsync Failed: {e}", response.ErrorException);
+ return seasonData;
+ }
+
+ var data = JsonSerializer.Deserialize(response.Content);
+
+ sbyte index = 0;
+ var seasons = data.Seasons.Reverse();
+ var acts = seasons.Where(season => season.Type == "act");
+
+ foreach (var act in acts)
+ {
+ if (index >= seasonData.Length)
+ break;
+ if (index > 0)
+ {
+ seasonData[index] = act.Id;
+ index++;
+ }
+ if (index == 0 & act.IsActive)
+ {
+ seasonData[0] = act.Id;
+ index++;
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ Constants.Log.Error("GetSeasonsAsync Failed: {Exception}", e);
+ }
+
+ return seasonData;
+ }
+
+ private static async Task TrackerAsync(string username)
+ {
+ if (string.IsNullOrEmpty(username))
+ return null;
+ try
+ {
+ var encodedUsername = Uri.EscapeDataString(username);
+ var url = new Uri(
+ "https://api.tracker.network/api/v2/valorant/standard/profile/riot/"
+ + encodedUsername
+ );
+ var response = await DoCachedRequestAsync(
+ Method.Get,
+ url.ToString(),
+ false,
+ false,
+ false,
+ "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.141 Safari/537.36 OverwolfClient/0.190.0.13"
+ )
+ .ConfigureAwait(false);
+ var numericStatusCode = (short)response.StatusCode;
+ if (numericStatusCode == 200)
+ return new Uri("https://tracker.gg/valorant/profile/riot/" + encodedUsername);
+ }
+ 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 base64String = "";
+ try
+ {
+ base64String = Convert.ToBase64String(
+ Encoding.UTF8.GetBytes($"riot:{Constants.LPassword}")
+ );
+ }
+ catch (Exception e)
+ {
+ Constants.Log.Error("GetPresencesAsync Failed; To Base 64 failed: {Exception}", e);
+ return null;
+ }
+
+ var request = new RestRequest()
+ .AddHeader("Authorization", $"Basic {base64String}")
+ .AddHeader("X-Riot-ClientPlatform", Constants.Platform)
+ .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}. Presences: {presences}",
+ response.ErrorException,
+ response.Data
+ );
+ return null;
+ }
+
+ private async Task GetPresenceInfoAsync(Guid puuid, PresencesResponse presences)
+ {
+ PlayerUIData playerUiData = new() { BackgroundColour = "#252A40", Puuid = puuid };
+
+ try
+ {
+ var friend = presences.Presences.First(friend => friend.Puuid == puuid);
+ var json = Encoding.UTF8.GetString(Convert.FromBase64String(friend.Private));
+ var content = JsonSerializer.Deserialize(json);
+ if (content == null)
+ return playerUiData;
+
+ playerUiData.PartyUuid = content.PartyId;
+
+ if (puuid != Constants.Ppuuid)
+ return playerUiData;
+
+ var maps = JsonSerializer.Deserialize>(
+ await File.ReadAllTextAsync(Constants.LocalAppDataPath + "\\ValAPI\\maps.json")
+ .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"
+ );
+ return playerUiData;
+ }
+ 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;
+ }
+
+ MatchInfo.GameMode = gameModeName;
+
+ if (string.IsNullOrEmpty(gameModeName))
+ {
+ var gamemodes = JsonSerializer.Deserialize>(
+ await File.ReadAllTextAsync(
+ Constants.LocalAppDataPath + "\\ValAPI\\gamemode.json"
+ )
+ .ConfigureAwait(false)
+ );
+ gamemodes.TryGetValue(gameModeId, out var gamemode);
+ MatchInfo.GameMode = gamemode;
+ }
+
+ MatchInfo.GameModeImage = new Uri(
+ Constants.LocalAppDataPath + $"\\ValAPI\\gamemodeimg\\{gameModeId}.png"
+ );
+ }
+ catch (InvalidOperationException)
+ {
+ return playerUiData;
+ }
+ catch (Exception e)
+ {
+ Constants.Log.Error("GetPresenceInfoAsync Failed; To Base 64 failed: {Exception}", e);
+ }
+
+ return playerUiData;
+ }
+}
diff --git a/NOWT/Helpers/Login.cs b/NOWT/Helpers/Login.cs
new file mode 100644
index 00000000..58230189
--- /dev/null
+++ b/NOWT/Helpers/Login.cs
@@ -0,0 +1,207 @@
+using System;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Text.Json;
+using System.Threading.Tasks;
+using RestSharp;
+using NOWT.Objects;
+
+namespace NOWT.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", Constants.Platform)
+ .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;
+ }
+
+ foreach (
+ var parts in from session in response.Data.ExtensionData
+ select session.Value.Deserialize() into game
+ where game is { ProductId: "valorant" }
+ select game.LaunchConfiguration.Arguments[4].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;
+ }
+
+ break;
+ }
+ }
+
+ public static void AddAuthToRequest(RestRequest request)
+ {
+ request.AddHeader("X-Riot-Entitlements-JWT", Constants.EntitlementToken);
+ request.AddHeader("Authorization", $"Bearer {Constants.AccessToken}");
+ request.AddHeader("X-Riot-ClientPlatform", Constants.Platform);
+ request.AddHeader("X-Riot-ClientVersion", Constants.Version);
+ }
+
+ public static async Task GetNameServiceGetUsernamesAsync(Guid[] puuids)
+ {
+ if (puuids.Length == 0)
+ 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 };
+
+ AddAuthToRequest(request);
+
+ string[] body = new string[puuids.Length];
+ for (int i = 0; i < puuids.Length; i++)
+ {
+ body[i] = puuids[i].ToString();
+ }
+
+ request.AddJsonBody(body);
+ var response = await client.ExecutePutAsync(request).ConfigureAwait(false);
+ string[] names = new string[puuids.Length];
+ if (response.IsSuccessful)
+ try
+ {
+ var incorrectContent = response.Content.Replace("\n", string.Empty);
+ var content = JsonSerializer.Deserialize(incorrectContent);
+ for (int i = 0; i < puuids.Length; i++)
+ {
+ names[i] = content[i].GameName + "#" + content[i].TagLine;
+ }
+ return names;
+ }
+ catch (Exception e)
+ {
+ Constants.Log.Error("GetNameServiceGetUsernameAsync Failed: {e}", e);
+ return new string[] { "" };
+ }
+
+ Constants.Log.Error("GetNameServiceGetUsernameAsync Failed: {e}", response.ErrorException);
+ return new string[] { "" };
+ }
+
+ public static async Task GetNameServiceGetUsernameAsync(Guid puuid)
+ {
+ if (puuid == Guid.Empty)
+ return null;
+ string[] names = await GetNameServiceGetUsernamesAsync(new Guid[1] { puuid });
+ return names[0];
+ }
+
+ private static async Task GetLatestVersionAsync()
+ {
+ var lines = await File.ReadAllLinesAsync(
+ Constants.LocalAppDataPath + "\\ValAPI\\version.json"
+ )
+ .ConfigureAwait(false);
+ Constants.Version = lines[0];
+ }
+
+ public static async Task DoCachedRequestAsync(
+ Method method,
+ string url,
+ bool addRiotAuth,
+ bool bypassCache = false,
+ bool displayError = true,
+ string? userAgent = null
+ )
+ {
+ var attemptCache = method == Method.Get && !bypassCache;
+ if (attemptCache)
+ if (Constants.UrlToBody.TryGetValue(url, out var res))
+ return res;
+ var client = new RestClient(url);
+
+ if (userAgent is not null)
+ {
+ client.AddDefaultHeader("User-Agent", userAgent);
+ }
+
+ var request = new RestRequest();
+ if (addRiotAuth)
+ {
+ AddAuthToRequest(request);
+ }
+
+ var response = await client.ExecuteAsync(request, method).ConfigureAwait(false);
+ if (!response.IsSuccessful && displayError)
+ {
+ Constants.Log.Error("Request to {url} Failed: {e}", url, response.ErrorException);
+ return response;
+ }
+
+ if (attemptCache)
+ Constants.UrlToBody.TryAdd(url, response);
+ return response;
+ }
+}
diff --git a/NOWT/Helpers/ValAPI.cs b/NOWT/Helpers/ValAPI.cs
new file mode 100644
index 00000000..6fe26cbd
--- /dev/null
+++ b/NOWT/Helpers/ValAPI.cs
@@ -0,0 +1,548 @@
+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 NOWT.Objects;
+using Settings = NOWT.Properties.Settings;
+
+namespace NOWT.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 _spraysInfo;
+ private static Urls _gamemodeInfo;
+ private static Urls _podsInfo;
+ 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> Fetch(string url)
+ {
+ var request = new RestRequest(url);
+ return await Client.ExecuteGetAsync(request).ConfigureAwait(false);
+ }
+
+ private static async Task GetValApiVersionAsync()
+ {
+ var response = await Fetch("/version");
+ return !response.IsSuccessful ? null : response.Data.Data.BuildDate;
+ }
+
+ private static async Task GetLocalValApiVersionAsync()
+ {
+ if (!File.Exists(Constants.LocalAppDataPath + "\\ValAPI\\version.json"))
+ return null;
+ try
+ {
+ var lines = await File.ReadAllLinesAsync(
+ Constants.LocalAppDataPath + "\\ValAPI\\version.json"
+ )
+ .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.json",
+ Url = $"/maps?language={language}"
+ };
+ _agentsInfo = new Urls
+ {
+ Name = "Agents",
+ Filepath = Constants.LocalAppDataPath + "\\ValAPI\\agents.json",
+ Url = $"/agents?language={language}"
+ };
+ _skinsInfo = new Urls
+ {
+ Name = "Skins",
+ Filepath = Constants.LocalAppDataPath + "\\ValAPI\\skinchromas.json",
+ Url = $"/weapons/skinchromas?language={language}"
+ };
+ _cardsInfo = new Urls
+ {
+ Name = "Cards",
+ Filepath = Constants.LocalAppDataPath + "\\ValAPI\\cards.json",
+ Url = $"/playercards?language={language}"
+ };
+ _spraysInfo = new Urls
+ {
+ Name = "Sprays",
+ Filepath = Constants.LocalAppDataPath + "\\ValAPI\\sprays.json",
+ Url = $"/sprays?language={language}"
+ };
+ _ranksInfo = new Urls
+ {
+ Name = "Ranks",
+ Filepath = Constants.LocalAppDataPath + "\\ValAPI\\competitivetiers.json",
+ Url = $"/competitivetiers?language={language}"
+ };
+ _versionInfo = new Urls
+ {
+ Name = "Version",
+ Filepath = Constants.LocalAppDataPath + "\\ValAPI\\version.json",
+ Url = "/version"
+ };
+ _gamemodeInfo = new Urls
+ {
+ Name = "Gamemode",
+ Filepath = Constants.LocalAppDataPath + "\\ValAPI\\gamemode.json",
+ Url = $"/gamemodes?language={language}"
+ };
+ _podsInfo = new Urls
+ {
+ Name = "Gamepods",
+ Filepath = Constants.LocalAppDataPath + "\\ValAPI\\gamepods.json",
+ Url = $"../internal/locres/{language}"
+ };
+ _allInfo = new List
+ {
+ _mapsInfo,
+ _agentsInfo,
+ _ranksInfo,
+ _versionInfo,
+ _skinsInfo,
+ _cardsInfo,
+ _spraysInfo,
+ _gamemodeInfo,
+ _podsInfo
+ };
+ 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)
+ {
+ Constants.Log.Error(
+ "updateVersion Failed, Response:{error}",
+ versionResponse.ErrorException
+ );
+ return;
+ }
+ string[] lines =
+ {
+ versionResponse.Data?.Data.RiotClientVersion,
+ versionResponse.Data?.Data.BuildDate
+ };
+ await File.WriteAllLinesAsync(_versionInfo.Filepath, lines).ConfigureAwait(false);
+ }
+
+ async Task UpdateMapsDictionary()
+ {
+ var mapsResponse = await Fetch(_mapsInfo.Url);
+ if (!mapsResponse.IsSuccessful)
+ {
+ Constants.Log.Error(
+ "updateMapsDictionary Failed, Response:{error}",
+ mapsResponse.ErrorException
+ );
+ return;
+ }
+ 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);
+ }
+
+ async Task UpdateAgentsDictionary()
+ {
+ var agentsResponse = await Fetch(_agentsInfo.Url);
+ if (!agentsResponse.IsSuccessful)
+ {
+ Constants.Log.Error(
+ "updateAgentsDictionary Failed, Response:{error}",
+ agentsResponse.ErrorException
+ );
+ return;
+ }
+ 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);
+ }
+
+ async Task UpdateSkinsDictionary()
+ {
+ var skinsResponse = await Fetch(_skinsInfo.Url);
+ if (!skinsResponse.IsSuccessful)
+ {
+ Constants.Log.Error(
+ "updateSkinsDictionary Failed, Response:{error}",
+ skinsResponse.ErrorException
+ );
+ return;
+ }
+ Dictionary skinsDictionary = new();
+ if (skinsResponse.Data != null)
+ foreach (var skin in skinsResponse.Data.Data)
+ skinsDictionary.TryAdd(
+ skin.Uuid,
+ new ValNameImage { Name = skin.DisplayName, Image = skin.FullRender }
+ );
+ await File.WriteAllTextAsync(
+ _skinsInfo.Filepath,
+ JsonSerializer.Serialize(skinsDictionary)
+ )
+ .ConfigureAwait(false);
+ }
+
+ async Task UpdateCardsDictionary()
+ {
+ var cardsResponse = await Fetch(_cardsInfo.Url);
+ if (!cardsResponse.IsSuccessful)
+ {
+ Constants.Log.Error(
+ "updateCardsDictionary Failed, Response:{error}",
+ cardsResponse.ErrorException
+ );
+ return;
+ }
+ Dictionary cardsDictionary = new();
+ if (cardsResponse.Data != null)
+ foreach (var card in cardsResponse.Data.Data)
+ cardsDictionary.TryAdd(
+ card.Uuid,
+ new ValCard
+ {
+ Name = card.DisplayName,
+ Image = card.DisplayIcon,
+ FullImage = card.LargeArt
+ }
+ );
+ await File.WriteAllTextAsync(
+ _cardsInfo.Filepath,
+ JsonSerializer.Serialize(cardsDictionary)
+ )
+ .ConfigureAwait(false);
+ }
+
+ async Task UpdateSpraysDictionary()
+ {
+ var spraysResponse = await Fetch(_spraysInfo.Url);
+ if (!spraysResponse.IsSuccessful)
+ {
+ Constants.Log.Error(
+ "updateSpraysDictionary Failed, Response:{error}",
+ spraysResponse.ErrorException
+ );
+ return;
+ }
+ Dictionary spraysDictionary = new();
+ if (spraysResponse.Data != null)
+ foreach (var spray in spraysResponse.Data.Data)
+ spraysDictionary.TryAdd(
+ spray.Uuid,
+ new ValNameImage
+ {
+ Name = spray.DisplayName,
+ Image = spray.FullTransparentIcon
+ }
+ );
+ await File.WriteAllTextAsync(
+ _spraysInfo.Filepath,
+ JsonSerializer.Serialize(spraysDictionary)
+ )
+ .ConfigureAwait(false);
+ }
+
+ async Task UpdateRanksDictionary()
+ {
+ var ranksRequest = new RestRequest(_ranksInfo.Url);
+ var ranksResponse = await Client
+ .ExecuteGetAsync(ranksRequest)
+ .ConfigureAwait(false);
+ if (!ranksResponse.IsSuccessful)
+ {
+ Constants.Log.Error(
+ "updateRanksDictionary Failed, Response:{error}",
+ ranksResponse.ErrorException
+ );
+ return;
+ }
+ 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);
+ }
+
+ async Task UpdateGamemodeDictionary()
+ {
+ var gameModeResponse = await Fetch(_gamemodeInfo.Url);
+ if (!gameModeResponse.IsSuccessful)
+ {
+ Constants.Log.Error(
+ "updateGamemodeDictionary Failed, Response:{error}",
+ gameModeResponse.ErrorException
+ );
+ return;
+ }
+ 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);
+ }
+
+ async Task UpdatePodsDictionary()
+ {
+ var podsResponse = await Fetch(_podsInfo.Url);
+ if (!podsResponse.IsSuccessful)
+ {
+ Constants.Log.Error(
+ "updatePodsDictionary Failed, Response:{error}",
+ podsResponse.ErrorException
+ );
+ return;
+ }
+ Dictionary podsDictionary = new();
+ if (
+ podsResponse.Data != null
+ && podsResponse.Data.Data.ContainsKey("UI_GamePodStrings")
+ )
+ {
+ podsDictionary = podsResponse.Data.Data["UI_GamePodStrings"];
+ }
+ if (Settings.Default.Language != "en")
+ {
+ var locresEnglishREsponse = await Fetch(
+ _podsInfo.Url + "/../en-US"
+ );
+ if (
+ locresEnglishREsponse.Data != null
+ && locresEnglishREsponse.Data.Data.ContainsKey("UI_GamePodStrings")
+ )
+ locresEnglishREsponse.Data.Data["UI_GamePodStrings"]
+ .ToList()
+ .ForEach(x => podsDictionary.TryAdd(x.Key, x.Value));
+ }
+
+ await File.WriteAllTextAsync(
+ _podsInfo.Filepath,
+ JsonSerializer.Serialize(podsDictionary)
+ )
+ .ConfigureAwait(false);
+ }
+
+ try
+ {
+ await Task.WhenAll(
+ UpdateVersion(),
+ UpdateRanksDictionary(),
+ UpdateAgentsDictionary(),
+ UpdateMapsDictionary(),
+ UpdateSkinsDictionary(),
+ UpdateCardsDictionary(),
+ UpdateSpraysDictionary(),
+ UpdateGamemodeDictionary(),
+ UpdatePodsDictionary()
+ )
+ .ConfigureAwait(false);
+ }
+ catch (Exception e)
+ {
+ Constants.Log.Error(
+ "updateGamemodeDictionary Parralel Tasks Failed, Response:{error}",
+ e
+ );
+ }
+ }
+ 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
+ }
+ }
+}
diff --git a/NOWT/IViewFactory.cs b/NOWT/IViewFactory.cs
new file mode 100644
index 00000000..3bdea318
--- /dev/null
+++ b/NOWT/IViewFactory.cs
@@ -0,0 +1,8 @@
+using System.Windows;
+
+namespace NOWT;
+
+public interface IViewFactory
+{
+ FrameworkElement? ResolveView(object viewModel);
+}
diff --git a/NOWT/MainWindow.xaml b/NOWT/MainWindow.xaml
new file mode 100644
index 00000000..3d839afb
--- /dev/null
+++ b/NOWT/MainWindow.xaml
@@ -0,0 +1,17 @@
+
+
+
\ No newline at end of file
diff --git a/NOWT/MainWindow.xaml.cs b/NOWT/MainWindow.xaml.cs
new file mode 100644
index 00000000..678efba1
--- /dev/null
+++ b/NOWT/MainWindow.xaml.cs
@@ -0,0 +1,15 @@
+using System.Windows;
+using Microsoft.Toolkit.Mvvm.DependencyInjection;
+using NOWT.ViewModels;
+
+namespace NOWT;
+
+public partial class MainWindow : Window
+{
+ public MainWindow()
+ {
+ InitializeComponent();
+ DataContext = Ioc.Default.GetRequiredService();
+ ((App)Application.Current).WindowPlace.Register(this);
+ }
+}
diff --git a/NOWT/NOWT.csproj b/NOWT/NOWT.csproj
new file mode 100644
index 00000000..8723ac25
--- /dev/null
+++ b/NOWT/NOWT.csproj
@@ -0,0 +1,198 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ WinExe
+ net6.0-windows
+ true
+ logo.ico
+ 2.0.1.5
+ True
+ NOWT.App
+ A Windows app to view player ranks and stats in a live Valorant Match
+ Soneliem,PWall
+ logo.png
+
+ https://github.com/WAIUA/WAIUA
+ en
+ MIT
+ Soneliem,PWall
+
+ false
+ README.md
+ git
+ 1.0.0
+ 2.0.1.5
+ AnyCPU
+ annotations
+ WAIUA
+ WAIUA
+ WAIUA
+
+
+
+ x64
+ False
+
+
+
+ True
+ x64
+
+
+
+
+
+
+
+
+
+
+
+ PublicResXFileCodeGenerator
+
+
+ PublicResXFileCodeGenerator
+
+
+ Resources.resx
+ PublicResXFileCodeGenerator
+
+
+ PublicResXFileCodeGenerator
+
+
+ Resources.resx
+ PublicResXFileCodeGenerator
+
+
+ PublicResXFileCodeGenerator
+
+
+ PublicResXFileCodeGenerator
+
+
+ PublicResXFileCodeGenerator
+
+
+ PublicResXFileCodeGenerator
+
+
+ PublicResXFileCodeGenerator
+ Resources.Designer.cs
+
+
+ PublicResXFileCodeGenerator
+
+
+ Resources.zh-Hant-TW.resx
+
+
+ Resources.resx
+
+
+ Resources.resx
+
+
+ True
+ True
+ Resources.resx
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+
+
+
+
+ True
+ \
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ True
+ True
+ Settings.settings
+
+
+
+
+
+ Never
+
+
+ PublicSettingsSingleFileGenerator
+ Settings.Designer.cs
+
+
+
+
diff --git a/NOWT/Objects/CustomObjects.cs b/NOWT/Objects/CustomObjects.cs
new file mode 100644
index 00000000..d052fbda
--- /dev/null
+++ b/NOWT/Objects/CustomObjects.cs
@@ -0,0 +1,325 @@
+using System;
+using System.Windows;
+using Microsoft.Toolkit.Mvvm.ComponentModel;
+
+namespace NOWT.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 _aresImage;
+
+ [ObservableProperty]
+ private string _aresName;
+
+ [ObservableProperty]
+ private Uri _buckyImage;
+
+ [ObservableProperty]
+ private string _buckyName;
+
+ [ObservableProperty]
+ private Uri _bulldogImage;
+
+ [ObservableProperty]
+ private string _bulldogName;
+
+ [ObservableProperty]
+ private Uri _cardImage;
+
+ [ObservableProperty]
+ private string _cardName;
+
+ [ObservableProperty]
+ private Uri _classicImage;
+
+ [ObservableProperty]
+ private string _classicName;
+
+ [ObservableProperty]
+ private Uri _frenzyImage;
+
+ [ObservableProperty]
+ private string _frenzyName;
+
+ [ObservableProperty]
+ private Uri _ghostImage;
+
+ [ObservableProperty]
+ private string _ghostName;
+
+ [ObservableProperty]
+ private Uri _guardianImage;
+
+ [ObservableProperty]
+ private string _guardianName;
+
+ [ObservableProperty]
+ private Uri _judgeImage;
+
+ [ObservableProperty]
+ private string _judgeName;
+
+ [ObservableProperty]
+ private Uri _largeCardImage;
+
+ [ObservableProperty]
+ private Uri _marshalImage;
+
+ [ObservableProperty]
+ private string _marshalName;
+
+ [ObservableProperty]
+ private Uri _outlawImage;
+
+ [ObservableProperty]
+ private string _outlawName;
+
+ [ObservableProperty]
+ private Uri _meleeImage;
+
+ [ObservableProperty]
+ private string _meleeName;
+
+ [ObservableProperty]
+ private Uri _odinImage;
+
+ [ObservableProperty]
+ private string _odinName;
+
+ [ObservableProperty]
+ private Uri _operatorImage;
+
+ [ObservableProperty]
+ private string _operatorName;
+
+ [ObservableProperty]
+ private Uri _phantomImage;
+
+ [ObservableProperty]
+ private string _phantomName;
+
+ [ObservableProperty]
+ private Uri _sheriffImage;
+
+ [ObservableProperty]
+ private string _sheriffName;
+
+ [ObservableProperty]
+ private Uri _shortyImage;
+
+ [ObservableProperty]
+ private string _shortyName;
+
+ [ObservableProperty]
+ private Uri _spectreImage;
+
+ [ObservableProperty]
+ private string _spectreName;
+
+ [ObservableProperty]
+ private Uri _spray1Image;
+
+ [ObservableProperty]
+ private string _spray1Name;
+
+ [ObservableProperty]
+ private Uri _spray2Image;
+
+ [ObservableProperty]
+ private string _spray2Name;
+
+ [ObservableProperty]
+ private Uri _spray3Image;
+
+ [ObservableProperty]
+ private string _spray3Name;
+
+ [ObservableProperty]
+ private Uri _spray4Image;
+
+ [ObservableProperty]
+ private string _spray4Name;
+
+ [ObservableProperty]
+ private Uri _stingerImage;
+
+ [ObservableProperty]
+ private string _stingerName;
+
+ [ObservableProperty]
+ private Uri _vandalImage;
+
+ [ObservableProperty]
+ private string _vandalName;
+}
+
+[INotifyPropertyChanged]
+public partial class RankData
+{
+ [ObservableProperty]
+ private int _maxRr = 100;
+
+ [ObservableProperty]
+ private Uri[] _rankImages;
+
+ [ObservableProperty]
+ private string[] _rankNames;
+}
+
+[INotifyPropertyChanged]
+public partial class MatchHistoryData
+{
+ [ObservableProperty]
+ private int[] _previousGames;
+
+ [ObservableProperty]
+ private string[] _previousGameColours;
+
+ [ObservableProperty]
+ private int _rankProgress;
+}
+
+public class ValMap
+{
+ public string Name { get; set; }
+ public Guid UUID { get; set; }
+}
+
+public class ValCard
+{
+ public string Name { get; set; }
+ public Uri Image { get; set; }
+ public Uri FullImage { get; set; }
+}
+
+public class ValNameImage
+{
+ 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;
+}
diff --git a/NOWT/Objects/RiotAPIObjects.cs b/NOWT/Objects/RiotAPIObjects.cs
new file mode 100644
index 00000000..672e17de
--- /dev/null
+++ b/NOWT/Objects/RiotAPIObjects.cs
@@ -0,0 +1,1179 @@
+using System;
+using System.Collections.Generic;
+using System.Text.Json;
+using System.Text.Json.Serialization;
+
+namespace NOWT.Objects;
+
+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")]
+ [JsonIgnore]
+ public object PostGameDetails { get; set; }
+
+ [JsonPropertyName("Players")]
+ public RiotLivePlayer[] Players { get; set; }
+
+ [JsonPropertyName("MatchmakingData")]
+ [JsonIgnore]
+ 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 CompetitiveUpdates[] Matches { get; set; }
+}
+
+public class CompetitiveUpdates
+{
+ [JsonPropertyName("MatchID")]
+ public Guid MatchId { get; set; }
+
+ [JsonPropertyName("MapID")]
+ public string MapId { get; set; }
+
+ [JsonPropertyName("SeasonID")]
+ [JsonIgnore]
+ public string? 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 CompetitiveUpdates 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 string 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; }
+}
diff --git a/NOWT/Objects/ValAPIObjects.cs b/NOWT/Objects/ValAPIObjects.cs
new file mode 100644
index 00000000..4a138660
--- /dev/null
+++ b/NOWT/Objects/ValAPIObjects.cs
@@ -0,0 +1,402 @@
+using System;
+using System.Collections.Generic;
+using System.Text.Json;
+using System.Text.Json.Serialization;
+
+namespace NOWT.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 ValApiSpraysResponse
+{
+ [JsonPropertyName("status")]
+ public long Status { get; set; }
+
+ [JsonPropertyName("data")]
+ public Datum[] Data { get; set; }
+}
+
+public class Datum
+{
+ [JsonPropertyName("uuid")]
+ public Guid Uuid { get; set; }
+
+ [JsonPropertyName("displayName")]
+ public string DisplayName { get; set; }
+
+ [JsonPropertyName("category")]
+ [JsonIgnore]
+ public string? Category { get; set; }
+
+ [JsonPropertyName("themeUuid")]
+ public Guid? ThemeUuid { get; set; }
+
+ [JsonPropertyName("displayIcon")]
+ public Uri DisplayIcon { get; set; }
+
+ [JsonPropertyName("fullIcon")]
+ public Uri FullIcon { get; set; }
+
+ [JsonPropertyName("fullTransparentIcon")]
+ public Uri FullTransparentIcon { get; set; }
+
+ [JsonPropertyName("animationPng")]
+ public Uri AnimationPng { get; set; }
+
+ [JsonPropertyName("animationGif")]
+ public Uri AnimationGif { get; set; }
+
+ [JsonPropertyName("assetPath")]
+ public string AssetPath { get; set; }
+
+ [JsonPropertyName("levels")]
+ public Level[] Levels { get; set; }
+}
+
+public class Level
+{
+ [JsonPropertyName("uuid")]
+ public Guid Uuid { get; set; }
+
+ [JsonPropertyName("sprayLevel")]
+ public long SprayLevel { get; set; }
+
+ [JsonPropertyName("displayName")]
+ public string DisplayName { get; set; }
+
+ [JsonPropertyName("displayIcon")]
+ public Uri DisplayIcon { 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; }
+}
+
+public class ValApiLocresResponse
+{
+ [JsonPropertyName("status")]
+ public long Status { get; set; }
+
+ [JsonPropertyName("data")]
+ public Dictionary> Data { get; set; }
+}
diff --git a/NOWT/Properties/Annotations.cs b/NOWT/Properties/Annotations.cs
new file mode 100644
index 00000000..0471a86e
--- /dev/null
+++ b/NOWT/Properties/Annotations.cs
@@ -0,0 +1,1900 @@
+/* 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 NOWT.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; }
+}
diff --git a/NOWT/Properties/Resources.Designer.cs b/NOWT/Properties/Resources.Designer.cs
new file mode 100644
index 00000000..93bdd149
--- /dev/null
+++ b/NOWT/Properties/Resources.Designer.cs
@@ -0,0 +1,432 @@
+//------------------------------------------------------------------------------
+//
+// This code was generated by a tool.
+// Runtime Version:4.0.30319.42000
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+//
+//------------------------------------------------------------------------------
+
+namespace NOWT.Properties {
+ using System;
+
+
+ ///
+ /// A strongly-typed resource class, for looking up localized strings, etc.
+ ///
+ // This class was auto-generated by the StronglyTypedResourceBuilder
+ // class via a tool like ResGen or Visual Studio.
+ // To add or remove a member, edit your .ResX file then rerun ResGen
+ // with the /str option, or rebuild your VS project.
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ public class Resources {
+
+ private static global::System.Resources.ResourceManager resourceMan;
+
+ private static global::System.Globalization.CultureInfo resourceCulture;
+
+ [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+ internal Resources() {
+ }
+
+ ///
+ /// Returns the cached ResourceManager instance used by this class.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ public static global::System.Resources.ResourceManager ResourceManager {
+ get {
+ if (object.ReferenceEquals(resourceMan, null)) {
+ global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("NOWT.Properties.Resources", typeof(Resources).Assembly);
+ resourceMan = temp;
+ }
+ return resourceMan;
+ }
+ }
+
+ ///
+ /// Overrides the current thread's CurrentUICulture property for all
+ /// resource lookups using this strongly typed resource class.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ public static global::System.Globalization.CultureInfo Culture {
+ get {
+ return resourceCulture;
+ }
+ set {
+ resourceCulture = value;
+ }
+ }
+
+ ///
+ /// 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.
+ ///
+ public static string Author {
+ get {
+ return ResourceManager.GetString("Author", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Authenticated as:.
+ ///
+ public static string AuthStatusAuthAs {
+ get {
+ return ResourceManager.GetString("AuthStatusAuthAs", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Check Authentication.
+ ///
+ public static string AuthStatusButton {
+ get {
+ return ResourceManager.GetString("AuthStatusButton", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Click below to update.
+ ///
+ public static string AuthStatusDefault {
+ get {
+ return ResourceManager.GetString("AuthStatusDefault", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Not Authenticated.
+ ///
+ public static string AuthStatusFail {
+ get {
+ return ResourceManager.GetString("AuthStatusFail", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Authentication Status.
+ ///
+ public static string AuthStatusTitle {
+ get {
+ return ResourceManager.GetString("AuthStatusTitle", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Note: Valorant needs to be running for this to work.
+ ///
+ public static string AutoLoginExplanation {
+ get {
+ return ResourceManager.GetString("AutoLoginExplanation", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Auto Login.
+ ///
+ public static string AutoLoginTitle {
+ get {
+ return ResourceManager.GetString("AutoLoginTitle", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Force Update.
+ ///
+ public static string CheckDownloadButton {
+ get {
+ return ResourceManager.GetString("CheckDownloadButton", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Check Downloaded Content.
+ ///
+ public static string CheckDownloadTitle {
+ get {
+ return ResourceManager.GetString("CheckDownloadTitle", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Check for Updates.
+ ///
+ public static string CheckUpdates {
+ get {
+ return ResourceManager.GetString("CheckUpdates", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Current Version: .
+ ///
+ public static string CurrentVersion {
+ get {
+ return ResourceManager.GetString("CurrentVersion", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Error.
+ ///
+ public static string Error {
+ get {
+ return ResourceManager.GetString("Error", resourceCulture);
+ }
+ }
+
+ ///
+ /// 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 Home {
+ get {
+ return ResourceManager.GetString("Home", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Info.
+ ///
+ public static string InfoTitle {
+ get {
+ return ResourceManager.GetString("InfoTitle", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Join my Discord.
+ ///
+ public static string JoinDiscord {
+ get {
+ return ResourceManager.GetString("JoinDiscord", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to For support, etc..
+ ///
+ public static string JoinDiscordSub {
+ get {
+ return ResourceManager.GetString("JoinDiscordSub", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Latest Version: .
+ ///
+ public static string Latestversion {
+ get {
+ return ResourceManager.GetString("Latestversion", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Login.
+ ///
+ public static string Login {
+ get {
+ return ResourceManager.GetString("Login", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Match.
+ ///
+ public static string Match {
+ get {
+ return ResourceManager.GetString("Match", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to No Match Detected.
+ ///
+ public static string NoMatch {
+ get {
+ return ResourceManager.GetString("NoMatch", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Please Open Valorant First.
+ ///
+ public static string NoValGame {
+ get {
+ return ResourceManager.GetString("NoValGame", resourceCulture);
+ }
+ }
+
+ ///
+ /// 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....
+ ///
+ public static string Refreshing {
+ get {
+ return ResourceManager.GetString("Refreshing", resourceCulture);
+ }
+ }
+
+ ///
+ /// 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.
+ ///
+ public static string RefreshMatch {
+ get {
+ return ResourceManager.GetString("RefreshMatch", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Score:.
+ ///
+ public static string Score {
+ get {
+ return ResourceManager.GetString("Score", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Select Language.
+ ///
+ public static string SelLanguageTitle {
+ get {
+ return ResourceManager.GetString("SelLanguageTitle", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to This page lets you manually sign in, change the app language, etc..
+ ///
+ public static string SettingsInfoExplanation1 {
+ get {
+ return ResourceManager.GetString("SettingsInfoExplanation1", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to All communication regarding your credentials is done directly with Riot servers with no storage of passwords being done locally or online..
+ ///
+ public static string SettingsInfoExplanation2 {
+ get {
+ return ResourceManager.GetString("SettingsInfoExplanation2", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Settings.
+ ///
+ public static string SettingsTitle {
+ get {
+ return ResourceManager.GetString("SettingsTitle", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Sponsors.
+ ///
+ public static string SponsorsTitle {
+ get {
+ return ResourceManager.GetString("SponsorsTitle", 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.
+ ///
+ public static string TrackerToolTip {
+ get {
+ return ResourceManager.GetString("TrackerToolTip", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Translated into English By Soneliem.
+ ///
+ public static string Translator {
+ get {
+ 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/NOWT/Properties/Resources.ar.resx b/NOWT/Properties/Resources.ar.resx
new file mode 100644
index 00000000..bd0b2109
--- /dev/null
+++ b/NOWT/Properties/Resources.ar.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
+
+
+ أحدث اصدار:
+
+
+ الإصدار الحالي:
+
+
+ تحقق من وجود تحديث
+
+
+ تسجيل الدخول
+
+
+ جميع المعاملات بخصوص معلومات تسجيل الدخول الخاصة بك تحدث مباشرة من خلال خوادم رايوت، حيث لا يتم تخزين او حفظ اي معلومات خاصة بك.
+
+
+ حالة المصاقة
+
+
+ انقر أدناه للنحديث
+
+
+ تحقق من المصادقة
+
+
+ تمت المصادقة كـ:
+
+
+ تسجيل الدخول التلقائي
+
+
+ ملاحظة: يجب تشغيل فالورانت حتى يعمل هذا
+
+
+ غير مُصدق
+
+
+ تمت الترجمة للغة العربية بواسطة hafyzwithawhy و Chica
+
+
+ انقر لتحديث المباراة
+
+
+ الإعدادات
+
+
+ هذه الصفحة تسمح لك بتسجيل الدخول يدويا، تغيير لغة البرنامج، الخ...
+
+
+ اختر اللغة
+
+
+ خطأ
+
+
+ يتم التحديث...
+
+
+ لم يتم الكشف عن أية مباراة
+
+
+ الرجاء فتح فالورانت أولا
+
+
+ افتح الملف الشخصي لـ tracker.gg
+
+
+ تحقق من المحتوى الذي تم تنزيله
+
+
+ فرض التحديث
+
+
+ الداعمين
+
+
+ الصفحة الرئيسية
+
+
+ تحديث
+
+
+ الحساب
+
+
+ المباراة
+
+
+ الحالة
+
+
+ فالورانت
+
+
+ المجموعة
+
+
+ وقت الوصول المقدر:
+
+
+ سيتم التحديث خلال:
+
+
+ النقاط:
+
+
+ أعلى نقاط:
+
+
+ ابدأ إحماء التصويب
+
+
+ اللاعب
+
+
\ No newline at end of file
diff --git a/NOWT/Properties/Resources.da.resx b/NOWT/Properties/Resources.da.resx
new file mode 100644
index 00000000..55aa66d8
--- /dev/null
+++ b/NOWT/Properties/Resources.da.resx
@@ -0,0 +1,243 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 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:
+
+
+ Spiller
+
+
\ No newline at end of file
diff --git a/NOWT/Properties/Resources.de.resx b/NOWT/Properties/Resources.de.resx
new file mode 100644
index 00000000..10cc110c
--- /dev/null
+++ b/NOWT/Properties/Resources.de.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
+
+
+ Tritt dem Discord bei
+
+
+ Für Support, etc.
+
+
+ Erstellt von Soneliem
+
+
+ Neuste Version:
+
+
+ Deine Version:
+
+
+ Suche Nach Updates
+
+
+ Login
+
+
+ Es werden keine Anmeldedaten gespeichert. Die Zugangsdaten werden für die direkte Kommunikation mit den Riot-Servern verwendet.
+
+
+ Anmelde Status
+
+
+ Zum Aktualisieren unten klicken
+
+
+ Überprüfe Anmeldung
+
+
+ Angemeldet als:
+
+
+ Automatischer Login
+
+
+ Hinweis: Valorant muss hierfür gestartet sein
+
+
+ Nicht angemeldet
+
+
+ Ins Deutsche Übersetzt von lolostill und NNebus
+ Fuzzy
+
+
+ Hier klicken, um Matchdaten neu zu laden
+
+
+ Einstellungen
+
+
+ Hier kannst du dich manuell anmelden, die Sprache ändern, etc
+
+
+ Sprache auswählen
+
+
+ Fehler
+
+
+ Neuladen...
+
+
+ Kein Match Gefunden
+
+
+ Bitte öffne zuerst Valorant
+
+
+ Tracker.gg Profil öffnen
+
+
+ Heruntergeladene Inhalte prüfen
+
+
+
+ Update erzwingen
+
+
+ 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.
+
+
+ Spieler
+
+
\ No newline at end of file
diff --git a/NOWT/Properties/Resources.en.resx b/NOWT/Properties/Resources.en.resx
new file mode 100644
index 00000000..8d6c16fe
--- /dev/null
+++ b/NOWT/Properties/Resources.en.resx
@@ -0,0 +1,244 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 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
+
+
+ Join my Discord
+
+
+ For support, etc.
+
+
+ Made By Soneliem
+
+
+ Latest Version:
+
+
+ Current Version:
+
+
+ Check for Updates
+
+
+ Login
+
+
+ All communication regarding your credentials is done directly with Riot servers with no storage of passwords being done locally or online.
+
+
+ Authentication Status
+
+
+ Click below to update
+
+
+ Check Authentication
+
+
+ Authenticated as:
+
+
+ Auto Login
+
+
+ Note: Valorant needs to be running for this to work
+
+
+ Not Authenticated
+
+
+ Translated into English By Soneliem
+ Fuzzy
+
+
+ Click To Refresh Match
+
+
+ Settings
+
+
+ This page lets you manually sign in, change the app language, etc.
+
+
+ Select Language
+
+
+ Error
+
+
+ Refreshing...
+
+
+ No Match Detected
+
+
+ Please Open Valorant First
+
+
+ Open Tracker.gg Profile
+
+
+ Check Downloaded Content
+
+
+ Force Update
+
+
+ Sponsors
+
+
+ Home
+
+
+ Refresh
+
+
+ Account
+
+
+ Match
+
+
+ Status
+
+
+ Valorant
+
+
+ Your Party
+
+
+ Queue Time:
+
+
+ Refreshing In:
+
+
+ Score:
+
+
+ High Score:
+
+
+ Player
+
+
\ No newline at end of file
diff --git a/NOWT/Properties/Resources.es.resx b/NOWT/Properties/Resources.es.resx
new file mode 100644
index 00000000..823039f5
--- /dev/null
+++ b/NOWT/Properties/Resources.es.resx
@@ -0,0 +1,243 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 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
+
+
+ Información
+
+
+ Únete a mi Discord
+
+
+ Por si acaso necesitas apoyo, etcétera
+
+
+ Desarrollado Por Soneliem
+
+
+ Última versión:
+
+
+ Versión Actual:
+
+
+ Buscar Actualizaciones
+
+
+ Iniciar sesión
+
+
+ Toda la comunicación con respecto a sus credenciales se realiza directamente con los servidores RIOT sin contraseñas guardadas localmente o en línea.
+
+
+ Estado de Autenticación
+
+
+ Haz clic debajo para actualizar
+
+
+ Comprobar la Autenticación
+
+
+ Autenticado como:
+
+
+ Inicio Automático de Sesión
+
+
+ Nota: Valorant necesita estar abierto para que esto funcione
+
+
+ No Autenticado
+
+
+ Traducido al Español Por ZzyzxFox, FamiTom
+
+
+ Haz clic aquí para actualizar el partido
+
+
+ Configuración
+
+
+ Esta página te permite iniciar sesión manualmente, cambiar el idioma de la aplicación, etc.
+
+
+ Seleccionar Idioma
+
+
+ Error
+
+
+ Actualizando...
+
+
+ No se ha detectado ningúna partida
+
+
+ Por Favor, Inicie Valorant Primero
+
+
+ Abrir perfil Tracker.gg
+
+
+ Check Downloaded Content
+
+
+ Force Update
+
+
+ Sponsors
+
+
+ Home
+
+
+ Refresh
+
+
+ Account
+
+
+ Match
+
+
+ Status
+
+
+ Valorant
+
+
+ Your Party
+
+
+ Queue Time:
+
+
+ Refreshing In:
+
+
+ Score:
+
+
+ High Score:
+
+
+ Player
+
+
\ No newline at end of file
diff --git a/NOWT/Properties/Resources.fa.resx b/NOWT/Properties/Resources.fa.resx
new file mode 100644
index 00000000..64dc82b3
--- /dev/null
+++ b/NOWT/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/NOWT/Properties/Resources.fr.resx b/NOWT/Properties/Resources.fr.resx
new file mode 100644
index 00000000..f2421719
--- /dev/null
+++ b/NOWT/Properties/Resources.fr.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
+
+
+ Rejoignez notre Discord
+
+
+ Pour du support, etc.
+
+
+ Fait par Soneliem
+
+
+ Dernière version:
+
+
+ Version actuelle:
+
+
+ Rechercher des mises à jour
+
+
+ Connexion
+
+
+ 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
+
+
+ Cliquer ci-dessous pour mettre à jour
+
+
+ Vérifier authentification
+
+
+ Authentifié comme:
+
+
+ Connexion automatique
+
+
+ Note: Valorant doit être en cours d'exécution pour que cela fonctionne
+
+
+ Non authentifié
+
+
+ Traduit en Français par Rayjacker et SeifB_
+
+
+ Cliquer ici pour rafraîchir le match
+
+
+ Paramètres
+
+
+ Cette page vous permet de vous connecter, changer la langue de l'appli, etc.
+
+
+ Sélectionner le language
+
+
+ Erreur
+
+
+ Rafraîchissement...
+
+
+ Aucun match détecté
+
+
+ Merci d'ouvrir Valorant d'abord
+
+
+ Ouvrir le profil Tracker.gg
+
+
+ Vérifier le contenu téléchargé
+
+
+ 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/NOWT/Properties/Resources.hi.resx b/NOWT/Properties/Resources.hi.resx
new file mode 100644
index 00000000..3544a5c3
--- /dev/null
+++ b/NOWT/Properties/Resources.hi.resx
@@ -0,0 +1,243 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 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 द्वारा निर्मित
+
+
+ नवीनतम संस्करण:
+
+
+ वर्तमान संस्करण:
+
+
+ Updates के लिए जाँच
+
+
+ लॉग इन
+
+
+ आपके क्रेडेंशियल्स के बारे में सभी संचार सीधे Riot सर्वर के साथ किया जाता है, जिसमें पासवर्ड का कोई भंडारण स्थानीय या ऑनलाइन नहीं किया जाता है.
+
+
+ प्रमाणीकरण कि स्थिति
+
+
+ अपडेट करने के लिए नीचे क्लिक करें
+
+
+ प्रमाणीकरण की जाँच करें
+
+
+ प्रमाणित:
+
+
+ स्व - लॉगिन
+
+
+ ध्यान दें : Valorant पृष्ठभूमि में चलने की जरूरत है
+
+
+ प्रमाणीकृत नहीं है
+
+
+ हिंदी में अनुवादित cheemonster द्वारा
+
+
+ मैच को ताज़ा करने के लिए क्लिक करें
+
+
+ सेटिंग
+
+
+ यह पृष्ठ आपको मैन्युअल रूप से sign in करने देता है, ऐप की भाषा बदलने देता है, आदि.
+
+
+ भाषा चुने
+
+
+ error
+
+
+ Refreshing...
+
+
+ कोई match नहीं मिला
+
+
+ कृपया पहले Valorant खोलें
+
+
+ Tracker.gg प्रोफ़ाइल खोलें
+
+
+ डाउनलोडेड समान देखें
+
+
+ जबरदस्ती अपडेट
+
+
+ स्पॉन्सर
+
+
+ घर
+
+
+ ताज़ा
+
+
+ खाता
+
+
+ Match
+
+
+ दर्जा
+
+
+ Valorant
+
+
+ आपकी टोली
+
+
+ कतार का समय
+
+
+ Refreshing In:
+
+
+ स्कोर:
+
+
+ हाईस्कोर:
+
+
+ खिलाड़ी
+
+
\ No newline at end of file
diff --git a/NOWT/Properties/Resources.it.resx b/NOWT/Properties/Resources.it.resx
new file mode 100644
index 00000000..f6d4d065
--- /dev/null
+++ b/NOWT/Properties/Resources.it.resx
@@ -0,0 +1,243 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 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
+
+
+ Informazioni
+
+
+ Entra sul mio Discord
+
+
+ Per supporto, eccetera.
+
+
+ Creato da Soneliem
+
+
+ Ultima versione:
+
+
+ Versione attuale:
+
+
+ Verifica se ci sono aggiornamenti
+
+
+ Accesso
+
+
+ Tutte le comunicazioni riguardanti le tue credenziali sono effettuate direttamente con i server Riot con nessuna memorizzazione delle password effettuata localmente o online.
+
+
+ Stato dell'autenticazione
+
+
+ Clicca qui sotto per aggiornare
+
+
+ Verifica autenticazione
+
+
+ Autenticato come:
+
+
+ Accesso Automatico
+
+
+ Nota: Valorant deve essere avviato per fare in modo che questo possa funzionare
+
+
+ Non autenticato
+
+
+ Tradotto in italiano da CyberKoreTv
+
+
+ Clicca per aggiornare la tua partita
+
+
+ Impostazioni
+
+
+ Questa pagina ti permette di fare l'accesso manualmente, cambiare la lingua dell'app, eccetera.
+
+
+ Seleziona lingua
+
+
+ Errore
+
+
+ Sto Aggiornando...
+
+
+ Nessuna partita rilevata
+
+
+ Per favore, prima avvia Valorant
+
+
+ Apri Profilo Tracker.gg
+
+
+ Controllo download contenuti
+
+
+ Forza Aggiornamento
+
+
+ Sponsor
+
+
+ Home
+
+
+ Aggiorna
+
+
+ Account
+
+
+ Partita
+
+
+ Stato
+
+
+ Valorant
+
+
+ Il tuo Party
+
+
+ Tempo Coda
+
+
+ Aggiorno in:
+
+
+ Punteggio
+
+
+ Mio record
+
+
+ Giocatore
+
+
\ No newline at end of file
diff --git a/NOWT/Properties/Resources.ja.resx b/NOWT/Properties/Resources.ja.resx
new file mode 100644
index 00000000..bd4b9af4
--- /dev/null
+++ b/NOWT/Properties/Resources.ja.resx
@@ -0,0 +1,243 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 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のサーバーで直接処理されており、ローカルもしくはオンラインでもパスワードは保管されていません。
+
+
+ 認証ステータス
+
+
+ 下をクリックしてアップデート
+
+
+ 認証の確認
+
+
+ 認証済み:
+
+
+ 自動ログイン
+
+
+ 注意: これを行うにはValorantを起動しておく必要があります
+
+
+ 未認証
+
+
+ 日本語翻訳: Aron, nepixjp
+
+
+ クリックで試合を更新
+
+
+ 設定
+
+
+ このページでは手動ログインや、アプリの言語変更などができます。
+
+
+ 言語を選択
+
+
+ エラー
+
+
+ 更新中…
+
+
+ 試合が検出されませんでした
+
+
+ まずValorantを開いてください
+
+
+ Tracker.gg上のプロフィールを開く
+
+
+ ダウンロードしたコンテンツを確認
+
+
+ 強制アップデート
+
+
+ スポンサー
+
+
+ Home
+
+
+ Refresh
+
+
+ Account
+
+
+ Match
+
+
+ Status
+
+
+ Valorant
+
+
+ Your Party
+
+
+ Queue Time:
+
+
+ Refreshing In:
+
+
+ Score:
+
+
+ High Score:
+
+
+ Player
+
+
\ No newline at end of file
diff --git a/NOWT/Properties/Resources.ko.resx b/NOWT/Properties/Resources.ko.resx
new file mode 100644
index 00000000..e6630a5b
--- /dev/null
+++ b/NOWT/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
+
+
+ 가장 최근 버전:
+
+
+ 현재 버전:
+
+
+ 업데이트가 있는지 확인하기
+
+
+ 로그인
+
+
+ 모든 정보는 라이엇 서버에서 불러오는것으로 따로 계정의 비밀번호나 개인정보를 수집하지 않습니다.
+
+
+ 인증 상태
+
+
+ 업데이트 하시려면 클릭
+
+
+ 인증 체크
+
+
+ 인증:
+
+
+ 자동 로그인
+
+
+ 주의: NOWT를 사용하려면 발로란트가 실행중이어야 합니다.
+
+
+ 인증 실패
+
+
+ 한국어 변역 ramon,Heart
+
+
+ 매치 상태 새로고침하기
+
+
+ 설정
+
+
+ 이 페이지에서는 수동으로 로그인을 하거나, 언어를 변경하거나 다른 많은 것들을 할 수 있습니다.
+
+
+ 언어를 선택해주세요
+
+
+ 오류
+
+
+ 새로고치는 중...
+
+
+ 현재 진행되고 있는 게임이 없습니다
+
+
+ 발로란트를 먼저 실행해주세요
+
+
+ Tracker.gg 프로필 열기
+
+
+ 다운로드된 컨텐츠 확인하기
+
+
+ 강제 업데이트
+
+
+ 스폰서
+
+
+ 메인
+
+
+ 새로고침
+
+
+ 계정
+
+
+ 매치
+
+
+ 상태
+
+
+ 발로란트
+
+
+ 파티
+
+
+ 대전 찾는시간:
+
+
+ 새로고침까지 남은 시간:
+
+
+ 점수:
+
+
+ 최고점수:
+
+
+ 에임 트레이너 시작하기
+
+
+ 플레이어
+
+
\ No newline at end of file
diff --git a/NOWT/Properties/Resources.nl.resx b/NOWT/Properties/Resources.nl.resx
new file mode 100644
index 00000000..c004ca4b
--- /dev/null
+++ b/NOWT/Properties/Resources.nl.resx
@@ -0,0 +1,243 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 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:
+
+
+ Speler
+
+
\ No newline at end of file
diff --git a/NOWT/Properties/Resources.pt.resx b/NOWT/Properties/Resources.pt.resx
new file mode 100644
index 00000000..35afd13a
--- /dev/null
+++ b/NOWT/Properties/Resources.pt.resx
@@ -0,0 +1,243 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 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
+
+
+ Entre no meu Discord
+
+
+ Para suporte, etc.
+
+
+ Feito por Soneliem
+
+
+ Versão mais recente:
+
+
+ Versão atual:
+
+
+ Procurar por autalizações
+
+
+ Login
+
+
+ Toda comunicação em relação às suas credenciais é feita diretamente com os servidores da Riot e nenhuma senha é armazenada localmente ou online.
+
+
+ Estado de autenticação
+
+
+ Clique abaixo para atualizar
+
+
+ Verificar autenticação
+
+
+ Autenticado como:
+
+
+ Login automático
+
+
+ Nota: O Valorant precisa estar aberto para funcionar
+
+
+ Não autenticado
+
+
+ Traduzido para Português por castrom4 e janinha
+
+
+ Clique para recarregar a partida
+
+
+ Definições
+
+
+ Esta página deixa-te fazer o login manualmente, mudar o idioma, etc.
+
+
+ Selecionar idioma
+
+
+ Erro
+
+
+ Atualizando...
+
+
+ Nenhuma partida detectada
+
+
+ Por favor abra o Valorant primeiro
+
+
+ Abrir perfil do tracker.gg
+
+
+ Verificar conteúdo descarregado
+
+
+ Forçar atualização
+
+
+ Patrocinadores
+
+
+ Início
+
+
+ Atualizar
+
+
+ Conta
+
+
+ Partida
+
+
+ Estado
+
+
+ Valorant
+
+
+ O teu grupo
+
+
+ Tempo de espera:
+
+
+ Atualiza em:
+
+
+ Score:
+
+
+ High Score:
+
+
+ Player
+
+
\ No newline at end of file
diff --git a/NOWT/Properties/Resources.resx b/NOWT/Properties/Resources.resx
new file mode 100644
index 00000000..e871d289
--- /dev/null
+++ b/NOWT/Properties/Resources.resx
@@ -0,0 +1,243 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 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
+
+
+ Join my Discord
+
+
+ For support, etc.
+
+
+ Made By Soneliem
+
+
+ Click To Refresh Match
+
+
+ Latest Version:
+
+
+ Current Version:
+
+
+ Check for Updates
+
+
+ Login
+
+
+ Authentication Status
+
+
+ Click below to update
+
+
+ Check Authentication
+
+
+ Authenticated as:
+
+
+ Auto Login
+
+
+ Note: Valorant needs to be running for this to work
+
+
+ Not Authenticated
+
+
+ Translated into English By Soneliem
+
+
+ Settings
+
+
+ Select Language
+
+
+ All communication regarding your credentials is done directly with Riot servers with no storage of passwords being done locally or online.
+
+
+ This page lets you manually sign in, change the app language, etc.
+
+
+ No Match Detected
+
+
+ Please Open Valorant First
+
+
+ Refreshing...
+
+
+ Open Tracker.gg Profile
+
+
+ Error
+
+
+ Check Downloaded Content
+
+
+ Force Update
+
+
+ Sponsors
+
+
+ Home
+
+
+ Your Party
+
+
+ Valorant
+
+
+ Match
+
+
+ Account
+
+
+ Status
+
+
+ Refresh
+
+
+ Queue Time:
+
+
+ Refreshing In:
+
+
+ Player
+
+
+ High Score:
+
+
+ Score:
+
+
\ No newline at end of file
diff --git a/NOWT/Properties/Resources.ru.resx b/NOWT/Properties/Resources.ru.resx
new file mode 100644
index 00000000..d1957994
--- /dev/null
+++ b/NOWT/Properties/Resources.ru.resx
@@ -0,0 +1,243 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 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, при этом пароли не хранятся ни локально, ни в Интернете.
+
+
+ Статус аутентификации
+
+
+ Нажмите ниже, чтобы обновить
+
+
+ Проверка аутентификации
+
+
+ Аутентифицирован как:
+
+
+ Автоматический вход
+
+
+ Примечание: Валорант должен быть запущен, чтобы это работало
+
+
+ Не аутентифицирован
+
+
+ Переведено на русский Язык ZzyzxFox и DXGames
+
+
+ Нажмите, чтобы обновить матч
+
+
+ Настройки
+
+
+ На этой странице можно вручную войти в систему, изменить язык приложения и так далее
+
+
+ Выберите язык
+
+
+ Ошибка
+
+
+ Обновление...
+
+
+ Матч не обнаружен
+
+
+ Пожалуйста, сначала запустите Валорант
+
+
+ Открыть профиль Tracker.gg
+
+
+ Check Downloaded Content
+
+
+ Force Update
+
+
+ Sponsors
+
+
+ Home
+
+
+ Refresh
+
+
+ Account
+
+
+ Match
+
+
+ Status
+
+
+ Valorant
+
+
+ Your Party
+
+
+ Queue Time:
+
+
+ Refreshing In:
+
+
+ Score:
+
+
+ High Score:
+
+
+ Player
+
+
\ No newline at end of file
diff --git a/NOWT/Properties/Resources.sr.resx b/NOWT/Properties/Resources.sr.resx
new file mode 100644
index 00000000..77433c66
--- /dev/null
+++ b/NOWT/Properties/Resources.sr.resx
@@ -0,0 +1,243 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 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 Srpski od strane icedancer#0001
+
+
+ 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:
+
+
+ Igrač
+
+
\ No newline at end of file
diff --git a/NOWT/Properties/Resources.sv.resx b/NOWT/Properties/Resources.sv.resx
new file mode 100644
index 00000000..f1e3f9d0
--- /dev/null
+++ b/NOWT/Properties/Resources.sv.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
+
+
+ Gå med i min Discord
+
+
+ För att få hjälp, mm.
+
+
+ Gjord Av Soneliem
+
+
+ Senaste Versionen:
+
+
+ Nuvarande Version
+
+
+ Kolla efter uppdateringar
+
+
+ Logga in
+
+
+ All kommunikation som handlar om ditt inlogg är gjort direkt via Riots servrar utan någon lagring av lösenord gjort lokalt eller online.
+
+
+ Autentiserings status
+
+
+ Klicka nedan för att uppdatera.
+
+
+ Kolla efter Autentisering
+
+
+ Autentiserad som:
+
+
+ Automatisk inloggning
+
+
+ Notera: Valorant måste vara igång för att detta ska fungera
+
+
+ Ej Autentiserat
+
+
+ Översatt till Svenska Av Xosiation
+
+
+ Klicka För Att Uppdatera Match
+
+
+ Inställningar
+
+
+ Denna sida låter dig manuellt logga in, byta språk, mm.
+
+
+ Välj Språk
+
+
+ Fel
+
+
+ Uppdaterar...
+
+
+ Ingen Match Upptäckt
+
+
+ Vänligen Öppna Valorant Först
+
+
+ Öppna Tracker.gg Profil
+
+
+ Leta Efter Nedladdningsbart Innehåll
+
+
+ Tvinga Uppdatering
+
+
+ Sponsorer
+
+
+ Hem
+
+
+ Uppdatera
+
+
+ Konto
+
+
+ Match
+
+
+ Status
+
+
+ Valorant
+
+
+ Din Grupp
+
+
+ Kö Tid:
+
+
+ Uppdaterar Om:
+
+
+ Poäng:
+
+
+ Rekord:
+
+
+ Starta Siktning Träning
+
+
+ Spelare
+
+
\ No newline at end of file
diff --git a/NOWT/Properties/Resources.tr.resx b/NOWT/Properties/Resources.tr.resx
new file mode 100644
index 00000000..d6b778e3
--- /dev/null
+++ b/NOWT/Properties/Resources.tr.resx
@@ -0,0 +1,243 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 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
+
+
+ Bilgi
+
+
+ Discord'a Katıl
+
+
+ Destek vb. için
+
+
+ Soneliem Tarafından Yapıldı
+
+
+ En Son Sürüm:
+
+
+ Mevcut Sürüm:
+
+
+ Güncelleme Kontrolü Yap
+
+
+ Giriş yap
+
+
+ Bilgileriniz ile ilgili tüm iletişim, yerel olarak veya çevrimiçi olarak şifrelerin depolanması olmadan doğrudan Riot sunucuları ile yapılır.
+
+
+ Doğrulama Durumu
+
+
+ Güncelleme yapmak için aşağıya tıkla
+
+
+ Doğrulama Kontrolü
+
+
+ Şu kişi olarak doğrulandın:
+
+
+ Otomatik Giriş
+
+
+ Not: Bunun çalışması için Valorant'ın çalışması lazım
+
+
+ Doğrulanmadın
+
+
+ void Tarafından Türkçeye Çevrildi
+
+
+ Maçı Yenilemek İçin Tıkla
+
+
+ Ayarlar
+
+
+ Bu sayfada manuel olarak giriş yapabilir, dilini ve başka şeyleri değiştirebilirsin.
+
+
+ Dil Seç
+
+
+ Hata
+
+
+ Yenileniyor...
+
+
+ Maç Bulunmadı
+
+
+ Lütfen Önce Valorant'ı Aç
+
+
+ Tracker.gg Profilini Aç
+
+
+ İndirilmiş İçeriği Kontrol Et
+
+
+ Güncellemeyi Zorla
+
+
+ Sponsorlar
+
+
+ Ana Menü
+
+
+ Yenile
+
+
+ Hesap
+
+
+ Maç
+
+
+ Durum
+
+
+ Valorant
+
+
+ Grubun
+
+
+ Sıra Zamanı:
+
+
+ Şu Süre İçinde Yenilenecek:
+
+
+ Puan:
+
+
+ En Yüksek Puan:
+
+
+ Oyuncu
+
+
\ No newline at end of file
diff --git a/NOWT/Properties/Resources.vi.resx b/NOWT/Properties/Resources.vi.resx
new file mode 100644
index 00000000..dfd386d3
--- /dev/null
+++ b/NOWT/Properties/Resources.vi.resx
@@ -0,0 +1,243 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 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:
+
+
+ Người chơi
+
+
\ No newline at end of file
diff --git a/NOWT/Properties/Resources.zh.resx b/NOWT/Properties/Resources.zh.resx
new file mode 100644
index 00000000..a905109c
--- /dev/null
+++ b/NOWT/Properties/Resources.zh.resx
@@ -0,0 +1,243 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 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:
+
+
+ Player
+
+
\ No newline at end of file
diff --git a/NOWT/Properties/Settings.Designer.cs b/NOWT/Properties/Settings.Designer.cs
new file mode 100644
index 00000000..4f7990c2
--- /dev/null
+++ b/NOWT/Properties/Settings.Designer.cs
@@ -0,0 +1,38 @@
+//------------------------------------------------------------------------------
+//
+// This code was generated by a tool.
+// Runtime Version:4.0.30319.42000
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+//
+//------------------------------------------------------------------------------
+
+namespace NOWT.Properties {
+
+
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ [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())));
+
+ public static Settings Default {
+ get {
+ return defaultInstance;
+ }
+ }
+
+ [global::System.Configuration.UserScopedSettingAttribute()]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Configuration.DefaultSettingValueAttribute("")]
+ public string Language {
+ get {
+ return ((string)(this["Language"]));
+ }
+ set {
+ this["Language"] = value;
+ }
+ }
+ }
+}
diff --git a/NOWT/Properties/Settings.settings b/NOWT/Properties/Settings.settings
new file mode 100644
index 00000000..a06ca562
--- /dev/null
+++ b/NOWT/Properties/Settings.settings
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/NOWT/Properties/launchSettings.json b/NOWT/Properties/launchSettings.json
new file mode 100644
index 00000000..837bb75e
--- /dev/null
+++ b/NOWT/Properties/launchSettings.json
@@ -0,0 +1,7 @@
+{
+ "profiles": {
+ "NOWT": {
+ "commandName": "Project"
+ }
+ }
+}
\ No newline at end of file
diff --git a/NOWT/Settings.cs b/NOWT/Settings.cs
new file mode 100644
index 00000000..2bf84fa5
--- /dev/null
+++ b/NOWT/Settings.cs
@@ -0,0 +1,22 @@
+using System.ComponentModel;
+using System.Configuration;
+
+namespace NOWT.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.
+ }
+}
diff --git a/NOWT/VersionInfo.xml b/NOWT/VersionInfo.xml
new file mode 100644
index 00000000..b792afaf
--- /dev/null
+++ b/NOWT/VersionInfo.xml
@@ -0,0 +1,8 @@
+
+
+-
+
2.0.1.5
+ https://github.com/WAIUA/WAIUA/releases/latest/download/WAIUA.exe
+ https://github.com/WAIUA/WAIUA/releases/latest
+ true
+
\ No newline at end of file
diff --git a/NOWT/ViewFactory.cs b/NOWT/ViewFactory.cs
new file mode 100644
index 00000000..d5d81940
--- /dev/null
+++ b/NOWT/ViewFactory.cs
@@ -0,0 +1,49 @@
+using System;
+using System.Linq;
+using System.Windows;
+
+namespace NOWT;
+
+// 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;
+ }
+}
diff --git a/NOWT/ViewModelPresenter.cs b/NOWT/ViewModelPresenter.cs
new file mode 100644
index 00000000..9c8bac99
--- /dev/null
+++ b/NOWT/ViewModelPresenter.cs
@@ -0,0 +1,59 @@
+using System.Windows;
+using System.Windows.Controls;
+using Microsoft.Toolkit.Mvvm.DependencyInjection;
+
+namespace NOWT;
+
+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;
+ }
+ }
+}
diff --git a/NOWT/ViewModels/HomeViewModel.cs b/NOWT/ViewModels/HomeViewModel.cs
new file mode 100644
index 00000000..1c04b778
--- /dev/null
+++ b/NOWT/ViewModels/HomeViewModel.cs
@@ -0,0 +1,250 @@
+using System;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Media;
+using System.Windows.Threading;
+using FontAwesome6;
+using Microsoft.Toolkit.Mvvm.ComponentModel;
+using Microsoft.Toolkit.Mvvm.Input;
+using NOWT.Helpers;
+using NOWT.Objects;
+using NOWT.Views;
+using static NOWT.Helpers.Login;
+
+namespace NOWT.ViewModels;
+
+public partial class HomeViewModel : ObservableObject
+{
+ public delegate void EventAction();
+
+ [ObservableProperty]
+ private int _countdownTime = 20;
+
+ [ObservableProperty]
+ private DispatcherTimer _countTimer;
+ private int _cycle = 3;
+
+ [ObservableProperty]
+ private List _playerList;
+
+ [ObservableProperty]
+ private string _refreshTime = "-";
+
+ public HomeViewModel()
+ {
+ _countTimer = new DispatcherTimer();
+ _countTimer.Tick += UpdateTimersAsync;
+ _countTimer.Interval = new TimeSpan(0, 0, 1);
+ }
+
+ public event EventAction GoMatchEvent;
+
+ [ICommand]
+ private async Task LoadNowAsync()
+ {
+ CountdownTime = 20;
+ await UpdateChecksAsync(true).ConfigureAwait(false);
+ }
+
+ [ICommand]
+ private void PassiveLoadAsync()
+ {
+ if (!_countTimer.IsEnabled)
+ _countTimer.Start();
+ }
+
+ [ICommand]
+ private async Task PassiveLoadCheckAsync()
+ {
+ if (!_countTimer.IsEnabled)
+ {
+ _countTimer.Start();
+ await UpdateChecksAsync(true).ConfigureAwait(false);
+ }
+ }
+
+ [ICommand]
+ private void StopPassiveLoadAsync()
+ {
+ _countTimer.Stop();
+ RefreshTime = "-";
+ }
+
+ 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();
+ }
+}
diff --git a/NOWT/ViewModels/InfoViewModel.cs b/NOWT/ViewModels/InfoViewModel.cs
new file mode 100644
index 00000000..1b87e6e4
--- /dev/null
+++ b/NOWT/ViewModels/InfoViewModel.cs
@@ -0,0 +1,5 @@
+using Microsoft.Toolkit.Mvvm.ComponentModel;
+
+namespace NOWT.ViewModels;
+
+internal class InfoViewModel : ObservableObject { }
diff --git a/NOWT/ViewModels/MainViewModel.cs b/NOWT/ViewModels/MainViewModel.cs
new file mode 100644
index 00000000..d52a99f4
--- /dev/null
+++ b/NOWT/ViewModels/MainViewModel.cs
@@ -0,0 +1,40 @@
+using Microsoft.Toolkit.Mvvm.ComponentModel;
+using Microsoft.Toolkit.Mvvm.DependencyInjection;
+using Microsoft.Toolkit.Mvvm.Input;
+
+namespace NOWT.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();
+ }
+}
diff --git a/NOWT/ViewModels/MatchViewModel.cs b/NOWT/ViewModels/MatchViewModel.cs
new file mode 100644
index 00000000..8f827016
--- /dev/null
+++ b/NOWT/ViewModels/MatchViewModel.cs
@@ -0,0 +1,194 @@
+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 NOWT.Helpers;
+using NOWT.Objects;
+
+namespace NOWT.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 MatchDetails _match;
+
+ [ObservableProperty]
+ private LoadingOverlay _overlay;
+
+ [ObservableProperty]
+ private string _refreshTime = "-";
+ private int _resettime = 80;
+
+ [ObservableProperty]
+ private List _rightPlayerList;
+
+ 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 void PassiveLoadAsync()
+ {
+ if (!_countTimer.IsEnabled)
+ _countTimer.Start();
+ }
+
+ [ICommand]
+ private async Task PassiveLoadCheckAsync()
+ {
+ if (!_countTimer.IsEnabled)
+ {
+ _countTimer.Start();
+ await GetMatchInfoAsync().ConfigureAwait(false);
+ }
+ }
+
+ [ICommand]
+ private void StopPassiveLoadAsync()
+ {
+ CountTimer?.Stop();
+ RefreshTime = "-";
+ }
+
+ 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)
+ {
+ if (player.PlayerUiData is null)
+ continue;
+ // 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;
+ }
+}
diff --git a/NOWT/ViewModels/SettingsViewModel.cs b/NOWT/ViewModels/SettingsViewModel.cs
new file mode 100644
index 00000000..76e0da01
--- /dev/null
+++ b/NOWT/ViewModels/SettingsViewModel.cs
@@ -0,0 +1,5 @@
+using Microsoft.Toolkit.Mvvm.ComponentModel;
+
+namespace NOWT.ViewModels;
+
+public class SettingsViewModel : ObservableObject { }
diff --git a/NOWT/Views/Home.xaml b/NOWT/Views/Home.xaml
new file mode 100644
index 00000000..dfe69d35
--- /dev/null
+++ b/NOWT/Views/Home.xaml
@@ -0,0 +1,255 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/NOWT/Views/Home.xaml.cs b/NOWT/Views/Home.xaml.cs
new file mode 100644
index 00000000..0b98a89f
--- /dev/null
+++ b/NOWT/Views/Home.xaml.cs
@@ -0,0 +1,38 @@
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Threading;
+using FontAwesome6.Fonts;
+using NOWT.ViewModels;
+
+namespace NOWT.Views;
+
+public partial class Home : UserControl
+{
+ public static ImageAwesome ValorantStatus;
+ public static ImageAwesome AccountStatus;
+ public static ImageAwesome MatchStatus;
+
+ public Home()
+ {
+ InitializeComponent();
+ DataContextChanged += DataContextChangedHandler;
+
+ ValorantStatus = ValorantStatusView;
+ AccountStatus = AccountStatusView;
+ MatchStatus = MatchStatusView;
+ }
+
+ private void DataContextChangedHandler(object sender, DependencyPropertyChangedEventArgs e)
+ {
+ if (e.NewValue is not HomeViewModel viewModel)
+ return;
+ viewModel.GoMatchEvent += () =>
+ {
+ Dispatcher.Invoke(() =>
+ {
+ if (GoMatch.Command.CanExecute(null))
+ GoMatch.Command.Execute(null);
+ });
+ };
+ }
+}
diff --git a/NOWT/Views/Info.xaml b/NOWT/Views/Info.xaml
new file mode 100644
index 00000000..4c1e295c
--- /dev/null
+++ b/NOWT/Views/Info.xaml
@@ -0,0 +1,216 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ WAIUA:RE
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/NOWT/Views/Info.xaml.cs b/NOWT/Views/Info.xaml.cs
new file mode 100644
index 00000000..32a007cf
--- /dev/null
+++ b/NOWT/Views/Info.xaml.cs
@@ -0,0 +1,30 @@
+using System.Diagnostics;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Documents;
+using System.Windows.Navigation;
+
+namespace NOWT.Views;
+
+public partial class Info : UserControl
+{
+ public Info()
+ {
+ InitializeComponent();
+ }
+
+ private void HandleLinkClickAsync(object sender, RequestNavigateEventArgs e)
+ {
+ var link = (Hyperlink)sender;
+ var navigateUri = link.NavigateUri.ToString();
+ Process.Start(new ProcessStartInfo(navigateUri) { UseShellExecute = true });
+ e.Handled = true;
+ }
+
+ private void ImageClickAsync(object sender, RoutedEventArgs e)
+ {
+ var button = (Button)sender;
+ Process.Start(new ProcessStartInfo(button.Tag.ToString()) { UseShellExecute = true });
+ e.Handled = true;
+ }
+}
diff --git a/NOWT/Views/Match.xaml b/NOWT/Views/Match.xaml
new file mode 100644
index 00000000..9882ce8f
--- /dev/null
+++ b/NOWT/Views/Match.xaml
@@ -0,0 +1,198 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/NOWT/Views/Match.xaml.cs b/NOWT/Views/Match.xaml.cs
new file mode 100644
index 00000000..13616a74
--- /dev/null
+++ b/NOWT/Views/Match.xaml.cs
@@ -0,0 +1,34 @@
+using System.Windows;
+using System.Windows.Controls;
+using NOWT.ViewModels;
+
+namespace NOWT.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)
+ return;
+
+ viewModel.GoHomeEvent += () =>
+ {
+ Dispatcher.Invoke(() =>
+ {
+ if (GoHome.Command.CanExecute(null))
+ GoHome.Command.Execute(null);
+ });
+ };
+ }
+}
diff --git a/NOWT/Views/Settings.xaml b/NOWT/Views/Settings.xaml
new file mode 100644
index 00000000..679356ab
--- /dev/null
+++ b/NOWT/Views/Settings.xaml
@@ -0,0 +1,622 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/NOWT/Views/Settings.xaml.cs b/NOWT/Views/Settings.xaml.cs
new file mode 100644
index 00000000..8a4028ae
--- /dev/null
+++ b/NOWT/Views/Settings.xaml.cs
@@ -0,0 +1,139 @@
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Reflection;
+using System.Resources;
+using System.Threading;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Input;
+using System.Xml;
+using AutoUpdaterDotNET;
+using NOWT.Helpers;
+using NOWT.Properties;
+using static NOWT.Helpers.Login;
+using static NOWT.Helpers.ValApi;
+
+namespace NOWT.Views;
+
+public partial class Settings : UserControl
+{
+ private readonly List _languageList = new();
+
+ public Settings()
+ {
+ InitializeComponent();
+ }
+
+ private async Task CheckAuthAsync()
+ {
+ 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)}";
+ }
+
+ private async void Button_Click1Async(object sender, RoutedEventArgs e)
+ {
+ string ProductVersion = System.Windows.Forms.Application.ProductVersion;
+ CurrentVersion.Text = ProductVersion;
+ LatestVersion.Text = await GetLatestVersionAsync().ConfigureAwait(false);
+ AutoUpdater.InstalledVersion = new Version(ProductVersion);
+ AutoUpdater.Start(
+ "https://raw.githubusercontent.com/WAIUA/WAIUA/master/NOWT/VersionInfo.xml"
+ );
+ await CheckAndUpdateJsonAsync().ConfigureAwait(false);
+ }
+
+ private static Task GetLatestVersionAsync()
+ {
+ var xml = new XmlDocument();
+ xml.Load("https://raw.githubusercontent.com/WAIUA/WAIUA/master/NOWT/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 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;
+ UpdateFilesAsync().ConfigureAwait(false);
+ Application.Current.Shutdown();
+ System.Windows.Forms.Application.Restart();
+ }
+
+ 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;
+ }
+}
diff --git a/WAIUA/logo.ico b/NOWT/logo.ico
similarity index 100%
rename from WAIUA/logo.ico
rename to NOWT/logo.ico
diff --git a/README.md b/README.md
index 2a27b46e..fab55db1 100644
--- a/README.md
+++ b/README.md
@@ -1,15 +1,23 @@
-
-
+
+
-WAIUA
-Who Am I Up Against?
+WAIUA:RE
+Who Am I Up Against? Reloaded Edition
+
+ A Windows application to view player ranks and other info in a live Valorant Match
- A WPF app to view player ranks and stats in a live Valorant Match
-
+
+
+
+
+
+
+
+
Table of Contents
@@ -18,7 +26,6 @@
About The Project
@@ -29,29 +36,34 @@
Usage
- Roadmap
+ Roadmap And Known Bugs
+ Built With
Contributing
- License
+ Sponsors
+ Translations
Contact
Acknowledgements
+ Disclaimer
-
## About The Project
-A simple(for you, not me) Windows GUI app that lets you see the ranks, recent games and other info of players of a live Valorant match which you're still playing it.
+
+"Who Am I Up Against? Reloaded Edition" (WAIUA:RE) is simple Windows app that lets you see the ranks, recent game stats and other info of players in a live Valorant match while you're still playing it. Below are the current features that are in the app.
### Current Features
-Displays for each player:
-* Current Rank
-* Past three ranks (from last 3 acts, not last 3 played acts)
-* W/L indicator for last three competitive games
-* IGN, Agent, Card and Account Level
-
-### Built With
-* [WPF](https://docs.microsoft.com/en-us/dotnet/desktop/wpf/?view=netdesktop-5.0)
-* [C#](https://docs.microsoft.com/en-us/dotnet/csharp/)
-* [.NET 5.0](https://dotnet.microsoft.com/)
+
+|Current Rank and Rank Progress|Past three ranks (from last 3 acts)|RR lost or gained in last three competitive games|Account Level and Agent Image|
+|:---:|:---:|:---:|:---:|
+|||||
+
+|In-game and Agent Name|Vandal And Phantom Skin|Party Indicators|Fully translated into 15+ languages|
+|:---:|:---:|:---:|:---:|
+|||||
+
+|Tracker.gg Intergration||Support For all Game Modes|Auto Refresh and Updates|
+|:---:|:---:|:---:|:---:|
+|||||
## Getting Started
@@ -59,53 +71,72 @@ To get the app up and running follow these simple steps.
### Prerequisites
-* Windows 64-bit
-* .NET (may be automatically installed)
+* Windows 64-bit (If you're able to run Valorant on it you'll be fine)
+* .NET (will be automatically installed during installation)
### Installation
-1. Download the latest .exe from the [Github releases page](https://github.com/Soneliem/WAIUA/releases)
-2. Run the .exe
+1. Download [the latest installer](https://github.com/WAIUA/WAIUA/releases/latest/download/WAIUA.exe)
+2. Run the .exe (If a blue box saying "Windows protected your PC" shows up, click `More Info` and then `Run Anyway`)
+3. Follow the steps to install WAIUA
## Usage
-Please ensure you are in a match when you try to use it. I swear if you complain about it not working and you're not in a match...
+1. Open the app
+2. WAIUA will automatically check for new matches or wait for a match like a good boi
+3. Win games (unless you find out you're playing against a smurf. In that case RIP your RR)
+
+## Roadmap and Known Bugs
-If Valorant is already running:
-1. Press the big "WAIUA" button
-2. Profit
+Please check the [issues tab](https://github.com/WAIUA/WAIUA/issues) before making a new issue.
-If Valorant is not running:
-1. Press the account button in the top left
-2. Use your Riot Account details to log in. Remember to select your region from the bottom left.
-3. Open Valorant lmao
-3. Press the big "WAIUA" button
-4. Profit slightly less
+## Built With
-## Roadmap
+* [WPF](https://docs.microsoft.com/en-us/dotnet/desktop/wpf/?view=netdesktop-6.0)
+* [C#](https://docs.microsoft.com/en-us/dotnet/csharp/)
+* [.NET 6.0](https://dotnet.microsoft.com/)
+
+I knew none of these things before making this lol
+
+#### Packages that I used/ recommend
+
+* [RestSharp](https://restsharp.dev/) for API requests
+* [System.Text.Json](https://docs.microsoft.com/en-us/dotnet/api/system.text.json) to deserialise JSON. Source generators are a Godsend
+* [Windows Community Toolkit MVVM](https://docs.microsoft.com/en-us/windows/communitytoolkit/mvvm/introduction) for MVVM. Ty for Source Generators too
+* [AutoUpdater.NET](https://github.com/ravibpatel/AutoUpdater.NET) for auto updates
+* [Inno Setup](https://jrsoftware.org/isinfo.php) to install WAIUA
+* [FontAwesome](https://fontawesome.com/license) for icons. I'm also supposed say that I changed the colours so here it is
+
+## Why I Made This
-See the [open issues](https://github.com/Soneliem/WAIUA/issues) for a list of proposed features (and known issues).
+The main reason I made this was to detect smurfs. This app basically settles the debates between team members or the enemy. The set of available features was chosen carefully to maintain the competitive integrity of the game. Many suggestions that I get are declined due to this (unless a certain "competing" verified app implements it).
+
+Another reason to making this was that I wanted some experience with .NET and GUI apps. This application uses C# as the backend, WPF as the frontend and .NET as the framework. I knew none of these when I began, so this was a fun journey. I've gained alot of experice of how to and how not to (mostly the latter) use WPF and C#.
## Contributing
-I welcome any sort of contribution and am happy to take in any ~~hate/~~ feedback. Open source means open heart :)
+I welcome any sort of contribution. Please remember that translations are managed externally as mentioned below.
+
+## Sponsors
-## License
+This project is sponsored by:
-Distributed under the MIT License. See [LISCENSE](https://github.com/Soneliem/WAIUA/blob/master/LICENSE) for more information.
+
-## Contact
+Thank you for your support! Any donation of $5 and over will get you into the app's main page. Sponnsors of $10 or more are automatically added above.
-Discord: Soneliem#4194
-Project Link: [https://github.com/Soneliem/WAIUA](https://github.com/Soneliem/WAIUA)
+## Translations
+
+WAIUA Supports full localization and instructions to help with translations can be found in [Localization](./Localization.md)
## Acknowledgements
* [techchrism for work on documenting Valorant endpoints](https://github.com/techchrism/valorant-api-docs)
-* [RumbleMike for auth flow](https://github.com/RumbleMike/ValorantClientAPI)
-* [Valorant-API.com](https://valorant-api.com/)
+* [Valorant-API.com for all images, etc](https://valorant-api.com/)
* [The guys on the Valorant App Developers Discord Server](https://discord.gg/a9yzrw3KAm)
-* This project uses Riot's unofficial-private-notforpublicuse API for most of the information. Riot pls no kil
+* This project uses Riot's in-game API for most of the information
## DISCLAIMER
-THIS PROJECT IS NOT ASSOCIATED OR ENDORSED BY RIOT GAMES.
+
+THIS PROJECT IS NOT ASSOCIATED OR ENDORSED BY RIOT GAMES. Riot Games, and all associated properties are trademarks or registered trademarks of Riot Games, Inc.
+By using this application, you agree that you, the individual, are knowingly accessing all information required to be displayed.
diff --git a/Screenshots/card.png b/Screenshots/card.png
new file mode 100644
index 00000000..1dfb449a
Binary files /dev/null and b/Screenshots/card.png differ
diff --git a/Screenshots/history.png b/Screenshots/history.png
new file mode 100644
index 00000000..ff9d7f04
Binary files /dev/null and b/Screenshots/history.png differ
diff --git a/Screenshots/home.png b/Screenshots/home.png
new file mode 100644
index 00000000..92f3352f
Binary files /dev/null and b/Screenshots/home.png differ
diff --git a/Screenshots/language.png b/Screenshots/language.png
new file mode 100644
index 00000000..85c210cb
Binary files /dev/null and b/Screenshots/language.png differ
diff --git a/Screenshots/logo.png b/Screenshots/logo.png
new file mode 100644
index 00000000..12607232
Binary files /dev/null and b/Screenshots/logo.png differ
diff --git a/Screenshots/main.png b/Screenshots/main.png
new file mode 100644
index 00000000..e2ad9db4
Binary files /dev/null and b/Screenshots/main.png differ
diff --git a/Screenshots/mode.png b/Screenshots/mode.png
new file mode 100644
index 00000000..33f56953
Binary files /dev/null and b/Screenshots/mode.png differ
diff --git a/Screenshots/name.png b/Screenshots/name.png
new file mode 100644
index 00000000..71942d63
Binary files /dev/null and b/Screenshots/name.png differ
diff --git a/Screenshots/party.png b/Screenshots/party.png
new file mode 100644
index 00000000..8d59ffd6
Binary files /dev/null and b/Screenshots/party.png differ
diff --git a/Screenshots/pranks.png b/Screenshots/pranks.png
new file mode 100644
index 00000000..f6b54fc8
Binary files /dev/null and b/Screenshots/pranks.png differ
diff --git a/Screenshots/rank.png b/Screenshots/rank.png
new file mode 100644
index 00000000..ae1430cc
Binary files /dev/null and b/Screenshots/rank.png differ
diff --git a/Screenshots/refresh.png b/Screenshots/refresh.png
new file mode 100644
index 00000000..e8d264dc
Binary files /dev/null and b/Screenshots/refresh.png differ
diff --git a/Screenshots/skin.png b/Screenshots/skin.png
new file mode 100644
index 00000000..e4abab7e
Binary files /dev/null and b/Screenshots/skin.png differ
diff --git a/Screenshots/tracker.png b/Screenshots/tracker.png
new file mode 100644
index 00000000..245289fe
Binary files /dev/null and b/Screenshots/tracker.png differ
diff --git a/Screenshots/trainer.png b/Screenshots/trainer.png
new file mode 100644
index 00000000..fa2b0aba
Binary files /dev/null and b/Screenshots/trainer.png differ
diff --git a/WAIUA.sln b/WAIUA.sln
deleted file mode 100644
index 82368b89..00000000
--- a/WAIUA.sln
+++ /dev/null
@@ -1,31 +0,0 @@
-
-Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio Version 16
-VisualStudioVersion = 16.0.31515.178
-MinimumVisualStudioVersion = 10.0.40219.1
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WAIUA", "WAIUA\WAIUA.csproj", "{AF25112C-91B9-4735-AE9B-C7CE963A30A4}"
-EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{13E3F6B6-D516-4741-9317-407D36E7B34F}"
- ProjectSection(SolutionItems) = preProject
- .editorconfig = .editorconfig
- WAIUA\Views\Account.xaml.cs = WAIUA\Views\Account.xaml.cs
- EndProjectSection
-EndProject
-Global
- GlobalSection(SolutionConfigurationPlatforms) = preSolution
- Debug|Any CPU = Debug|Any CPU
- Release|Any CPU = Release|Any CPU
- EndGlobalSection
- GlobalSection(ProjectConfigurationPlatforms) = postSolution
- {AF25112C-91B9-4735-AE9B-C7CE963A30A4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {AF25112C-91B9-4735-AE9B-C7CE963A30A4}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {AF25112C-91B9-4735-AE9B-C7CE963A30A4}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {AF25112C-91B9-4735-AE9B-C7CE963A30A4}.Release|Any CPU.Build.0 = Release|Any CPU
- EndGlobalSection
- GlobalSection(SolutionProperties) = preSolution
- HideSolutionNode = FALSE
- EndGlobalSection
- GlobalSection(ExtensibilityGlobals) = postSolution
- SolutionGuid = {F05DC966-85E4-423F-85FE-52ECD226D937}
- EndGlobalSection
-EndGlobal
diff --git a/WAIUA/App.xaml b/WAIUA/App.xaml
deleted file mode 100644
index 18c7e62b..00000000
--- a/WAIUA/App.xaml
+++ /dev/null
@@ -1,20 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/WAIUA/App.xaml.cs b/WAIUA/App.xaml.cs
deleted file mode 100644
index 4499b181..00000000
--- a/WAIUA/App.xaml.cs
+++ /dev/null
@@ -1,16 +0,0 @@
-using System.Windows;
-
-namespace WAIUA
-{
- ///
- /// Interaction logic for App.xaml
- ///
- public partial class App : Application
- {
- private void Application_DispatcherUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e)
- {
- MessageBox.Show("An unhandled exception just occurred: " + e.Exception.Message, "Exception Sample", MessageBoxButton.OK, MessageBoxImage.Warning);
- e.Handled = true;
- }
- }
-}
\ No newline at end of file
diff --git a/WAIUA/AssemblyInfo.cs b/WAIUA/AssemblyInfo.cs
deleted file mode 100644
index 4f943deb..00000000
--- a/WAIUA/AssemblyInfo.cs
+++ /dev/null
@@ -1,10 +0,0 @@
-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)
-)]
\ No newline at end of file
diff --git a/WAIUA/Assets/rankdown.png b/WAIUA/Assets/rankdown.png
deleted file mode 100644
index e7ba39fc..00000000
Binary files a/WAIUA/Assets/rankdown.png and /dev/null differ
diff --git a/WAIUA/Assets/rankup.png b/WAIUA/Assets/rankup.png
deleted file mode 100644
index b84208ac..00000000
Binary files a/WAIUA/Assets/rankup.png and /dev/null differ
diff --git a/WAIUA/Assets/sign-in.png b/WAIUA/Assets/sign-in.png
deleted file mode 100644
index 4d50b62f..00000000
Binary files a/WAIUA/Assets/sign-in.png and /dev/null differ
diff --git a/WAIUA/Assets/user.png b/WAIUA/Assets/user.png
deleted file mode 100644
index 56baf766..00000000
Binary files a/WAIUA/Assets/user.png and /dev/null differ
diff --git a/WAIUA/Commands/APIConnection.cs b/WAIUA/Commands/APIConnection.cs
deleted file mode 100644
index bfe75a44..00000000
--- a/WAIUA/Commands/APIConnection.cs
+++ /dev/null
@@ -1,600 +0,0 @@
-using Newtonsoft.Json;
-using Newtonsoft.Json.Linq;
-using RestSharp;
-using System;
-using System.IO;
-using System.Net;
-using System.Text;
-using System.Text.RegularExpressions;
-
-namespace WAIUA.Commands
-{
- public static class APIConnection
- {
- public static string AccessToken { get; set; }
- public static string EntitlementToken { get; set; }
- public static string Region { get; set; }
- public static string Version { get; set; }
- public static string PPUUID { get; set; }
- public static string PUUID { get; set; }
- public static string Matchid { get; set; }
- public static string IGN { get; set; }
- public static string INusername { get; set; }
- public static string INpassword { get; set; }
- public static string Port { get; set; }
- public static string LPassword { get; set; }
- public static string Protocol { get; set; }
- public static string CurrentSeason { get; set; }
- public static string PSeason { get; set; }
- public static string PPSeason { get; set; }
- public static string PPPSeason { get; set; }
- public static int[] PlayerNo { get; set; } = new int[10];
- public static string[] PlayerList { get; set; } = new string[10];
- public static string[] PUUIDList { get; set; } = new string[10];
- public static string[] AgentList { get; set; } = new string[10];
- public static string[] AgentPList { get; set; } = new string[10];
- public static string[] CardList { get; set; } = new string[10];
- public static string[] LevelList { get; set; } = new string[10];
- public static string[] RankList { get; set; } = new string[10];
- public static string[] PRankList { get; set; } = new string[10];
- public static string[] PPRankList { get; set; } = new string[10];
- public static string[] PPPRankList { get; set; } = new string[10];
- public static string[] RankProgList { get; set; } = new string[10];
- public static string[] PGList { get; set; } = new string[10];
- public static string[] PPGList { get; set; } = new string[10];
- public static string[] PPPGList { get; set; } = new string[10];
- //public static string processName { get; set; };
- //public static string processId { get; set; };
-
- public static void Login(CookieContainer cookie, string username, string password)
- {
- try
- {
- APIConnection.GetAuthorization(cookie);
- var authJson = JsonConvert.DeserializeObject(APIConnection.Authenticate(cookie, username, password));
- JToken authObj = JObject.FromObject(authJson);
-
- string authURL = authObj["response"]["parameters"]["uri"].Value();
- var access_tokenVar = Regex.Match(authURL, @"access_token=(.+?)&scope=").Groups[1].Value;
- AccessToken = $"{access_tokenVar}";
-
- RestClient client = new RestClient(new Uri("https://entitlements.auth.riotgames.com/api/token/v1"));
- RestRequest request = new RestRequest(Method.POST);
-
- request.AddHeader("Authorization", $"Bearer {AccessToken}");
- request.AddJsonBody("{}");
-
- string response = client.Execute(request).Content;
- var entitlement_token = JsonConvert.DeserializeObject(response);
- JToken entitlement_tokenObj = JObject.FromObject(entitlement_token);
-
- EntitlementToken = entitlement_tokenObj["entitlements_token"].Value();
-
- GetPPUUID();
- }
- catch (Exception e)
- {
- System.Diagnostics.Debug.WriteLine(e);
- }
- }
-
- public static void GetPPUUID()
- {
- RestClient client = new RestClient(new Uri("https://auth.riotgames.com/userinfo"));
- RestRequest request = new RestRequest(Method.POST);
-
- request.AddHeader("Authorization", $"Bearer {AccessToken}");
- request.AddJsonBody("{}");
-
- string response = client.Execute(request).Content;
- var PlayerInfo = JsonConvert.DeserializeObject(response);
- JToken PUUIDObj = JObject.FromObject(PlayerInfo);
- PPUUID = PUUIDObj["sub"].Value();
- }
-
- public static void GetAuthorization(CookieContainer jar)
- {
- string url = "https://auth.riotgames.com/api/v1/authorization";
- RestClient client = new RestClient(url);
-
- client.CookieContainer = jar;
-
- RestRequest request = new RestRequest(Method.POST);
- string body = "{\"client_id\":\"play-valorant-web-prod\",\"nonce\":\"1\",\"redirect_uri\":\"https://playvalorant.com/opt_in" + "\",\"response_type\":\"token id_token\",\"scope\":\"account openid\"}";
- request.AddJsonBody(body);
- client.Execute(request);
- }
-
- public static string Authenticate(CookieContainer cookie, string user, string pass)
- {
- string url = "https://auth.riotgames.com/api/v1/authorization";
- RestClient client = new RestClient(url);
-
- client.CookieContainer = cookie;
-
- RestRequest request = new RestRequest(Method.PUT);
- string body = "{\"type\":\"auth\",\"username\":\"" + user + "\",\"password\":\"" + pass + "\",\"remember\": true, \"language\": \"en_US\"}";
- request.AddJsonBody(body);
-
- return client.Execute(request).Content;
- }
-
- //My attempt at re-authentication
- //public static void Reauth(CookieContainer jar)
- //{
- // RestClient client = new RestClient(new Uri("https://auth.riotgames.com/authorize?redirect_uri=https%3A%2F%2Fplayvalorant.com%2Fopt_in&client_id=play-valorant-web-prod&response_type=token%20id_token"));
- // client.CookieContainer = jar;
-
- // RestRequest request = new RestRequest();
-
- // var response = client.Get(request);
- // Uri responseUri = response.ResponseUri;
- // var errorMessage = response.ErrorMessage;
- // System.Diagnostics.Debug.WriteLine($"Response: {responseUri}");
- // System.Diagnostics.Debug.WriteLine($"errorCode: {errorMessage}");
-
- // AccessToken = responseUri.ToString();
- // string[] parts = AccessToken.Split(new char[] { '=', '&' });
- // AccessToken = parts[1];
-
- // RestClient client2 = new RestClient(new Uri("https://entitlements.auth.riotgames.com/api/token/v1"));
- // client2.CookieContainer = jar;
- // RestRequest request2 = new RestRequest();
-
- // request2.AddHeader("Authorization", $"Bearer {AccessToken}");
- // request2.AddJsonBody("{}");
-
- // var response2 = client2.Post(request2);
- // string content = client2.Execute(request2).Content;
- // var errorMessage2 = content;
- // System.Diagnostics.Debug.WriteLine($"errorCode2: {errorMessage2}");
- // var entitlement_token = JsonConvert.DeserializeObject(content);
- // JToken entitlement_tokenObj = JObject.FromObject(entitlement_token);
- // EntitlementToken = entitlement_tokenObj["entitlements_token"].Value();
- //}
- public static Boolean CheckLocal()
- {
- var lockfileLocation = $@"{Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData)}\Riot Games\Riot Client\Config\lockfile";
-
- if (File.Exists(lockfileLocation))
- {
- using (FileStream fileStream = new FileStream(lockfileLocation, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite))
- using (StreamReader sr = new StreamReader(fileStream))
- {
- string[] parts = sr.ReadToEnd().Split(":");
- Port = parts[2];
- LPassword = parts[3];
- Protocol = parts[4];
- return true;
- }
- }
- return false;
- }
-
- public static void LocalLogin()
- {
- GetLatestVersion();
- RestClient client = new RestClient(new Uri($"https://127.0.0.1:{Port}/entitlements/v1/token"));
- RestRequest request = new RestRequest(Method.GET);
- client.RemoteCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => true;
- request.AddHeader("Authorization", $"Basic {Convert.ToBase64String(Encoding.UTF8.GetBytes($"riot:{LPassword}"))}");
- request.AddHeader("X-Riot-ClientPlatform", "ew0KCSJwbGF0Zm9ybVR5cGUiOiAiUEMiLA0KCSJwbGF0Zm9ybU9TIjogIldpbmRvd3MiLA0KCSJwbGF0Zm9ybU9TVmVyc2lvbiI6ICIxMC4wLjE5MDQyLjEuMjU2LjY0Yml0IiwNCgkicGxhdGZvcm1DaGlwc2V0IjogIlVua25vd24iDQp9");
- request.AddHeader("X-Riot-ClientVersion", $"{Version}");
- request.RequestFormat = RestSharp.DataFormat.Json;
- var response = client.Get(request);
- string content = client.Execute(request).Content;
- var responsevar = JsonConvert.DeserializeObject(content);
- JToken responseObj = JObject.FromObject(responsevar);
- AccessToken = responseObj["accessToken"].Value();
- EntitlementToken = responseObj["token"].Value();
- GetPPUUID();
- }
-
- public static void LocalRegion()
- {
- GetLatestVersion();
- RestClient client = new RestClient(new Uri($"https://127.0.0.1:{Port}/product-session/v1/external-sessions"));
- RestRequest request = new RestRequest(Method.GET);
- client.RemoteCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => true;
- request.AddHeader("Authorization", $"Basic {Convert.ToBase64String(Encoding.UTF8.GetBytes($"riot:{LPassword}"))}");
- request.AddHeader("X-Riot-ClientPlatform", "ew0KCSJwbGF0Zm9ybVR5cGUiOiAiUEMiLA0KCSJwbGF0Zm9ybU9TIjogIldpbmRvd3MiLA0KCSJwbGF0Zm9ybU9TVmVyc2lvbiI6ICIxMC4wLjE5MDQyLjEuMjU2LjY0Yml0IiwNCgkicGxhdGZvcm1DaGlwc2V0IjogIlVua25vd24iDQp9");
- request.AddHeader("X-Riot-ClientVersion", $"{Version}");
- request.RequestFormat = RestSharp.DataFormat.Json;
- var response = client.Get(request);
- string content = client.Execute(request).Content;
- JObject root = JObject.Parse(content);
- JProperty property = (JProperty)root.First;
- var fullstring = (property.Value["launchConfiguration"]["arguments"][3]);
- string[] parts = fullstring.ToString().Split(new char[] { '=', '&' });
- string output = parts[1];
- Region = output;
- }
-
- public static void GetLatestVersion()
- {
- RestClient client = new RestClient(new Uri("https://valorant-api.com/v1/version"));
- RestRequest request = new RestRequest(Method.GET);
- var response = client.Get(request);
- string content = response.Content;
- var responsevar = JsonConvert.DeserializeObject(content);
- JToken responseObj = JObject.FromObject(responsevar);
- string Lversion = responseObj["data"]["riotClientVersion"].Value();
- Version = Lversion;
- }
-
- public static string GetIGUsername(CookieContainer cookie, string puuid)
- {
- try
- {
- string gameName = "";
- string gameTag = "";
- string url = $"https://pd.{Region}.a.pvp.net/name-service/v2/players";
- RestClient client = new RestClient(url);
- client.CookieContainer = cookie;
- RestRequest request = new RestRequest(Method.PUT);
-
- request.RequestFormat = RestSharp.DataFormat.Json;
- request.AddHeader("X-Riot-Entitlements-JWT", $"{EntitlementToken}");
- request.AddHeader("Authorization", $"Bearer {AccessToken}");
-
- string[] body = new String[1] { puuid };
- request.AddJsonBody(body);
-
- var response = client.Put(request);
- string content = client.Execute(request).Content;
-
- content = content.Replace("[", "");
- content = content.Replace("]", "");
-
- string errorMessage = response.ErrorMessage;
-
- var uinfo = JsonConvert.DeserializeObject(content);
- JToken uinfoObj = JObject.FromObject(uinfo);
- gameName = uinfoObj["GameName"].Value();
- gameTag = uinfoObj["TagLine"].Value();
- IGN = gameName + "#" + gameTag;
- }
- catch (Exception e)
- {
- System.Diagnostics.Debug.WriteLine(e);
- }
- return IGN;
- }
-
- public static Boolean LiveMatchID(CookieContainer jar)
- {
- try
- {
- string url = $"https://glz-{Region}-1.{Region}.a.pvp.net/core-game/v1/players/{PPUUID}";
- RestClient client = new RestClient(url);
- client.CookieContainer = jar;
- RestRequest request = new RestRequest(Method.GET);
- request.AddHeader("X-Riot-Entitlements-JWT", $"{EntitlementToken}");
- request.AddHeader("Authorization", $"Bearer {AccessToken}");
- string response = client.Execute(request).Content;
- var matchinfo = JsonConvert.DeserializeObject(response);
- JToken matchinfoObj = JObject.FromObject(matchinfo);
- Matchid = matchinfoObj["MatchID"].Value();
- return true;
- }
- catch (Exception e)
- {
- System.Diagnostics.Debug.WriteLine(e);
- return false;
- }
- }
-
- public static void LiveMatchSetup()
- {
- try
- {
- CookieContainer cookie = new CookieContainer();
- if (String.IsNullOrEmpty(APIConnection.GetIGUsername(cookie, PPUUID)))
- {
- if (CheckLocal())
- {
- LocalLogin();
- LocalRegion();
- }
- }
- if (LiveMatchID(cookie))
- {
- GetSeasons();
- GetLatestVersion();
- string url = $"https://glz-{Region}-1.{Region}.a.pvp.net/core-game/v1/matches/{Matchid}";
- RestClient client = new RestClient(url);
- RestRequest request = new RestRequest(Method.GET);
- request.AddHeader("X-Riot-Entitlements-JWT", $"{EntitlementToken}");
- request.AddHeader("Authorization", $"Bearer {AccessToken}");
- string content = client.Execute(request).Content;
- dynamic matchinfo = JsonConvert.DeserializeObject(content);
- int[] playerno = new int[10];
- string[] puuid = new string[10];
- string[] agent = new string[10];
- string[] card = new string[10];
- string[] level = new string[10];
- int index = 0;
- foreach (var entry in matchinfo.Players)
- {
- playerno[index] = index;
- puuid[index] = entry.Subject;
- agent[index] = entry.CharacterID;
- card[index] = entry.PlayerIdentity.PlayerCardID;
- level[index] = entry.PlayerIdentity.AccountLevel;
- index++;
- }
- PlayerNo = playerno;
- PUUIDList = puuid;
- AgentList = agent;
- CardList = card;
- LevelList = level;
- }
- }
- catch (Exception)
- {
- }
- }
-
- public static string[] LiveMatchOutput(int playerno)
- {
- CookieContainer cookie = new CookieContainer();
- PlayerList[playerno] = GetIGUsername(cookie, PUUIDList[playerno]);
- GetAgentInfo(AgentList[playerno], playerno);
- GetCardInfo(CardList[playerno], playerno);
- GetCompHistory(PUUIDList[playerno], playerno);
- GetPlayerHistory(PUUIDList[playerno], playerno);
-
- string[] output = new string[]{
- PlayerList[playerno],
- AgentList[playerno],
- AgentPList[playerno],
- CardList[playerno],
- LevelList[playerno],
- PGList[playerno],
- PPGList[playerno],
- PPPGList[playerno],
- RankProgList[playerno],
- RankList[playerno],
- PRankList[playerno],
- PPRankList[playerno],
- PPPRankList[playerno]
- };
- return output;
- }
-
- public static void GetAgentInfo(string agent, int playerno)
- {
- try
- {
- string url = $"https://valorant-api.com/v1/agents/{agent}";
- RestClient client = new RestClient(url);
- RestRequest request = new RestRequest(Method.GET);
-
- string response = client.Execute(request).Content;
- var agentinfo = JsonConvert.DeserializeObject(response);
- JToken agentinfoObj = JObject.FromObject(agentinfo);
- AgentPList[playerno] = agentinfoObj["data"]["killfeedPortrait"].Value();
- AgentList[playerno] = agentinfoObj["data"]["displayName"].Value();
- }
- catch (Exception e)
- {
- System.Diagnostics.Debug.WriteLine(e);
- }
- }
-
- public static void GetCardInfo(string card, int playerno)
- {
- try
- {
- string url = $"https://valorant-api.com/v1/playercards/{card}";
- RestClient client = new RestClient(url);
- RestRequest request = new RestRequest(Method.GET);
-
- string response = client.Execute(request).Content;
- var agentinfo = JsonConvert.DeserializeObject(response);
- JToken agentinfoObj = JObject.FromObject(agentinfo);
- CardList[playerno] = agentinfoObj["data"]["smallArt"].Value();
- }
- catch (Exception e)
- {
- System.Diagnostics.Debug.WriteLine(e);
- }
- }
-
- public static void GetCompHistory(string puuid, int playerno)
- {
- try
- {
- string url = $"https://pd.{Region}.a.pvp.net/mmr/v1/players/{puuid}/competitiveupdates?queue=competitive";
- RestClient client = new RestClient(url);
- RestRequest request = new RestRequest(Method.GET);
- request.AddHeader("X-Riot-Entitlements-JWT", $"{EntitlementToken}");
- request.AddHeader("Authorization", $"Bearer {AccessToken}");
- request.AddHeader("X-Riot-ClientPlatform", "ew0KCSJwbGF0Zm9ybVR5cGUiOiAiUEMiLA0KCSJwbGF0Zm9ybU9TIjogIldpbmRvd3MiLA0KCSJwbGF0Zm9ybU9TVmVyc2lvbiI6ICIxMC4wLjE5MDQyLjEuMjU2LjY0Yml0IiwNCgkicGxhdGZvcm1DaGlwc2V0IjogIlVua25vd24iDQp9");
- string response = client.Execute(request).Content;
- var historyinfo = JsonConvert.DeserializeObject(response);
- JToken historyinfoObj = JObject.FromObject(historyinfo);
- RankProgList[playerno] = historyinfoObj["Matches"][0]["RankedRatingAfterUpdate"].Value();
- if (historyinfoObj["Matches"][0]["RankedRatingEarned"].Value() >= 0)
- {
- PGList[playerno] = "/Assets/rankup.png";
- }
- else
- {
- PGList[playerno] = "/Assets/rankdown.png";
- }
- if (historyinfoObj["Matches"][1]["RankedRatingEarned"].Value() >= 0)
- {
- PPGList[playerno] = "/Assets/rankup.png";
- }
- else
- {
- PPGList[playerno] = "/Assets/rankdown.png";
- }
- if (historyinfoObj["Matches"][2]["RankedRatingEarned"].Value() >= 0)
- {
- PPPGList[playerno] = "/Assets/rankup.png";
- }
- else
- {
- PPPGList[playerno] = "/Assets/rankdown.png";
- }
- }
- catch (Exception e)
- {
- System.Diagnostics.Debug.WriteLine(e);
- }
- }
-
- public static void GetPlayerHistory(string puuid, int playerno)
- {
- try
- {
- string rank, prank, pprank, ppprank = "";
- string url = $"https://pd.{Region}.a.pvp.net/mmr/v1/players/{puuid}";
- RestClient client = new RestClient(url);
- RestRequest request = new RestRequest(Method.GET);
- request.AddHeader("X-Riot-Entitlements-JWT", $"{EntitlementToken}");
- request.AddHeader("Authorization", $"Bearer {AccessToken}");
- request.AddHeader("X-Riot-ClientPlatform", "ew0KCSJwbGF0Zm9ybVR5cGUiOiAiUEMiLA0KCSJwbGF0Zm9ybU9TIjogIldpbmRvd3MiLA0KCSJwbGF0Zm9ybU9TVmVyc2lvbiI6ICIxMC4wLjE5MDQyLjEuMjU2LjY0Yml0IiwNCgkicGxhdGZvcm1DaGlwc2V0IjogIlVua25vd24iDQp9");
- request.AddHeader("X-Riot-ClientVersion", $"{Version}");
- string content = client.Execute(request).Content;
- dynamic contentobj = JObject.Parse(content);
-
- rank = contentobj.QueueSkills.competitive.SeasonalInfoBySeasonID[$"{CurrentSeason}"].CompetitiveTier;
- RankList[playerno] = GetLRankIcon(rank);
- try
- {
- prank = contentobj.QueueSkills.competitive.SeasonalInfoBySeasonID[$"{PSeason}"].CompetitiveTier;
- }
- catch (Exception)
- {
- prank = "0";
- }
- PRankList[playerno] = GetRankIcon(prank);
- try
- {
- pprank = contentobj.QueueSkills.competitive.SeasonalInfoBySeasonID[$"{PPSeason}"].CompetitiveTier;
- }
- catch (Exception)
- {
- pprank = "0";
- }
- PPRankList[playerno] = GetRankIcon(pprank);
- try
- {
- ppprank = contentobj.QueueSkills.competitive.SeasonalInfoBySeasonID[$"{PPPSeason}"].CompetitiveTier;
- }
- catch (Exception)
- {
- ppprank = "0";
- }
- PPPRankList[playerno] = GetRankIcon(ppprank);
- }
- catch (Exception e)
- {
- System.Diagnostics.Debug.WriteLine(e);
- }
- }
-
- private static void GetSeasons()
- {
- try
- {
- string url = $"https://shared.{Region}.a.pvp.net/content-service/v2/content";
- RestClient client = new RestClient(url);
- RestRequest request = new RestRequest(Method.GET);
- request.AddHeader("X-Riot-Entitlements-JWT", $"{EntitlementToken}");
- request.AddHeader("Authorization", $"Bearer {AccessToken}");
- request.AddHeader("X-Riot-ClientPlatform", "ew0KCSJwbGF0Zm9ybVR5cGUiOiAiUEMiLA0KCSJwbGF0Zm9ybU9TIjogIldpbmRvd3MiLA0KCSJwbGF0Zm9ybU9TVmVyc2lvbiI6ICIxMC4wLjE5MDQyLjEuMjU2LjY0Yml0IiwNCgkicGxhdGZvcm1DaGlwc2V0IjogIlVua25vd24iDQp9");
- request.AddHeader("X-Riot-ClientVersion", $"{Version}");
- string response = client.Execute(request).Content;
- dynamic content = JsonConvert.DeserializeObject(response);
-
- int index = 0;
- int currentindex = 0;
-
- foreach (var season in content.Seasons)
- {
- if ((season.IsActive == true) & (season.Type == "act"))
- {
- CurrentSeason = season.ID;
- currentindex = index;
- }
- index++;
- }
- currentindex--;
- if (content.Seasons[currentindex].Type == "act")
- {
- PSeason = content.Seasons[currentindex].ID;
- }
- else
- {
- currentindex--;
- PSeason = content.Seasons[currentindex].ID;
- }
- currentindex--;
- if (content.Seasons[currentindex].Type == "act")
- {
- PPSeason = content.Seasons[currentindex].ID;
- }
- else
- {
- currentindex--;
- PPSeason = content.Seasons[currentindex].ID;
- }
- currentindex--;
- if (content.Seasons[currentindex].Type == "act")
- {
- PPPSeason = content.Seasons[currentindex].ID;
- }
- else
- {
- currentindex--;
- PPPSeason = content.Seasons[currentindex].ID;
- }
- }
- catch (Exception e)
- {
- System.Diagnostics.Debug.WriteLine(e);
- }
- }
-
- public static string GetLRankIcon(string rank)
- {
- string url = $"https://valorant-api.com/v1/competitivetiers";
- RestClient client = new RestClient(url);
- RestRequest request = new RestRequest(Method.GET);
- string response = client.Execute(request).Content;
- dynamic agentinfo = JsonConvert.DeserializeObject(response);
- string output = "";
- foreach (var tiers in agentinfo.data[2].tiers)
- {
- if (tiers.tier == rank)
- {
- output = tiers.largeIcon;
- break;
- }
- }
- return output;
- }
-
- public static string GetRankIcon(string rank)
- {
- string url = $"https://valorant-api.com/v1/competitivetiers";
- RestClient client = new RestClient(url);
- RestRequest request = new RestRequest(Method.GET);
- string response = client.Execute(request).Content;
- dynamic agentinfo = JsonConvert.DeserializeObject(response);
- string output = "";
- foreach (var tiers in agentinfo.data[2].tiers)
- {
- if (tiers.tier == rank)
- {
- output = tiers.smallIcon;
- }
- }
- return output;
- }
- }
-}
\ No newline at end of file
diff --git a/WAIUA/Commands/LiveMatch.cs b/WAIUA/Commands/LiveMatch.cs
deleted file mode 100644
index 515809f0..00000000
--- a/WAIUA/Commands/LiveMatch.cs
+++ /dev/null
@@ -1,6 +0,0 @@
-namespace WAIUA.Commands
-{
- public class LiveMatch
- {
- }
-}
\ No newline at end of file
diff --git a/WAIUA/Commands/UpdateViewCommand.cs b/WAIUA/Commands/UpdateViewCommand.cs
deleted file mode 100644
index 637ee457..00000000
--- a/WAIUA/Commands/UpdateViewCommand.cs
+++ /dev/null
@@ -1,39 +0,0 @@
-using System;
-using System.Windows.Input;
-using WAIUA.ViewModels;
-
-namespace WAIUA.Commands
-{
- public class UpdateViewCommand : ICommand
- {
- private MainViewModel viewModel;
-
- public UpdateViewCommand(MainViewModel viewModel)
- {
- this.viewModel = viewModel;
- }
-
- public event EventHandler CanExecuteChanged;
-
- public bool CanExecute(object parameter)
- {
- return true;
- }
-
- public void Execute(object parameter)
- {
- if (parameter.ToString() == "Home")
- {
- viewModel.SelectedViewModel = new HomeViewModel();
- }
- else if (parameter.ToString() == "Account")
- {
- viewModel.SelectedViewModel = new AccountViewModel();
- }
- else if (parameter.ToString() == "Profile")
- {
- viewModel.SelectedViewModel = new ProfileViewModel();
- }
- }
- }
-}
\ No newline at end of file
diff --git a/WAIUA/Fonts/RopaSans.ttf b/WAIUA/Fonts/RopaSans.ttf
deleted file mode 100644
index 660a493e..00000000
Binary files a/WAIUA/Fonts/RopaSans.ttf and /dev/null differ
diff --git a/WAIUA/MainWindow.xaml b/WAIUA/MainWindow.xaml
deleted file mode 100644
index 97aa502c..00000000
--- a/WAIUA/MainWindow.xaml
+++ /dev/null
@@ -1,240 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/WAIUA/MainWindow.xaml.cs b/WAIUA/MainWindow.xaml.cs
deleted file mode 100644
index 7b902af6..00000000
--- a/WAIUA/MainWindow.xaml.cs
+++ /dev/null
@@ -1,27 +0,0 @@
-using System.Windows;
-using WAIUA.Commands;
-using WAIUA.ViewModels;
-
-namespace WAIUA
-{
- ///
- /// Interaction logic for MainWindow.xaml
- ///
- public partial class MainWindow : Window
- {
- public MainWindow()
- {
- InitializeComponent();
- DataContext = new MainViewModel();
- }
-
- public void Window_Loaded(object sender, RoutedEventArgs e)
- {
- if (APIConnection.CheckLocal())
- {
- APIConnection.LocalLogin();
- APIConnection.LocalRegion();
- }
- }
- }
-}
\ No newline at end of file
diff --git a/WAIUA/ViewModels/AccountViewModel.cs b/WAIUA/ViewModels/AccountViewModel.cs
deleted file mode 100644
index e0fc433c..00000000
--- a/WAIUA/ViewModels/AccountViewModel.cs
+++ /dev/null
@@ -1,6 +0,0 @@
-namespace WAIUA.ViewModels
-{
- internal class AccountViewModel : BaseViewModel
- {
- }
-}
\ No newline at end of file
diff --git a/WAIUA/ViewModels/BaseViewModel.cs b/WAIUA/ViewModels/BaseViewModel.cs
deleted file mode 100644
index f297bde5..00000000
--- a/WAIUA/ViewModels/BaseViewModel.cs
+++ /dev/null
@@ -1,14 +0,0 @@
-using System.ComponentModel;
-
-namespace WAIUA.ViewModels
-{
- public class BaseViewModel : INotifyPropertyChanged
- {
- public event PropertyChangedEventHandler PropertyChanged;
-
- protected void OnPropertyChanged(string propertyName)
- {
- PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
- }
- }
-}
\ No newline at end of file
diff --git a/WAIUA/ViewModels/HomeViewModel.cs b/WAIUA/ViewModels/HomeViewModel.cs
deleted file mode 100644
index c03cf462..00000000
--- a/WAIUA/ViewModels/HomeViewModel.cs
+++ /dev/null
@@ -1,6 +0,0 @@
-namespace WAIUA.ViewModels
-{
- public class HomeViewModel : BaseViewModel
- {
- }
-}
\ No newline at end of file
diff --git a/WAIUA/ViewModels/MainViewModel.cs b/WAIUA/ViewModels/MainViewModel.cs
deleted file mode 100644
index 8534cd9a..00000000
--- a/WAIUA/ViewModels/MainViewModel.cs
+++ /dev/null
@@ -1,27 +0,0 @@
-using System.Windows.Input;
-using WAIUA.Commands;
-
-namespace WAIUA.ViewModels
-{
- public class MainViewModel : BaseViewModel
- {
- private BaseViewModel _selectedViewModel;
-
- public BaseViewModel SelectedViewModel
- {
- get { return _selectedViewModel; }
- set
- {
- _selectedViewModel = value;
- OnPropertyChanged(nameof(SelectedViewModel));
- }
- }
-
- public ICommand UpdateViewCommand { get; set; }
-
- public MainViewModel()
- {
- UpdateViewCommand = new UpdateViewCommand(this);
- }
- }
-}
\ No newline at end of file
diff --git a/WAIUA/ViewModels/ProfileViewModel.cs b/WAIUA/ViewModels/ProfileViewModel.cs
deleted file mode 100644
index e2e3cca1..00000000
--- a/WAIUA/ViewModels/ProfileViewModel.cs
+++ /dev/null
@@ -1,6 +0,0 @@
-namespace WAIUA.ViewModels
-{
- internal class ProfileViewModel : BaseViewModel
- {
- }
-}
\ No newline at end of file
diff --git a/WAIUA/Views/Account.xaml b/WAIUA/Views/Account.xaml
deleted file mode 100644
index 7afc8f73..00000000
--- a/WAIUA/Views/Account.xaml
+++ /dev/null
@@ -1,446 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Play around with each region if you are not sure which one you are in
-
-
-
-
\ No newline at end of file
diff --git a/WAIUA/Views/Account.xaml.cs b/WAIUA/Views/Account.xaml.cs
deleted file mode 100644
index 8fa08102..00000000
--- a/WAIUA/Views/Account.xaml.cs
+++ /dev/null
@@ -1,123 +0,0 @@
-using System;
-using System.Net;
-using System.Windows.Controls;
-using WAIUA.Commands;
-
-namespace WAIUA.Views
-{
- ///
- /// Interaction logic for Account.xaml
- ///
- public partial class Account : UserControl
- {
- public Account()
- {
- InitializeComponent();
- }
-
- private void Button_Click(object sender, System.Windows.RoutedEventArgs e)
- {
- LogIn();
- }
-
- private void PasswordBox_KeyDown(object sender, System.Windows.Input.KeyEventArgs e)
- {
- LogIn();
- }
-
- public void LogIn()
- {
- CookieContainer cookie = new CookieContainer();
- string user = usernameBox.Text;
- string pass = passwordBox.Password;
- while (true)
- {
- if (String.IsNullOrEmpty(user))
- {
- authStatusBox.Text = "Please enter your credentials";
- break;
- }
- else if (String.IsNullOrEmpty(pass))
- {
- authStatusBox.Text = "Please enter your credentials";
- break;
- }
- else if (this.RegionList.SelectedIndex == -1)
- {
- authStatusBox.Text = "Please select a region";
- break;
- }
- else
- {
- authStatusBox.Text = "Authenticating...";
- APIConnection.Login(cookie, user, pass);
- CheckAuth(cookie);
- break;
- }
- }
- }
-
- public void CheckAuth(CookieContainer cookie)
- {
- while (true)
- {
- if (String.IsNullOrEmpty(APIConnection.GetIGUsername(cookie, APIConnection.PPUUID)))
- {
- authStatusBox.Text = "Not Authenticated";
- break;
- }
- else
- {
- authStatusBox.Text = $"Authenticated as: {APIConnection.GetIGUsername(cookie, APIConnection.PPUUID)}";
- break;
- }
- }
- }
-
- private void Button_Click2(object sender, System.Windows.RoutedEventArgs e)
- {
- CookieContainer cookie = new CookieContainer();
- CheckAuth(cookie);
- }
-
- private void Button_Click3(object sender, System.Windows.RoutedEventArgs e)
- {
- CookieContainer cookie = new CookieContainer();
- if (APIConnection.CheckLocal() == true)
- {
- APIConnection.LocalLogin();
- APIConnection.LocalRegion();
- CheckAuth(cookie);
- }
- else
- {
- authStatusBox.Text = "Valorant need to be running for auto signin";
- }
- }
-
- private void ListBox_Selected(object sender, System.Windows.RoutedEventArgs e)
- {
- switch (RegionList.SelectedIndex)
- {
- case 0:
- APIConnection.Region = "na";
- break;
-
- case 1:
- APIConnection.Region = "ap";
- break;
-
- case 2:
- APIConnection.Region = "eu";
- break;
-
- case 3:
- APIConnection.Region = "ko";
- break;
-
- default:
- break;
- }
- }
- }
-}
\ No newline at end of file
diff --git a/WAIUA/Views/Home.xaml b/WAIUA/Views/Home.xaml
deleted file mode 100644
index b0132c2d..00000000
--- a/WAIUA/Views/Home.xaml
+++ /dev/null
@@ -1,1550 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/WAIUA/Views/Home.xaml.cs b/WAIUA/Views/Home.xaml.cs
deleted file mode 100644
index 94f52c62..00000000
--- a/WAIUA/Views/Home.xaml.cs
+++ /dev/null
@@ -1,73 +0,0 @@
-using System.Net;
-using System.Windows;
-using System.Windows.Controls;
-using WAIUA.Commands;
-
-namespace WAIUA.Views
-{
- ///
- /// Interaction logic for Home.xaml
- ///
- public partial class Home : UserControl
- {
- public class HomeInfo
- {
- public static string[] Player0 { get; set; }
- public static string[] Player1 { get; set; }
- public static string[] Player2 { get; set; }
- public static string[] Player3 { get; set; }
- public static string[] Player4 { get; set; }
- public static string[] Player5 { get; set; }
- public static string[] Player6 { get; set; }
- public static string[] Player7 { get; set; }
- public static string[] Player8 { get; set; }
- public static string[] Player9 { get; set; }
-
- public static HomeInfo GetHomeInfo()
- {
- var output = new HomeInfo() { };
- try
- {
- APIConnection.LiveMatchSetup();
- Player0 = APIConnection.LiveMatchOutput(0);
- Player1 = APIConnection.LiveMatchOutput(1);
- Player2 = APIConnection.LiveMatchOutput(2);
- Player3 = APIConnection.LiveMatchOutput(3);
- Player4 = APIConnection.LiveMatchOutput(4);
- Player5 = APIConnection.LiveMatchOutput(5);
- Player6 = APIConnection.LiveMatchOutput(6);
- Player7 = APIConnection.LiveMatchOutput(7);
- Player8 = APIConnection.LiveMatchOutput(8);
- Player9 = APIConnection.LiveMatchOutput(9);
- }
- catch (System.Exception)
- {
- }
- return output;
- }
- }
-
- public Home()
- {
- InitializeComponent();
- CookieContainer cookie = new CookieContainer();
- if (APIConnection.LiveMatchID(cookie))
- {
- DataContext = HomeInfo.GetHomeInfo();
- }
- else
- {
- if (APIConnection.CheckLocal())
- {
- APIConnection.LocalLogin();
- APIConnection.LocalRegion();
- DataContext = HomeInfo.GetHomeInfo();
- }
- }
- }
-
- public void Window_Loaded(object sender, RoutedEventArgs e)
- {
- }
- }
-}
\ No newline at end of file
diff --git a/WAIUA/Views/Profile.xaml b/WAIUA/Views/Profile.xaml
deleted file mode 100644
index acaaa813..00000000
--- a/WAIUA/Views/Profile.xaml
+++ /dev/null
@@ -1,28 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/WAIUA/Views/Profile.xaml.cs b/WAIUA/Views/Profile.xaml.cs
deleted file mode 100644
index e4741e44..00000000
--- a/WAIUA/Views/Profile.xaml.cs
+++ /dev/null
@@ -1,15 +0,0 @@
-using System.Windows.Controls;
-
-namespace WAIUA.Views
-{
- ///
- /// Interaction logic for Profile.xaml
- ///
- public partial class Profile : UserControl
- {
- public Profile()
- {
- InitializeComponent();
- }
- }
-}
\ No newline at end of file
diff --git a/WAIUA/WAIUA.csproj b/WAIUA/WAIUA.csproj
deleted file mode 100644
index a139cd66..00000000
--- a/WAIUA/WAIUA.csproj
+++ /dev/null
@@ -1,53 +0,0 @@
-
-
-
- WinExe
- net5.0-windows
- true
- logo.ico
-
-
-
-
-
-
-
-
-
-
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Never
-
-
-
-
diff --git a/WAIUA/cookies.json b/WAIUA/cookies.json
deleted file mode 100644
index 78500209..00000000
--- a/WAIUA/cookies.json
+++ /dev/null
@@ -1,11 +0,0 @@
-{
- "exclude": [
- "**/bin",
- "**/bower_components",
- "**/jspm_packages",
- "**/node_modules",
- "**/obj",
- "**/platforms"
-
- ]
-}
\ No newline at end of file
diff --git a/docs/.idea/.gitignore b/docs/.idea/.gitignore
new file mode 100644
index 00000000..b58b603f
--- /dev/null
+++ b/docs/.idea/.gitignore
@@ -0,0 +1,5 @@
+# Default ignored files
+/shelf/
+/workspace.xml
+# Editor-based HTTP Client requests
+/httpRequests/
diff --git a/docs/.idea/discord.xml b/docs/.idea/discord.xml
new file mode 100644
index 00000000..d8e95616
--- /dev/null
+++ b/docs/.idea/discord.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/docs/.idea/docs.iml b/docs/.idea/docs.iml
new file mode 100644
index 00000000..606f68ae
--- /dev/null
+++ b/docs/.idea/docs.iml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/docs/.idea/jsLibraryMappings.xml b/docs/.idea/jsLibraryMappings.xml
new file mode 100644
index 00000000..64b168e0
--- /dev/null
+++ b/docs/.idea/jsLibraryMappings.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/docs/.idea/modules.xml b/docs/.idea/modules.xml
new file mode 100644
index 00000000..6049cfe0
--- /dev/null
+++ b/docs/.idea/modules.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/docs/.idea/vcs.xml b/docs/.idea/vcs.xml
new file mode 100644
index 00000000..6c0b8635
--- /dev/null
+++ b/docs/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/docs/CNAME b/docs/CNAME
new file mode 100644
index 00000000..6f1219be
--- /dev/null
+++ b/docs/CNAME
@@ -0,0 +1 @@
+waiua.sonel.dev
\ No newline at end of file
diff --git a/docs/browserconfig.xml b/docs/browserconfig.xml
new file mode 100644
index 00000000..c5541482
--- /dev/null
+++ b/docs/browserconfig.xml
@@ -0,0 +1,2 @@
+
+#ffffff
\ No newline at end of file
diff --git a/docs/css/styles.css b/docs/css/styles.css
new file mode 100644
index 00000000..ad720d0c
--- /dev/null
+++ b/docs/css/styles.css
@@ -0,0 +1,346 @@
+@import url(https://fonts.googleapis.com/css?family=Maven+Pro:400,700);
+@import url(https://unicons.iconscout.com/release/v4.0.0/css/line.css);
+
+html {
+ scroll-behavior: smooth;
+}
+
+body {
+ font-family: "Maven Pro", sans-serif;
+ padding-top: 70px;
+}
+
+.small-text {
+ color: #5b5b5b;
+ font-size: 20px;
+ font-weight: 700;
+ padding: 8px 16px 8px 0;
+ border-radius: 50px;
+ letter-spacing: 0.2px;
+}
+
+ul {
+ margin: 0;
+ padding: 0;
+}
+
+ul li {
+ list-style: none;
+}
+
+a {
+ font-weight: 400;
+ text-decoration: none !important;
+ transition: all 0.4s ease;
+}
+
+a:hover {
+ color: #32e2b2 !important;
+}
+
+.navbar-brand .uil {
+ font-size: 40px;
+}
+
+p {
+ font-size: 18px;
+ font-weight: 300;
+ line-height: 1.5;
+ color: #ababab;
+}
+
+h1,
+h2,
+h3,
+h4,
+h5,
+h6 {
+ font-weight: 700;
+ letter-spacing: -1px;
+}
+
+h1 {
+ color: #212121;
+ font-size: 2.8em;
+ margin: 24px 0;
+}
+
+h2 {
+ color: #353535;
+ font-size: 2.4em;
+ font-weight: 700;
+}
+
+h3 {
+ color: #484848;
+ font-weight: 700;
+}
+
+th {
+ font-size: large;
+}
+
+td,
+th {
+ color: #d0cfcf;
+}
+
+.custom-btn {
+ background: #eee;
+ color: #5b5b5b;
+ font-weight: 700;
+ border-radius: 50px;
+ padding: 13px 29px;
+ font-size: 14px;
+ line-height: normal;
+ overflow: hidden;
+ transition: all 0.4s ease;
+}
+
+.custom-btn:hover {
+ color: #32e2b2;
+}
+
+.custom-btn.custom-btn-bg {
+ background: #474559;
+ color: #fff;
+}
+
+.custom-btn.custom-btn-bg:hover {
+ background: #32e2b2;
+ color: #fff !important;
+}
+
+.download-btn-text {
+ vertical-align: middle;
+ color: #fff;
+}
+
+.navbar-collapse {
+ justify-content: end;
+}
+
+.navbar-brand {
+ font-weight: 700;
+}
+
+.navbar-expand-sm .navbar-nav .nav-link {
+ padding: 0 20px;
+}
+
+.nav-link {
+ font-weight: 700;
+ font-size: 16px;
+ overflow: hidden;
+}
+
+.nav-link span {
+ position: relative;
+ display: inline-block;
+ transition: transform 0.3s;
+}
+
+.nav-link span:before {
+ position: absolute;
+ top: 100%;
+ content: attr(data-hover);
+ transform: translate3d(0, 0, 0);
+}
+
+.navbar-light .navbar-nav .nav-link:focus,
+.navbar-light .navbar-nav .nav-link:hover {
+ color: #32e2b2;
+ font-weight: 700;
+}
+
+.navbar-light .navbar-nav .nav-link:focus span,
+.navbar-light .navbar-nav .nav-link:hover span {
+ transform: translateY(-100%);
+}
+
+.navbar-light .navbar-toggler-icon {
+ background: 0 0;
+}
+
+.color-mode {
+ font-weight: 700;
+ cursor: pointer;
+}
+
+.color-mode-icon {
+ position: relative;
+ right: 6px;
+}
+
+.color-mode-icon:after {
+ font-family: unicons, serif;
+ content: "\ea9f";
+ font-size: 30px;
+ font-weight: 300;
+ font-style: normal;
+}
+
+.dark-mode {
+ background: #0c0c0d;
+}
+
+.dark-mode .navbar-light .navbar-nav .nav-link {
+ color: rgba(255, 255, 255, 0.8);
+}
+
+.dark-mode .navbar-light .navbar-nav .nav-link:hover {
+ color: #32e2b2;
+}
+
+.dark-mode .navbar[class*="headroom--not-top"] {
+ background: #0c0c0d;
+ border-bottom: 1px solid #1f1f1f;
+}
+
+.dark-mode .small-text {
+ background: #0d0c15;
+ color: #fff;
+}
+
+.dark-mode .color-mode,
+.dark-mode .navbar-light .navbar-brand,
+.dark-mode h1,
+.dark-mode h2,
+.dark-mode h3,
+.dark-mode h4,
+.dark-mode h5,
+.dark-mode h6 {
+ color: #fff;
+}
+
+.contact-info {
+ background: #474559;
+ border-radius: 0 0 3px 3px;
+ position: relative;
+ bottom: 8px;
+}
+
+.contact-info a,
+.contact-info p {
+ color: #f7f3f3;
+}
+
+.social-links .uil {
+ color: #f7f3f3;
+ font-size: 20px;
+ display: block;
+ margin: 5px 0;
+}
+
+.social-links .uil:hover {
+ color: #32e2b2;
+}
+
+@media (max-width: 991px) {
+ .color-mode {
+ display: none;
+ }
+
+ .about-image {
+ margin-top: 4em;
+ }
+
+ .contact-info {
+ padding: 0 2rem;
+ }
+}
+
+@media (max-width: 767px) {
+ h1 {
+ font-size: 2.4em;
+ }
+
+ h2 {
+ font-size: 2em;
+ }
+
+ .navbar-collapse {
+ background: #fff;
+ text-align: center;
+ padding-bottom: 20px;
+ }
+
+ .navbar-expand-sm .navbar-nav .nav-link {
+ padding: 3px 20px;
+ }
+}
+
+@media (max-width: 580px) {
+ .custom-btn-group {
+ text-align: center;
+ }
+
+ .custom-btn {
+ display: block;
+ margin: 10px 0;
+ }
+}
+
+@media (max-width: 320px) {
+ .about-text {
+ text-align: center;
+ }
+
+ .contact-info {
+ flex-direction: column;
+ }
+
+ .social-links li {
+ display: inline-block;
+ vertical-align: top;
+ }
+}
+
+.about-text h1 span {
+ display: inline-flex;
+ color: #32e2b2;
+}
+
+.about-text h1 span:nth-child(even) {
+ overflow: hidden;
+ transition: ease-in-out 0.5s;
+ color: #fff;
+ letter-spacing: -1em;
+}
+
+.about-text h1 .hover:nth-child(even),
+.about-text h1:hover span:nth-child(even) {
+ overflow: hidden;
+ transition: ease-in-out 0.5s;
+ color: #fff;
+ letter-spacing: 0;
+}
+
+.about-text h1 .hover:nth-child(2),
+.about-text h1:hover span:nth-child(2) {
+ transition-delay: 0s;
+}
+
+.about-text h1 .hover:nth-child(4),
+.about-text h1:hover span:nth-child(4) {
+ transition-delay: 0.5s;
+}
+
+.about-text h1 .hover:nth-child(8),
+.about-text h1:hover span:nth-child(8) {
+ transition-delay: 1s;
+}
+
+.about-text h1 .hover:nth-child(10),
+.about-text h1:hover span:nth-child(10) {
+ transition-delay: 1.5s;
+}
+
+.corner {
+ border-radius: 15px;
+}
+
+.warning {
+ color: red;
+ font-size: larger;
+}
\ No newline at end of file
diff --git a/docs/fonts/unicons-line.ttf b/docs/fonts/unicons-line.ttf
new file mode 100644
index 00000000..4595d806
Binary files /dev/null and b/docs/fonts/unicons-line.ttf differ
diff --git a/docs/images/android-icon-144x144.png b/docs/images/android-icon-144x144.png
new file mode 100644
index 00000000..83f8605d
Binary files /dev/null and b/docs/images/android-icon-144x144.png differ
diff --git a/docs/images/android-icon-192x192.png b/docs/images/android-icon-192x192.png
new file mode 100644
index 00000000..bbb35bfd
Binary files /dev/null and b/docs/images/android-icon-192x192.png differ
diff --git a/docs/images/android-icon-36x36.png b/docs/images/android-icon-36x36.png
new file mode 100644
index 00000000..c3321b88
Binary files /dev/null and b/docs/images/android-icon-36x36.png differ
diff --git a/docs/images/android-icon-48x48.png b/docs/images/android-icon-48x48.png
new file mode 100644
index 00000000..a9f700eb
Binary files /dev/null and b/docs/images/android-icon-48x48.png differ
diff --git a/docs/images/android-icon-72x72.png b/docs/images/android-icon-72x72.png
new file mode 100644
index 00000000..bbd189fc
Binary files /dev/null and b/docs/images/android-icon-72x72.png differ
diff --git a/docs/images/android-icon-96x96.png b/docs/images/android-icon-96x96.png
new file mode 100644
index 00000000..19456ba2
Binary files /dev/null and b/docs/images/android-icon-96x96.png differ
diff --git a/docs/images/apple-icon-114x114.png b/docs/images/apple-icon-114x114.png
new file mode 100644
index 00000000..bebce5cb
Binary files /dev/null and b/docs/images/apple-icon-114x114.png differ
diff --git a/docs/images/apple-icon-120x120.png b/docs/images/apple-icon-120x120.png
new file mode 100644
index 00000000..70024a2f
Binary files /dev/null and b/docs/images/apple-icon-120x120.png differ
diff --git a/docs/images/apple-icon-144x144.png b/docs/images/apple-icon-144x144.png
new file mode 100644
index 00000000..8e654e2a
Binary files /dev/null and b/docs/images/apple-icon-144x144.png differ
diff --git a/docs/images/apple-icon-152x152.png b/docs/images/apple-icon-152x152.png
new file mode 100644
index 00000000..7be4066c
Binary files /dev/null and b/docs/images/apple-icon-152x152.png differ
diff --git a/docs/images/apple-icon-180x180.png b/docs/images/apple-icon-180x180.png
new file mode 100644
index 00000000..e5d9baa2
Binary files /dev/null and b/docs/images/apple-icon-180x180.png differ
diff --git a/docs/images/apple-icon-57x57.png b/docs/images/apple-icon-57x57.png
new file mode 100644
index 00000000..78b0b7e1
Binary files /dev/null and b/docs/images/apple-icon-57x57.png differ
diff --git a/docs/images/apple-icon-60x60.png b/docs/images/apple-icon-60x60.png
new file mode 100644
index 00000000..3e4b2e75
Binary files /dev/null and b/docs/images/apple-icon-60x60.png differ
diff --git a/docs/images/apple-icon-72x72.png b/docs/images/apple-icon-72x72.png
new file mode 100644
index 00000000..b2af6c82
Binary files /dev/null and b/docs/images/apple-icon-72x72.png differ
diff --git a/docs/images/apple-icon-76x76.png b/docs/images/apple-icon-76x76.png
new file mode 100644
index 00000000..f5b104de
Binary files /dev/null and b/docs/images/apple-icon-76x76.png differ
diff --git a/docs/images/apple-icon-precomposed.png b/docs/images/apple-icon-precomposed.png
new file mode 100644
index 00000000..a717bcd9
Binary files /dev/null and b/docs/images/apple-icon-precomposed.png differ
diff --git a/docs/images/apple-icon.png b/docs/images/apple-icon.png
new file mode 100644
index 00000000..1642e5cd
Binary files /dev/null and b/docs/images/apple-icon.png differ
diff --git a/docs/images/card.png b/docs/images/card.png
new file mode 100644
index 00000000..c6b27553
Binary files /dev/null and b/docs/images/card.png differ
diff --git a/docs/images/favicon-16x16.png b/docs/images/favicon-16x16.png
new file mode 100644
index 00000000..4fd57a8c
Binary files /dev/null and b/docs/images/favicon-16x16.png differ
diff --git a/docs/images/favicon-32x32.png b/docs/images/favicon-32x32.png
new file mode 100644
index 00000000..55e67530
Binary files /dev/null and b/docs/images/favicon-32x32.png differ
diff --git a/docs/images/favicon-96x96.png b/docs/images/favicon-96x96.png
new file mode 100644
index 00000000..c137eba5
Binary files /dev/null and b/docs/images/favicon-96x96.png differ
diff --git a/docs/images/favicon.ico b/docs/images/favicon.ico
new file mode 100644
index 00000000..bc9607f7
Binary files /dev/null and b/docs/images/favicon.ico differ
diff --git a/docs/images/history.png b/docs/images/history.png
new file mode 100644
index 00000000..3b5300c9
Binary files /dev/null and b/docs/images/history.png differ
diff --git a/docs/images/language.png b/docs/images/language.png
new file mode 100644
index 00000000..d71cce4d
Binary files /dev/null and b/docs/images/language.png differ
diff --git a/docs/images/logo.png b/docs/images/logo.png
new file mode 100644
index 00000000..ca56ee7c
Binary files /dev/null and b/docs/images/logo.png differ
diff --git a/docs/images/main.png b/docs/images/main.png
new file mode 100644
index 00000000..f28512f1
Binary files /dev/null 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..57521784
Binary files /dev/null and b/docs/images/mode.png differ
diff --git a/docs/images/ms-icon-144x144.png b/docs/images/ms-icon-144x144.png
new file mode 100644
index 00000000..3919236c
Binary files /dev/null and b/docs/images/ms-icon-144x144.png differ
diff --git a/docs/images/ms-icon-150x150.png b/docs/images/ms-icon-150x150.png
new file mode 100644
index 00000000..a31996ab
Binary files /dev/null and b/docs/images/ms-icon-150x150.png differ
diff --git a/docs/images/ms-icon-310x310.png b/docs/images/ms-icon-310x310.png
new file mode 100644
index 00000000..9cd7be46
Binary files /dev/null and b/docs/images/ms-icon-310x310.png differ
diff --git a/docs/images/ms-icon-70x70.png b/docs/images/ms-icon-70x70.png
new file mode 100644
index 00000000..2acbc5d8
Binary files /dev/null and b/docs/images/ms-icon-70x70.png differ
diff --git a/docs/images/name.png b/docs/images/name.png
new file mode 100644
index 00000000..71942d63
Binary files /dev/null and b/docs/images/name.png differ
diff --git a/docs/images/party.png b/docs/images/party.png
new file mode 100644
index 00000000..aed3c90c
Binary files /dev/null and b/docs/images/party.png differ
diff --git a/docs/images/pranks.png b/docs/images/pranks.png
new file mode 100644
index 00000000..006b31b9
Binary files /dev/null and b/docs/images/pranks.png differ
diff --git a/docs/images/rank.png b/docs/images/rank.png
new file mode 100644
index 00000000..449d53be
Binary files /dev/null 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..63a47675
Binary files /dev/null and b/docs/images/refresh.png differ
diff --git a/docs/images/skin.png b/docs/images/skin.png
new file mode 100644
index 00000000..6aba93a3
Binary files /dev/null and b/docs/images/skin.png differ
diff --git a/docs/images/softpedia.png b/docs/images/softpedia.png
new file mode 100644
index 00000000..eb720cdd
Binary files /dev/null and b/docs/images/softpedia.png differ
diff --git a/docs/images/tracker.png b/docs/images/tracker.png
new file mode 100644
index 00000000..245289fe
Binary files /dev/null and b/docs/images/tracker.png differ
diff --git a/docs/images/trainer.png b/docs/images/trainer.png
new file mode 100644
index 00000000..e9e544e5
Binary files /dev/null and b/docs/images/trainer.png differ
diff --git a/docs/index.html b/docs/index.html
new file mode 100644
index 00000000..bde6eb9b
--- /dev/null
+++ b/docs/index.html
@@ -0,0 +1,472 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ WAIUA
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
WAIUA
+
+
+
+
+
+
+
+
+
+
+
+ WAIUA has left active development. It won't stop working immediately, as
+ it is completely standalone and communicates directly with Riot Servers. However, like it has happened before,
+ changes
+ to Riot's architecture will eventually break WAIUA's functionality. Full story on my Discord server.
+
+
+
+
+
+
+
+
This is:
+
+ W ho
+ A m
+ I
+ U p
+ A gainst
+
+
A simple Windows app that lets you see the ranks, recent games and other info of players in a
+ live Valorant match while you're still playing it.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Screenshot
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Rank
+
Current Rank and Rank Progress
+
+
+
+
+
Previous Ranks
+
Past three ranks (from last 3 acts)
+
+
+
+
+
+
+
+
+
+
+
Last 3 Games
+
RR lost or gained in last three competitive games
+
+
+
+
+
In-game and Agent name
+
Full game name and the agent that they are playing
+
+
+
+
+
+
+
+
+
+
+
Vandal And Phantom Skin
+
For both teams
+
+
+
+
+
Account Level and Agent Image
+
Account level and Agent for quick navigation. Replaced with Card when unavailable
+
+
+
+
+
+
+
+
+
+
+
Party Indicators
+
See who's in a party togeather
+
+
+
+
+
Tracker.gg integration
+
If a player is on tracker.gg , a link will be available
+
+
+
+
+
+
+
+
+
+
+
+
Translations
+
Fully translated into 15+ languages
+
+
+
+
+
Mini-Aim Trainer
+
Test your skills while waiting for a match
+
+
+
+
+
+
+
+
+
+
+
+
Support For all Game Modes
+
Including Agent Select
+
+
+
+
+
Auto Refresh and Updates
+
Automatically refreshes when going in an out of a game
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Compare
+
+
+
+
+
+
+ Feature
+ WAIUA
+ Tracker.gg
+
+
+
+
+ Current Rank
+ ✔️
+ ✔️
+
+
+ Agent and In-Game Name Info
+ ✔️
+ ✔️
+
+
+ Party Info
+ ✔️
+ ✔️
+
+
+ Previous Ranks
+ ✔️
+ ❌
+
+
+ Last 3 Game W/L
+ ✔️
+ ❌
+
+
+ Account Level
+ ✔️
+ ❌
+
+
+ Skin Previews
+ ✔️
+ ❌
+
+
+ Aim Trainer
+ ✔️
+ ❌
+
+
+ Reads Game Memory
+ ❌
+ ✔️
+
+
+ A million dollar for-profit company
+ ❌
+ ✔️
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Frequently Asked Questions
+
+
+
+
+
Can I get banned using this?
+
No, if Riot doesn't want you using it, they will contact me first.
+
+
+
Doesn't this break Riot's TOS?
+
On your side, no. On my side, also no. This app uses the ingame API which has no rules.
+
+
+
+
+
How is this app even useful?
+
The main intention is to settle the debate of if they are a smurf or not. Some of the other
+ features like the skin viewer are useful to worthlessly beg for skins, etc.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Discord
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Help Support this Project
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/docs/js/custom.js b/docs/js/custom.js
new file mode 100644
index 00000000..c33b0202
--- /dev/null
+++ b/docs/js/custom.js
@@ -0,0 +1,29 @@
+
+
+
+$(document).ready(function() {
+ var download_count = 0;
+ var output;
+ const settings = {
+ "async": true,
+ "crossDomain": true,
+ "url": "https://api.github.com/repos/pwall2222/NOWT/releases",
+ "method": "GET",
+ "headers": {}
+ };
+
+ $.ajax(settings).done(function (response) {
+ response.forEach(element => {
+ download_count = download_count + element.assets[0].download_count;
+ });
+ $("#download_count").html(download_count);
+ console.log(download_count);
+ });
+
+
+ setInterval(function(){
+ $('.about-text > h1 > span').toggleClass('hover');
+ },5000);
+
+
+ });
\ No newline at end of file
diff --git a/docs/manifest.json b/docs/manifest.json
new file mode 100644
index 00000000..013d4a6a
--- /dev/null
+++ b/docs/manifest.json
@@ -0,0 +1,41 @@
+{
+ "name": "App",
+ "icons": [
+ {
+ "src": "\/android-icon-36x36.png",
+ "sizes": "36x36",
+ "type": "image\/png",
+ "density": "0.75"
+ },
+ {
+ "src": "\/android-icon-48x48.png",
+ "sizes": "48x48",
+ "type": "image\/png",
+ "density": "1.0"
+ },
+ {
+ "src": "\/android-icon-72x72.png",
+ "sizes": "72x72",
+ "type": "image\/png",
+ "density": "1.5"
+ },
+ {
+ "src": "\/android-icon-96x96.png",
+ "sizes": "96x96",
+ "type": "image\/png",
+ "density": "2.0"
+ },
+ {
+ "src": "\/android-icon-144x144.png",
+ "sizes": "144x144",
+ "type": "image\/png",
+ "density": "3.0"
+ },
+ {
+ "src": "\/android-icon-192x192.png",
+ "sizes": "192x192",
+ "type": "image\/png",
+ "density": "4.0"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/global.json b/global.json
new file mode 100644
index 00000000..0b738cd8
--- /dev/null
+++ b/global.json
@@ -0,0 +1,5 @@
+{
+ "sdk": {
+ "version": "6.0.400"
+ }
+}