Giter Club home page Giter Club logo

riot-games-dotnet-client's Introduction

Riot Games .NET Client (unofficial)

Daily Test (@main) .NET CodeQL

image

An unofficial .NET Client for Riot Games and their games League of Legends, Legends of Runeterra, Teamfight Tactics and Valorant.

✅ Purpose-built Open API client generator

✅ Vanilla C# - Code generation done with Roslyn.

✅ Auto-generated overloads for CLR objects.

✅ Continuously tested against the live API.

✅ All tests required to be successful before deploy.

✅ Performance tested - the extra classes have no measurable impact.

✅ Optimized - you call the HttpClient almost directly.

Embedded symbols and Source link - see the source code while debugging.

Deterministic build - byte-for-byte output is identical across compilations.

❌ POST, PUT, DELETE and queries - for that, use other libraries for now (e.g. for RGAPI, Camille, and or LCU, PoniLCU).

❌ Game API - for that, use other libraries for now (e.g. Camille).

Sponsors

A big thank you for your support!

Sentry Logo JetBrains Logo (Main) logo

Demo

You can see the library running in your browser using Blazor at masteries.quest, which has a Cloudflare Workers proxy between the browser and Riot Games API.

Download

You can find the latest releases on GitHub Packages and on NuGet.org.

To install the latest version of the package, type the following in the package manager console:

Install-Package MikaelDui.RiotGames.Client

Or use the .NET CLI reference the latest stable and stay up-to-date:

dotnet add package MikaelDui.RiotGames.Client --version *

You can also use a PackageReference to stay up-to-date with the latest stable build:

<PackageReference Include="MikaelDui.RiotGames.Client" Version="*" />

Examples

using RiotGames.LeagueOfLegends;
using LeagueOfLegendsClient client = new("RGAPI-SUPERSECRET", Server.NA);

var summoner = await client.GetSummonerByNameAsync("Some summoner name");
var masteries = await client.GetMasteriesAsync(summoner);
foreach(var mastery in masteries)
    Console.WriteLine($"Champion #{mastery.ChampionId}: {mastery.championPoints} points");
using RiotGames.LegendsOfRuneterra;
using LegendsOfRuneterraClient client = new("RGAPI-SUPERSECRET", RegionRoute.AMERICAS);

var leaderboards = await client.GetRankedLeaderboardsAsync();
foreach(var player in leaderboards.Players)
    Console.WriteLine($"Player #{player.Name}: {player.Lp} LP");
using RiotGames.TeamfightTactics;
using TeamfightTacticsClient client = new("RGAPI-SUPERSECRET", PlatformRoute.NA1);

var leagueEntries = await client.GetLeagueEntriesAsync("some-summoner-ID");
foreach(var entry in leagueEntries)
    Console.WriteLine($"Player #{entry.SummonerName}: {player.LeaguePoints} LP");

Getting a Valorant match

using RiotGames.Valorant;
using ValorantClient client = new("RGAPI-SUPERSECRET", ValPlatformRoute.EU);

var match = await client.GetMatchAsync("some-match-ID");
foreach(var player in match.Players)
    Console.WriteLine($"Player #{player.Title} played champion #{player.ChampionId}");

Doing multi-game stuff

Using the RiotGamesClient class gives you easy access to multiple game clients at once.

using RiotGames;
using RiotGamesClient client = new("RGAPI-SUPERSECRET", PlatformRoute.NA1, ValPlatformRoute.NA);

var lolSummoner = await client.LeagueOfLegends.GetSummonerByNameAsync("some-summoner-name");
var lolMasteries = await client.LeagueOfLegends.GetMasteriesAsync(summoner);
foreach(var mastery in lolMasteries)
    Console.WriteLine($"Champion #{mastery.ChampionId}: {mastery.championPoints} points");

var lorLeaderboards = await client.LegendsOfRuneterra.GetRankedLeaderboardsAsync();
foreach(var player in lorLeaderboards.Players)
    Console.WriteLine($"Player #{player.Name}: {player.Lp} LP");

Getting the current League of Legends champ select

You can use the LeagueClient to communicate directly with the League Client (aka LCU).

using RiotGames.LeagueOfLegends.LeagueClient;
using LeagueClient.LeagueOfLegendsClient client = new();

var session = await client.ChampSelect.GetSessionAsync();
foreach(var teamMember in session.MyTeam)
{
    var summoner = await client.Summoners.GetSummonerAsync(teamMember);
    Console.WriteLine($"Team member: {summoner.DisplayName}");
}

Generated Code

The generated code looks like this:

image

Sub-packages

The client includes these sub-packages:

Notice from Riot Games

Riot Games .NET Client (unofficial) isn't endorsed by Riot Games and doesn't reflect the views or opinions of Riot Games or anyone officially involved in producing or managing Riot Games properties. Riot Games, and all associated properties are trademarks or registered trademarks of Riot Games, Inc.

riot-games-dotnet-client's People

Contributors

mikaeldui avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

