Skip to content

ManiaAPI.NET is an unofficial collection of .NET web API wrappers connected with Trackmania and ManiaPlanet games.

License

Notifications You must be signed in to change notification settings

BigBang1112/maniaapi-net

Repository files navigation

GitHub release (latest by date including pre-releases) GitHub last commit (branch)

A wrapper for these web APIs:

This set of libraries was made to be very easy and straightforward to use, but also easily mocked, so that it can be integrated into the real world in no time.

Packages

Anything you can imagine!

Samples

  • WebAppXmlExample - Blazor Server web application that demonstrates the use of the ManiaAPI.Xml API, currently only TMTurbo.
  • WebAppTmxExample - Blazor Server web application that demonstrates the use of the ManiaAPI.TMX API.
  • WebAppAuthorizationExample - Simple ASP.NET Core web application to show how to conveniently use the OAuth2 from ManiaAPI.TrackmaniaAPI.Extensions.Hosting and ManiaAPI.ManiaPlanetAPI.Extensions.Hosting.

See the Samples folder for more.

ManiaAPI.NadeoAPI

NuGet

Wraps the official Nadeo API used in the latest Trackmania (2020). This API requires authorization.

After initial authentication, the connectivity is managed by the library, so you don't have to worry about refreshing the token.

The game provides 3 domains, and they are split into 3 separate services:

  • NadeoServices for the core functionality
  • NadeoLiveServices for leaderboards, clubs, and other live content
  • NadeoMeetServices for getting the current Cup of the Day

Features

For NadeoServices:

  • Get map records
  • Get account records
  • Get player zones
  • Get API routes
  • Get all available zones
  • Get player club tags
  • Get map info

For NadeoLiveServices:

  • Edit club campaigns
  • Edit club activities
  • Get map info
  • Get map leaderboards
  • Get map medal records
  • Get seasonal campaigns
  • Get weekly shorts
  • Get TOTDs
  • Get club campaigns
  • Get club info
  • Get club members
  • Get club activities
  • Get club rooms
  • Get player season rankings
  • Get active advertisements
  • Join daily channel (COTD)

For NadeoMeetServices:

  • Get the current Cup of the Day

Setup for a single service

using ManiaAPI.NadeoAPI;

var ns = new NadeoServices();

await ns.AuthorizeAsync("mylogin", "mypassword", AuthorizationMethod.UbisoftAccount);

// Ready to use
var zones = await ns.GetZonesAsync();

You can also use a dedicated server. Just be aware it has some limitations.

await ns.AuthorizeAsync("my_dedicated_server", "ls>97jO>e3>>D/Ce", AuthorizationMethod.DedicatedServer);

For other services, just replace NadeoServices with NadeoLiveServices or NadeoMeetServices.

Setup for multiple services

using ManiaAPI.NadeoAPI;

var login = "mylogin";
var password = "mypassword";

var ns = new NadeoServices();
await ns.AuthorizeAsync(login, password, AuthorizationMethod.UbisoftAccount);

var nls = new NadeoLiveServices();
await nls.AuthorizeAsync(login, password, AuthorizationMethod.UbisoftAccount);

// Ready to use combined

// With NadeoLiveServices
var weeklyCampaigns = await nls.GetSeasonalCampaignsAsync(1);
var campaignMap = weeklyCampaigns.CampaignList.First().Playlist.First();
var mapInfo = await nls.GetMapInfoAsync(campaignMap.MapUid);
var mapLeaderboard = await nls.GetTopLeaderboardAsync(campaignMap.MapUid);

// With NadeoServices
var records = await ns.GetMapRecordsAsync(mapLeaderboard.Top.Top.Select(x => x.AccountId), mapInfo.MapId);

For DI, consider using the ManiaAPI.NadeoAPI.Extensions.Hosting package. It handles the authorization for you without additional startup code.

ManiaAPI.NadeoAPI.Extensions.Hosting

NuGet

