Changes

Jump to navigation Jump to search
11,055 bytes added ,  21:35, 29 July 2017
Created page with "Maniaplanet 4 and Trackmania Turbo provide '''telemetry''' data via a shared memory interface. ==Interface== The data is written continuously to a non-persisted wikipedia:..."
Maniaplanet 4 and Trackmania Turbo provide '''telemetry''' data via a shared memory interface.

==Interface==

The data is written continuously to a non-persisted [[wikipedia:Memory-mapped_file|memory mapped file]] in virtual memory. External applications have direct access to it. The name of the file mapping object is ''ManiaPlanet_Telemetry''.

The interface is active immediately after the start of the game. If Maniaplanet and Trackmania Turbo are running at the same time (or multiple instances of the same game), it is not possible to determine from which instance the data originates.

It is not known when or how often the data is updated.

An export of the telemetry data by UDP streaming is not available. The data can only be received on the PC on which the game is running.

The following information is provided:
* Game state - Information about the current state of the game
* Race state - Information about the current state of the race
* Object state - State of the vehicle within the virtual world
* Vehicle state - Current information about the vehicle itself
* Device state - Information for virtual chairs

The complete data structure can be taken from the header file maniaplanet_telemetry.h:

<syntaxhighlight lang="c++">#ifndef _MANIAPLANET_TELEMETRY_H
#define _MANIAPLANET_TELEMETRY_H

#pragma once

namespace NManiaPlanet {

enum {
ECurVersion = 2,
};

typedef unsigned int Nat32;
typedef unsigned int Bool;

struct Vec3 {
float x,y,z;
};
struct Quat {
float w,x,y,z;
};

struct STelemetry {
struct SHeader {
char Magic[32]; // "ManiaPlanet_Telemetry"
Nat32 Version;
Nat32 Size; // == sizeof(STelemetry)
};
enum EGameState {
EState_Starting = 0,
EState_Menus,
EState_Running,
EState_Paused,
};
enum ERaceState {
ERaceState_BeforeState = 0,
ERaceState_Running,
ERaceState_Finished,
};
struct SGameState {
EGameState State;
char GameplayVariant[64]; // environment name 'stadium' 'canyon', ....
char MapId[64];
char MapName[256];
char __future__[128];
};
struct SRaceState {
ERaceState State;
Nat32 Time;
Nat32 NbRespawns;
Nat32 NbCheckpoints;
Nat32 CheckpointTimes[125];
char __future__[32];
};
struct SObjectState {
Nat32 Timestamp;
Nat32 DiscontinuityCount; // the number changes everytime the object is moved not continuously (== teleported).
Quat Rotation;
Vec3 Translation; // +x is "left", +y is "up", +z is "front"
Vec3 Velocity; // (world velocity)
Nat32 LatestStableGroundContactTime;
char __future__[32];
};
struct SVehicleState {
Nat32 Timestamp;

float InputSteer;
float InputGasPedal;
Bool InputIsBraking;
Bool InputIsHorn;

float EngineRpm; // 1500 -> 10000
int EngineCurGear;
float EngineTurboRatio; // 1 turbo starting/full .... 0 -> finished
Bool EngineFreeWheeling;

Bool WheelsIsGroundContact[4];
Bool WheelsIsSliping[4];
float WheelsDamperLen[4];
float WheelsDamperRangeMin;
float WheelsDamperRangeMax;

float RumbleIntensity;

Nat32 SpeedMeter; // unsigned km/h
Bool IsInWater;
Bool IsSparkling;
Bool IsLightTrails;
Bool IsLightsOn;
Bool IsFlying; // long time since touching ground.

char __future__[32];
};
struct SDeviceState { // VrChair state.
Vec3 Euler; // yaw, pitch, roll (order: pitch, roll, yaw)
float CenteredYaw; // yaw accumulated + recentered to apply onto the device
float CenteredAltitude; // Altitude accumulated + recentered

char __future__[32];
};

SHeader Header;

Nat32 UpdateNumber;
SGameState Game;
SRaceState Race;
SObjectState Object;
SVehicleState Vehicle;
SDeviceState Device;
};

}

#endif // _MANIAPLANET_TELEMETRY_H</syntaxhighlight>

==Using the data==