Forkers

ponita0

riot-games-dotnet-client's Issues

Proxy support for League Client

It'd be great to be able to use the library to remotely operate a League Client. This would be through some kind of proxy.

One could, for example, create a Mimic clone so that one can do champ select from the WC.

Support for request bundling

Would improve performance for multiple queries against a platform/region far away.

Suggested implementation:

var req1 = new SummonerRequest("summonerA");
var req2 = new ChampMasteryRequest(hmmmm); // Placeholder value?

var results = await (new LeagueOfLegendsMultiRequestClient(Server.NA)).SendAsync(req1, req2);

Could this be solved by WebSocket support, #50 ?


For reference, here are the ping times to euw1.api.riotgames.com from location all around the world (https://tools.keycdn.com/ping):

image

Injectable support

Something like .AddRiotGames(options => options.Token = "RGAPI-1234").

LCU schema no longer updated

The LCU schema can no longer be access using enable_swagger in LCU's system.yaml. See RiotGames/developer-relations#608.

This means that there won't be any new endpoints added automatically and deprecated endpoints won't be removed automatically, and endpoints with changes could break.

If something's missing or broken one could write the models and methods for the new endpoints manually, using the internal Get/Post/Put/Delete methods.

LCU messages as events

The most idiomatic way to consume LCU event messages would probably be trough event though they might be too advanced so a backup solution by still providing ReceiveAsync?

Current working code:

internal delegate void LeagueClientEventHandler<in T>(LcuClient sender, T args);

internal class LcuClient : LeagueClient
{
    private readonly ConcurrentDictionary<string, Action<JsonElement>> _subscriptions = new();
    private readonly SemaphoreSlim _connectionLock = new(1, 1);
    private readonly CancellationTokenSource _cancellationTokenSource = new();

    private readonly JsonSerializerOptions _jsonSerializerOptions = new() {PropertyNameCaseInsensitive = true};

    protected void Subscribe<T>(string topic, Action<T> handler) => Task.Run(async () =>
    {
        await _connectionLock.WaitAsync();
        try
        {
            if (_subscriptions.IsEmpty) // Then the connection is closed.
            {
                _cancellationTokenSource.TryReset();
                await WampClient.ConnectAsync(); // TODO: CancellationToken

                _ = Task.Run(async () =>
                {
                    while (!_cancellationTokenSource.IsCancellationRequested)
                    {
                        var response = await this.WampClient.ReceiveAsync(_cancellationTokenSource.Token);
                        if (!_subscriptions.TryGetValue(response.Topic, out var subscriber)) continue;
                        subscriber?.Invoke(response.Data);
                    }
                }, _cancellationTokenSource.Token).ConfigureAwait(false);
            }
        }
        finally
        {
            _connectionLock.Release();
        }

        if (_subscriptions.TryAdd(topic,
                data => handler.Invoke(data.Deserialize<T>(_jsonSerializerOptions) ??
                                       throw new LeagueClientException("Couldn't deserialize the event payload."))))
            await WampClient.SubscribeAsync(topic);
    }).ConfigureAwait(false);

    protected void Unsubscribe(string topic) => Task.Run(async () =>
    {
        await WampClient.UnsubscribeAsync("OnJsonApiEvent_lol-champ-select_v1_session");
        _subscriptions.Remove(topic, out _);

        await _connectionLock.WaitAsync();
        try
        {
            if (_subscriptions.IsEmpty) // Then the connection should be closed.
            {
                _cancellationTokenSource.Cancel();
                await WampClient.CloseAsync();
            }
        }
        finally
        {
            _connectionLock.Release();
        }
    }).ConfigureAwait(false);

    private event LeagueClientEventHandler<LolChampSelectChampSelectSession>? _onChampSelectSessionChanged;

    public event LeagueClientEventHandler<LolChampSelectChampSelectSession>? OnChampSelectSessionChanged
    {
        add
        {
            if (_onChampSelectSessionChanged == null)
                Subscribe("OnJsonApiEvent_lol-champ-select_v1_session",
                    (LolChampSelectChampSelectSession args) => _onChampSelectSessionChanged?.Invoke(this, args));

            _onChampSelectSessionChanged += value;
        }
        remove
        {
            _onChampSelectSessionChanged -= value;

            if (_onChampSelectSessionChanged == null)
                Unsubscribe("OnJsonApiEvent_lol-champ-select_v1_session");
        }
    }
}

with a test app:

Console.WriteLine("Welcome!");

using LcuClient client = new();

void OnClientOnOnChampSelectSessionChanged(LcuClient sender, LolChampSelectChampSelectSession session) => Console.WriteLine(string.Join(", ", new[] {session.MyTeam[0].SummonerId}));

client.OnChampSelectSessionChanged += OnClientOnOnChampSelectSessionChanged;

await Task.Delay(30000);

client.OnChampSelectSessionChanged -= OnClientOnOnChampSelectSessionChanged;

Console.WriteLine("Done!");
Console.ReadKey();

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.