Provides an efficient way to inject all Nadeo services into your application.

Setup

Providing options.Credentials is optional, but setting it will automatically authorize on the first request and maintain that connection, so you don't have to call AuthorizeAsync.

using ManiaAPI.TrackmaniaAPI.Extensions.Hosting;

builder.Services.AddNadeoAPI(options =>
{
    options.Credentials = new NadeoAPICredentials(
        builder.Configuration["NadeoAPI:Login"]!,
        builder.Configuration["NadeoAPI:Password"]!,
        AuthorizationMethod.DedicatedServer);
});

Features this setup brings:

  • NadeoServices, NadeoLiveServices, and NadeoMeetServices will be available as transients
  • HTTP client will be handled properly
  • Credentials will be handled as a singleton

ManiaAPI.NadeoAPI.Extensions.Gbx

NuGet

Connects ManiaAPI.NadeoAPI with GBX.NET features to provide convenient map upload and map update.

Features

  • Upload a map
  • Update a map

Example

A bit more advanced example to show how you can update a map without having to manually specify the map ID:

using ManiaAPI.NadeoAPI;
using ManiaAPI.NadeoAPI.Extensions.Gbx;
using GBX.NET;
using GBX.NET.Engines.Game;

var ns = new NadeoServices();
await ns.AuthorizeAsync("mylogin", "mypassword", AuthorizationMethod.UbisoftAccount);

// Parse the map Gbx header
var mapFileName = "Path/To/Map.Map.Gbx";
var map = Gbx.ParseHeaderNode<CGameCtnChallenge>(mapFileName);

// Get the map info (we need map ID, not map UID)
var mapInfo = await ns.GetMapInfoAsync(map.MapUid);

// Update the map (no leaderboard lost!)
await ns.UpdateMapAsync(mapInfo.MapId, mapFileName);

You can also pass the CGameCtnChallenge instance directly, but it is not recommended as the object is re-serialized and some data might change or corrupt (rarely, but still possible).

This example parses the map twice, which is not optimal. Currently, a method overload that can call GetMapInfoAsync behind the scenes is missing.

ManiaAPI.TrackmaniaAPI

NuGet

Wraps https://api.trackmania.com/doc (Trackmania web API). This API requires authorization.

Features

  • Get display names
  • Get account IDs from display names
  • Get user's map records

More will be added in the future.

Setup

For the list of scopes, see the API docs. Generate your credentials here.

using ManiaAPI.TrackmaniaAPI;

var tm = new TrackmaniaAPI();

await tm.AuthorizeAsync("clientId", "clientSecret", ["clubs", "read_favorite"]);

// Ready to use

For DI, consider using the ManiaAPI.TrackmaniaAPI.Extensions.Hosting package.

ManiaAPI.TrackmaniaAPI.Extensions.Hosting

NuGet

Provides Trackmania OAuth2 authorization for ASP.NET Core applications and an efficient way to inject TrackmaniaAPI into your application.

Setup TrackmaniaAPI injection

TrackmaniaAPI will be available as a transient, with a singleton handling of credentials. This will make sure the HttpClient beneath is handled properly.

Providing options.Credentials is optional, but setting it will automatically authorize on the first request and maintain that connection, so you don't have to call AuthorizeAsync.

using ManiaAPI.TrackmaniaAPI.Extensions.Hosting;

builder.Services.AddTrackmaniaAPI(options =>
{
    options.Credentials = new ManiaPlanetAPICredentials(
        builder.Configuration["Trackmania:ClientId"]!,
        builder.Configuration["Trackmania:ClientSecret"]!);
});

Setup OAuth2

For the list of scopes, see the API docs. Generate your credentials here. The redirect URL is the /signin-trackmania relative to the web root, for example: https://localhost:7864/signin-trackmania.