Nadeo has provided an [http://files.maniaplanet.com/ManiaPlanet4Beta/test-sharedmem_2016-11-17.zip example program] (including source code) in the closed Maniaplanet 4 Beta forums. The tool displays all of the provided telemetry data items live in a window.

To process the data, we need to know when and how the individual data records are provided. The following C++ source code allows you to create a simple console application that will output some of the telemetry data live:

<syntaxhighlight lang="c++">// maniaplanet_telemetry.cpp : TM² - TrackMania Telemetry Monitor
//
#include <windows.h>
#include <stdio.h>
#include <tchar.h>

#include "maniaplanet_telemetry.h"

bool done = false;

BOOL CtrlHandler(DWORD fdwCtrlType)
{
done = true;
return TRUE;
}

int _tmain(int argc, _TCHAR* argv[])
{
HANDLE hMapFile = NULL;
void* pBufView = NULL;

using namespace NManiaPlanet;
const volatile STelemetry* Shared = NULL;
Nat32 UpdateNumber = 0;

// Set console title and control handler
SetConsoleTitle(TEXT("TM² - TrackMania Telemetry Monitor"));
SetConsoleCtrlHandler((PHANDLER_ROUTINE)CtrlHandler, TRUE);

// Main loop
while (!done)
{
// Get access to the telemetry data
if (Shared == NULL)
{
if (hMapFile == NULL)
hMapFile = OpenFileMapping(FILE_MAP_READ, FALSE, TEXT("ManiaPlanet_Telemetry"));

if (hMapFile != NULL)
{
if (pBufView == NULL)
pBufView = (void*)MapViewOfFile(hMapFile, FILE_MAP_READ, 0, 0, 4096);
}

// Show the wait status in the console title
static bool show_waiting_title = true;
if (show_waiting_title && pBufView == NULL)
{
show_waiting_title = false;
SetConsoleTitle(TEXT("TM² - Waiting for the game..."));
}

Shared = (const STelemetry*)pBufView;
}
else
{
STelemetry S;

for (;;)
{
Nat32 Before = Shared->UpdateNumber;
memcpy(&S, (const STelemetry*)Shared, sizeof(S));
Nat32 After = Shared->UpdateNumber;

if (Before == After)
break;
else
continue; // reading while the game is changing the values.. retry.
}

// Update the console title and output the header
static bool write_header = true;
if (write_header)
{
write_header = false;
SetConsoleTitle(TEXT("TM² - TrackMania Telemetry Monitor"));
puts("UpdateNumber,GameState,GameplayVariant,MapName,MapId,RaceState,RaceTime,"
"NbRespawns,NbCheckpoints,CheckpointTimes,Timestamp,SpeedMeter,InputSteer,InputGasPedal,"
"InputIsBraking,EngineRpm,EngineCurGear,EngineTurboRatio,RumbleIntensity");
}

// Check for updated telemetry data
if (S.UpdateNumber != UpdateNumber)
{
UpdateNumber = S.UpdateNumber;

// Output update number
printf("%u,", S.UpdateNumber);

// Output game data
switch (S.Game.State)
{
case STelemetry::EState_Starting:
printf("Starting,");
break;
case STelemetry::EState_Menus:
printf("Menus");
break;
case STelemetry::EState_Running:
printf("Running");
break;
case STelemetry::EState_Paused:
printf("Paused");
break;
}

printf(",%s,%s,%s,", S.Game.GameplayVariant, S.Game.MapName, S.Game.MapId);

// Output race data
switch (S.Race.State)
{
case STelemetry::ERaceState_BeforeState:
printf("BeforeStart");
break;
case STelemetry::ERaceState_Running:
printf("Running");
break;
case STelemetry::ERaceState_Finished:
printf("Finished");
break;
}

printf(",%d,%u,%u,%u,", S.Race.Time, S.Race.NbRespawns, S.Race.NbCheckpoints,
S.Race.NbCheckpoints == 0 ? 0 : S.Race.CheckpointTimes[S.Race.NbCheckpoints - 1]);

// Output some vehicle data
printf("%u,%u,%f,%f,%s,%f,%d,%f,%f", S.Vehicle.Timestamp, S.Vehicle.SpeedMeter, S.Vehicle.InputSteer,
S.Vehicle.InputGasPedal, S.Vehicle.InputIsBraking ? "True" : "False", S.Vehicle.EngineRpm,
S.Vehicle.EngineCurGear, S.Vehicle.EngineTurboRatio, S.Vehicle.RumbleIntensity);

printf("\n");
}
}

// Suspend the busy wait loop
Sleep(5);
}

// Cleanup
if (pBufView)
UnmapViewOfFile(pBufView);
if (hMapFile)
CloseHandle(hMapFile);

return 0;
}</syntaxhighlight>

''UpdateNumer'' is used to synchronize the data between the game and the receiver. The variable is incremented once before the values are changed and once thereafter.

For timing information, the object state and vehicle state structures each contain a ''Timestamp'' variable. The resolution of the included time is 10 milliseconds.

A few notes about the race data:
* A new race starts when the race state changes from ''BeforeState'' to ''Running''.
* A race ends when the race state changes from ''Running'' to ''Finished'' or ''BeforeState''. In order to distinguish between finish and restart, it's necessary to check whether the checkpoint count has increased.
* It is not guaranteed that the checkpoint time has been updated at the same time as the checkpoint number is raised.
* There is no a lap counter. In a multi-lap race, you can not detect if a lap has been completed.
* The provided telemetry data records are not cleared after a race ends.

==Hardware and software that use the telemetry interface==

* [http://www.d-box.com/download/trackmania-turbo/ D-BOX Technologies Inc. motion-cueing systems]
* [[Telemetry_Monitor|TrackMania Telemetry Monitor]]

[[Category:Specifications]]

Navigation menu