ExtraLeaderboardAPI is a Java/JEE-based application programming interface (API) that allows developers to access and retrieve information about map leaderboards in the TrackMania Next game.
ExtraLeaderboardAPI is designed to be called by an Openplanet plugin inside the game, and it uses the Nadeo API to retrieve leaderboard data.
You will need Java 17 to run the API.
This API uses Maven to manage dependencies. To install the API, simply clone the repository and run mvn install
in the root directory.
It was deployed on a JBoss/Wildfly server.
The following properties are required :
- ubisoft.email : the email address used to log in to the Ubisoft account
- ubisoft.password : the password used to log in to the Ubisoft account
When deployed (for example locally), the API can be accessed at http://localhost:8080/ELP
.
When using GitHub, the war file generated by a push on master
is automatically deployed on a AWS EC2 instance.
All the endpoints take a mapId as a URL parameter, which is the ID of the map in which we want to get scores, leaderboards etc.
Endpoints return info in the form of UserResponse
objects, a UserResponse
mainly contains:
- A list of
LeaderboardPosition
objects (aLeaderboardPosition
quantifies a time and rank, and a players Account ID). - One
MapInfo
object (aMapInfo
contains basic information regarding a map). - A map<String,Object> containing metadata about the map, for now it is only the player count of the map.
Here is a typical UserResponse object Generated by the url:
/api/leaderboard/map/JADzePlJElXk6wLX3z5Fksf6wL3/records?score=42000,42500,43000&medal=1,2,3,4&position=10,100,200&getplayercount=true&getmapinfo=true
{
"positions": [
{
"time": 65000,
"rank": 5316,
"accountId": "8ff2fad2-059d-4a9a-99d3-93861e2e8f89"
},
{
"time": 52000,
"rank": 4759,
"accountId": "8ff2fad2-059d-4a9a-99d3-93861e2e8f89"
},
{
"time": 46000,
"rank": 3232,
"accountId": "8ff2fad2-059d-4a9a-99d3-93861e2e8f89"
},
{
"time": 42908,
"rank": 338,
"accountId": "8ff2fad2-059d-4a9a-99d3-93861e2e8f89"
},
{
"time": 43000,
"rank": 376,
"accountId": "8ff2fad2-059d-4a9a-99d3-93861e2e8f89"
},
{
"time": 43500,
"rank": 809,
"accountId": "8ff2fad2-059d-4a9a-99d3-93861e2e8f89"
},
{
"time": 44000,
"rank": 1310,
"accountId": "8ff2fad2-059d-4a9a-99d3-93861e2e8f89"
},
{
"time": 42095,
"rank": 10,
"accountId": "9219cc64-63ec-4cfe-8890-a4239093e71c"
},
{
"time": 42550,
"rank": 100,
"accountId": "dbe9698f-68ce-4792-ab6f-3262ddcf9c75"
},
{
"time": 42747,
"rank": 200,
"accountId": "b59bc880-ef99-4a3b-9865-213117b2734d"
}
],
"meta": {
"playerCount": 5625
},
"mapInfo": {
"uid": "QqCyGzZKOCU2duwiEEgCeZ7Ivj7",
"name": "$s$09FDeform$FFFative$09F|Ξ",
"author": "70d991d1-434e-4e69-80df-f6e9c5ab6ea7",
"nbLaps": 0,
"submitter": "70d991d1-434e-4e69-80df-f6e9c5ab6ea7",
"authorTime": 42908,
"goldTime": 46000,
"silverTime": 52000,
"bronzeTime": 65000
}
}
- None
- UserResponse containing information relative to the map
- None
- UserResponse containing information about the medals of the map
The returned UserResponse contains all theoretical positions and times corresponding to the medals of the map, in the form of a MapInfo object.
- None
- UserResponse containing information on the theoretical time and position of the author medal of the map.
- None
- UserResponse containing information on the theoretical time and position of the gold medal of the map.
- None
- UserResponse containing information on the theoretical time and position of the silver medal of the map.
- None
- UserResponse containing information on the theoretical time and position of the bronze medal of the map.
- None
- UserResponse containing the amount of players that have a time on the map.
- pos: the position in the map leaderboard from which to get the time
- UserResponse containing the time of the given position.
- time: the time from which to get a leaderboard position
- UserResponse containing the position of the given time on the leaderboard.
- score: list of the time scores on the map to get the positions for.
- player: list of players to get the time scores and positions of.
- medal: list of medals to get the theoretical time scores and positions of.
- position: list of positions to get the time scores of.
- getplayercount: whether to return the amount of players that have a time on the map.
- getmapinfo: whether to return general info about the map (the corresponding mapInfo object).
- isStunt : whether the map uses the stunt gamemode.
- UserResponse containing information corresponding to the results of all queries.
- Add better logging
- Add telemetry
- Generate Swagger documentation
- Add more information in the leaderboardposition in the response (like what request does this position refers)
- Better error handling to return more information to the user
- Optimize requests to the Nadeo API (e.g. if we want top 1,2,5 for example, we can do only one request to the Nadeo API with a length of 5 and return the top 1,2,5)
Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change.
You can send a mail to [email protected]
if you have any questions or suggestions. You may also open an issue on GitHub.
Here is some explanation about how the API works.
When a request is made to the API, it will arrive at a resource class. this function will then do the bare minimum to handle the input data, before calling the business logic class. The business logic class will then do the actual work, and return the result to the resource class. The resource class will then return the result to the user.
The business logic classes all have the same structure. They always prepare the input data and transform it into one or multiple Request
.
After that, it will create a MainHandler
object, and call the method, giving it the requests.
This MainHandler
object will then create a Payload to contain all necessary information, and give that to a sequence of handler. There are currently 2 handlers:
- The
RequestHandler
: this handler will take the requests and send them to the Nadeo API, by using various classes. It will then store the result in the payload. - The
ResponseHandler
: this handler will take the result from the payload and transform it into a smaller response object that only contains the necessary data for us.
After that, the main handler will return a list of response objects to the business logic class, which will then return either use it to launch a new batch of request, or will create a UserResponse
object to give back to the resource class.
There is also a system working in parallel of all of this. It will handle everything related to tokens. Nadeo Require a token to access the API, and it is valid for around one hour. This system will check if the token is still valid, and if not, it will request a new one or refresh the old one.
This works thanks to a TimerTask
which will automatically wait 55 min before refreshing tokens.
Currently, the needed tokens are requested at the start of the application.