using ManiaAPI.TrackmaniaAPI.Extensions.Hosting;
using ManiaAPI.TrackmaniaAPI.Extensions.Hosting.Authentication;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
    .AddCookie()
    .AddTrackmania(options =>
    {
        options.ClientId = builder.Configuration["OAuth2:Trackmania:ClientId"]!;
        options.ClientSecret = builder.Configuration["OAuth2:Trackmania:ClientSecret"]!;
        
        options.Scope.Add("clubs");
    });

var app = builder.Build();

app.MapGet("/login", () =>
{
    return TypedResults.Challenge(new() { RedirectUri = "/" }, [TrackmaniaAuthenticationDefaults.AuthenticationScheme]);
});

app.Run();

You can inject TrackmaniaAPI if you create a special HTTP client handler to provide the token from HttpContext.GetTokenAsync("access_token") and use that to get more information from the authorized user. Don't forget to set SaveTokens = true in options - see the sample.

ManiaAPI.ManiaPlanetAPI

NuGet

Wraps https://maniaplanet.com/swagger (ManiaPlanet web API). This API does not require authorization, but you can authorize to have more methods available.

Features

All available on Swagger.

Setup

For the list of scopes, see here at the bottom. Generate your credentials here.

using ManiaAPI.ManiaPlanetAPI;

var mp = new ManiaPlanetAPI();

// You can optionally authorize to do more things, and possibly be less limited
await mp.AuthorizeAsync("clientId", "clientSecret", ["basic", "dedicated", "maps"]);

// Ready to use

For DI, consider using the ManiaAPI.ManiaPlanetAPI.Extensions.Hosting package.

ManiaAPI.ManiaPlanetAPI.Extensions.Hosting

NuGet

Provides ManiaPlanet OAuth2 authorization for ASP.NET Core applications and an efficient way to inject ManiaPlanetAPI into your application.

Setup ManiaPlanetAPI injection

ManiaPlanetAPI will be available as a transient, with a singleton handling of credentials. This will make sure the HttpClient beneath is handled properly.

Providing options.Credentials is optional, but setting it will automatically authorize on the first request and maintain that connection, so you don't have to call AuthorizeAsync.

using ManiaAPI.ManiaPlanetAPI.Extensions.Hosting;

builder.Services.AddManiaPlanetAPI(options =>
{
    options.Credentials = new ManiaPlanetAPICredentials(
        builder.Configuration["ManiaPlanet:ClientId"]!,
        builder.Configuration["ManiaPlanet:ClientSecret"]!);
});

Setup OAuth2

For the list of scopes, see here at the bottom. Generate your credentials here. The redirect URL is the /signin-maniaplanet relative to the web root, for example: https://localhost:7864/signin-maniaplanet.

using ManiaAPI.ManiaPlanetAPI.Extensions.Hosting;
using ManiaAPI.ManiaPlanetAPI.Extensions.Hosting.Authentication;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
    .AddCookie()
    .AddManiaPlanet(options =>
    {
        options.ClientId = builder.Configuration["OAuth2:ManiaPlanet:ClientId"]!;
        options.ClientSecret = builder.Configuration["OAuth2:ManiaPlanet:ClientSecret"]!;

        Array.ForEach(["basic", "dedicated", "titles"], options.Scope.Add);
    });

var app = builder.Build();

app.MapGet("/login", () =>
{
    return TypedResults.Challenge(new() { RedirectUri = "/" }, [ManiaPlanetAuthenticationDefaults.AuthenticationScheme]);
});

app.Run();

You can inject ManiaPlanetAPI if you create a special HTTP client handler to provide the token from HttpContext.GetTokenAsync("access_token") and use that to get more information from the authorized user. Don't forget to set SaveTokens = true in options - see the sample.

ManiaAPI.TrackmaniaIO

NuGet

Wraps the https://trackmania.io/ API which provides services around the Nadeo API.

This API is more moderated and cached, but doesn't require you to authorize with it.

Features

  • Get various campaigns (including weekly shorts)
  • Get leaderboards
  • Get recent world records
  • Get map info
  • Get clubs, including their members and activities
  • Get club rooms
  • Get track of the days
  • Get advertisements
  • Get competitions

Setup

using ManiaAPI.TrackmaniaIO;

var tmio = new TrackmaniaIO("Example from ManiaAPI.NET"); // User agent to comply with https://openplanet.dev/tmio/api

or with DI, using an injected HttpClient:

using ManiaAPI.TrackmaniaIO;

builder.Services.AddHttpClient<TrackmaniaIO>();

ManiaAPI.TrackmaniaWS

NuGet

Wraps https://ws.trackmania.com/ (old TMF web API). This API requires authorization (via constructor).

Features

  • Get player info (registration ID from login for example)

More will be added in the future.

Setup

using ManiaAPI.TrackmaniaWS;

var ws = new TrackmaniaWS("tmf_yourapp", "password");

// Ready to use

For DI, consider using the ManiaAPI.TrackmaniaWS.Extensions.Hosting package.

ManiaAPI.TrackmaniaWS.Extensions.Hosting

NuGet

Provides an efficient way to inject TrackmaniaWS into your application.

Setup

using ManiaAPI.TrackmaniaWS.Extensions.Hosting;

builder.Services.AddTrackmaniaWS(new TrackmaniaWSOptions
{
    Credentials = new("tmf_yourapp", "password")
});

ManiaAPI.TMX

NuGet

Wraps https://tm-exchange.com/ (old TMX).

Features

  • Get replays
  • Search leaderboards
  • Search trackpacks
  • Search tracks
  • Search users
  • Get Gbx URLs and HTTP responses
  • Get image URLs and HTTP responses

Setup

using ManiaAPI.TMX;

// Pick one from TMUF, TMNF, Nations, Sunrise, Original
var tmx = new TMX(TmxSite.TMUF);

or with DI, for a specific site, using an injected HttpClient:

using ManiaAPI.TMX;

builder.Services.AddHttpClient("TMX_TMNF");
builder.Services.AddScoped<TMX>(provider => new TMX(
    provider.GetRequiredService<IHttpClientFactory>().CreateClient("TMX_TMNF"), TmxSite.TMNF));

For advanced DI, consider using the ManiaAPI.TMX.Extensions.Hosting package.

ManiaAPI.TMX.Extensions.Hosting

NuGet

Provides an efficient way to inject all TMX services into your application.

Setup

using ManiaAPI.TMX.Extensions.Hosting;

builder.Services.AddTMX();

Features this setup brings:

  • You can inject ImmutableDictionary<TmxSite, TMX> to get all TMX sites as individual instances
  • If you don't need specific site context, you can inject IEnumerable<TMX> to get all TMX sites
  • Specific TMX can be injected using [FromKeyedServices(TmxSite.TMNF)]

Warning

If you just inject TMX alone, it will give the last-registered one (in this case, Original). If you need a specific site, use [FromKeyedServices(...)].

ManiaAPI.TMX.Extensions.Gbx

NuGet

Connects ManiaAPI.TMX with GBX.NET features.

Features

  • Get track Gbx header
  • Get track Gbx object
  • Get replay Gbx header
  • Get replay Gbx object

Example

using ManiaAPI.TMX;
using ManiaAPI.TMX.Extensions.Gbx;

// Pick one from TMUF, TMNF, Nations, Sunrise, Original
var tmx = new TMX(TmxSite.TMUF);

// Get the track object
var map = await tmx.GetTrackGbxNodeAsync(12345);

Console.WriteLine("Number of blocks: " + map.GetBlocks().Count());

ManiaAPI.Xml

NuGet

Wraps TMF, TMT, and ManiaPlanet XML ingame APIs. Does not relate to the dedicated server XML-RPC.

It currently does not support any authentication for its complexity and security reasons. If some of the leaderboard methods will become secured with authentication though, this will be considered. For authenticated functionality in TMUF, use the TMF.NET library.

For dedicated server XML-RPC, use the GbxRemote.Net library.

Features

For TMUF:

  • Get scores
    • Top 10 leaderboards
    • All records (without identities)
    • Skillpoints
    • Medals
  • Get ladder zone rankings
  • Get ladder player rankings

For ManiaPlanet:

  • Get campaign and map leaderboard from multiple campaigns/maps at once
    • Top 10 leaderboards
    • All records (without identities)
    • Skillpoints
    • Medals
  • Get campaign and map leaderboards
  • Any range of records
  • Skillpoints
  • Medals
  • Get available master servers

For TMT:

  • Get all map records (without identities)
  • Get campaign medal rankings (without identities)
  • Get available master servers

For all games:

  • Get all available zones

Setup for TMUF

using ManiaAPI.Xml;

var masterServer = new MasterServerTMUF();

Setup for ManiaPlanet

First examples assume Maniaplanet relay 2 master server is still running.

using ManiaAPI.Xml;

var masterServer = new MasterServerMP4();

Because the responses can be quite large sometimes, it's recommended to accept compression on the client.

using ManiaAPI.Xml;

var httpClient = new HttpClient(new HttpClientHandler { AutomaticDecompression = DecompressionMethods.GZip })
{
    BaseAddress = new Uri(MasterServerMP4.DefaultAddress)
};
var masterServer = new MasterServerMP4(httpClient);

In case Maniaplanet relay 2 shuts down / errors out, you have to reach out to init server with GetWaitingParams and retrieve an available relay. That's how the game client does it (thanks Mystixor for figuring this out).

To be most inline with the game client, you should validate the master server first with ValidateAsync. Behind the scenes, it first requests GetApplicationConfig, then on catched HTTP exception, it requests GetWaitingParams from the init server and use the available master server instead.

using ManiaAPI.Xml;

var httpClient = new HttpClient(new HttpClientHandler { AutomaticDecompression = DecompressionMethods.GZip })
{
    BaseAddress = new Uri(MasterServerMP4.DefaultAddress)
};
var masterServer = new MasterServerMP4(httpClient);

await masterServer.ValidateAsync(); // Do this for reliability

// The master server is now ready to use

Setup for TMT

TMT handles 3 platforms: PC, XB1, and PS4. Each have their own init server and master server. Nadeo still tends to change these master servers, so it's recommended to first go through the init server.

using ManiaAPI.Xml;

var initServer = new InitServerTMT(Platform.PC);
var waitingParams = await initServer.GetWaitingParamsAsync();

var masterServer = new MasterServerTMT(waitingParams.MasterServers.First());

// You can repeat this exact setup for XB1 and PS4 as well if you want to work with those platforms, with something like Dictionary<Platform, MasterServerTMT> ...

Because the responses can be quite large sometimes, it's recommended to accept compression on the client for the master server. Init server does not return large responses, so it's not necessary for that one.

using ManiaAPI.Xml;

var initServer = new InitServerTMT(Platform.PC);
var waitingParams = await initServer.GetWaitingParamsAsync();

var httpClient = new HttpClient(new HttpClientHandler { AutomaticDecompression = DecompressionMethods.GZip })
{
    BaseAddress = waitingParams.MasterServers.First().GetUri()
};
var masterServer = new MasterServerTMT(httpClient);

// You can repeat this exact setup for XB1 and PS4 as well if you want to work with those platforms, with something like Dictionary<Platform, MasterServerTMT> ...

For a simple setup with multiple platforms, the AggregatedMasterServerTMT is recommended:

using ManiaAPI.Xml;

var waitingParams = Enum.GetValues<Platform>().ToDictionary(
    platform => platform, 
    platform => new InitServerTMT(platform).GetWaitingParamsAsync(cancellationToken));

await Task.WhenAll(waitingParams.Values);

var aggregatedMasterServer = new AggregatedMasterServerTMT(waitingParams.ToDictionary(
    pair => pair.Key,
    pair => new MasterServerTMT(
        new HttpClient(new HttpClientHandler { AutomaticDecompression = DecompressionMethods.GZip })
        {
            BaseAddress = pair.Value.Result.MasterServers.First().GetUri()
        })
    ));

// You can now use aggregatedMasterServer to work with all master servers at once

ManiaAPI.Xml.Extensions.Hosting

NuGet

Provides an efficient way to inject all XML services into your application.

Setup for TMUF

using ManiaAPI.Xml.Extensions.Hosting;

builder.Services.AddMasterServerTMUF();

Setup for ManiaPlanet

Relying on Maniaplanet relay 2 to continue running:

using ManiaAPI.Xml.Extensions.Hosting;

builder.Services.AddMasterServerMP4();

You can now inject MasterServerMP4 (registered as singleton) and use it without additional steps. Compression is enabled.

If you want to be extra sure the correct master server is selected, use this setup:

using ManiaAPI.Xml.Extensions.Hosting;

builder.Services.AddInitServerMP4();
builder.Services.AddMasterServerMP4();

// In a scope, retrieve init server, and use it for validating the master server
// No need for CreateScopeAsync if your service is scoped
await using var scope = provider.CreateScopeAsync();

var initServer = scope.ServiceProvider.GetRequiredService<InitServerMP4>();
var masterServer = scope.ServiceProvider.GetRequiredService<MasterServerMP4>();

await masterServer.ValidateAsync(initServer);

Setup for TMT

using ManiaAPI.Xml.Extensions.Hosting;

// Register the services
builder.Services.AddMasterServerTMT();

// Do the setup
// This should run at the start of your application, or when you need to refresh the master servers
// No need for CreateScopeAsync if your service is scoped
await using var scope = provider.CreateScopeAsync();

foreach (var platform in Enum.GetValues<Platform>())
{
    var initServer = scope.ServiceProvider.GetRequiredKeyedService<InitServerTMT>(platform);
    var waitingParams = await initServer.GetWaitingParamsAsync(cancellationToken);
    var masterServer = scope.ServiceProvider.GetRequiredKeyedService<MasterServerTMT>(platform);
    masterServer.Client.BaseAddress = waitingParams.MasterServers.First().GetUri();
}

Features this last setup brings:

  • You can inject AggregatedMasterServerTMT to conveniently work with all master servers
  • You can inject ImmutableDictionary<Platform, MasterServerTMT> to get all master servers as individual instances
  • If you don't need specific platform context, you can inject IEnumerable<MasterServerTMT> to get all master servers
  • Specific InitServerTMT and MasterServerTMT can be injected using [FromKeyedServices(Platform.PC)]
  • All MasterServerTMT handle compression

Warning

If you just inject MasterServerTMT alone, it will give the last-registered one (in this case, PS4). If you need a specific platform, use [FromKeyedServices(...)].

Build

Note

You don't need to build the solution/repository to use ManiaAPI.NET, NuGet packages have been made for you. This is only for internal development purposes.

Make sure you have these framework SDKs available:

  • .NET 9
  • .NET 8

Visual Studio 2022 should be able to install those with default installation settings. Using Visual Studio 2019 will not work.

In Visual Studio, you can just use Build Solution and everything should build. JetBrains Rider has been tested and also works.

In .NET CLI, run dotnet build on the solution (.sln) level.

Contributing

Contributions are welcome! Please fork the repository and submit a pull request with your changes.

License

ManiaAPI.NET is entirely MIT Licensed.

PLEASE do not use this library to spam the APIs!

Respect the rate limits and cache the responses where possible. Caching is not done internally to give you better control.

If you need to make a lot of requests, do so in a way that doesn't overwhelm the APIs.

About

ManiaAPI.NET is an unofficial collection of .NET web API wrappers connected with Trackmania and ManiaPlanet games.

Topics

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Languages