Echo VR API Documentation
Unofficial documentation for Echo VR's HTTP API.
Summary
Echo Arena has an HTTP API available for querying current game state. This API
listens locally on port 6721 (http://127.0.0.1:6721/session
). This API is always
on and does not require any options to enable it.
Note that if any other service is alredy bound to this (TCP) port, which often
happens on Windows, Echo will not be able to bind to it. To kill any services
using it, run net stop HTTP
in an administrator command prompt.
This repository aims to document all the functionality of this API.
API Endpoints
GET /session
This returns a detailed representation of the current state of the match. The response is a JSON string, which can be parsed with any standard JSON parser.
Example response (formatted for readability):
{ "client_name": "ajedi32", "sessionid": "0BD7D136-E487-11E8-9F32-F2801F1B9FD1", "match_type": "Echo_Arena_Private", "map_name": "mpl_arena_a", "private_match": true, "tournament_match": false, "game_clock_display": "00:45.65", "game_clock": 45.659531, "game_status": "playing", "possession": [1, 0], "blue_points": 9, "orange_points": 5, "orange_team_restart_request": 0, "blue_team_restart_request": 0, "sessionip": "204.74.226.94", "player": { "vr_left": [1, 0, 0], "vr_position": [0, 0, 0], "vr_forward": [0, 0, 1], "vr_up": [0, 1, 0] }, "disc": { "position": [0, 0, 0], "forward": [0, 0, 1], "left": [1, 0, 0], "up": [0, 1, 0], "velocity": [0, 0, 0], "bounce_count": 0 }, // TODO: Make this consistent with the other stats in the example. "last_score": { "disc_speed": 0.0, "team": "blue", "goal_type": "[NO GOAL]", "point_amount": 0, "distance_thrown": 0.0, "person_scored": "[INVALID]", "assist_scored": "[INVALID]" }, "teams": [ { "team": "BLUE TEAM", "possession": false, "stats": { "points": 9, "possession_time": 132.18958, "interceptions": 0, "blocks": 0, "steals": 0, "catches": 0, "passes": 0, "saves": 2, "goals": 0, "stuns": 29, "assists": 2, "shots_taken": 7 }, "players": [ { "name": "Bob", "playerid": 0, "userid": 9221405949665979, "number": 88, "level": 16, "stunned": false, "ping": 75, "invulnerable": false, "possession": false, "blocking": false, "head": { "position": [1.9080001, -0.80900002, -7.9890003], "forward": [-0.34600002, -0.41700003, -0.84100002], "left": [-0.93600005, 0.21200001, 0.28], "up": [0.061000004, 0.88400006, -0.46300003] }, "body": { "position": [1.9080001, -0.80900002, -7.9890003], "forward": [-0.208, 0.36600003, -0.90700006], "left": [-0.91400003, 0.257, 0.31400001], "up": [0.34800002, 0.89400005, 0.28100002] }, "velocity": [0, 0, 0], "lhand": { "pos": [-2.7710001, 2.2950001, -6.4300003], "forward": [-0.61800003, 0.60500002, -0.50200003], "left": [0.147, 0.71600002, 0.68300003], "up": [0.77200001, 0.34800002, -0.53100002] }, "rhand": { "pos": [0.21600001, -2.3150001, 78.168007], "forward": [-0.69100004, 0.112, -0.71400005 ], "left": [-0.574, -0.68500006, 0.44800001], "up": [-0.43900001, 0.72000003, 0.53800005] }, "stats": { "points": 5, "possession_time": 78.645569, "interceptions": 0, "blocks": 0, "steals": 0, "catches": 0, "passes": 0, "saves": 1, "goals": 0, "stuns": 14, "assists": 1, "shots_taken": 5 } } /* ...other blue players here */ ] }, { "team": "ORANGE TEAM", "possession": true, "stats": { "points": 5, "possession_time": 80.32605, "interceptions": 0, "blocks": 0, "steals": 1, "catches": 0, "passes": 0, "saves": 2, "goals": 0, "stuns": 12, "assists": 1, "shots_taken": 5 }, "players": [ /* ...orange players here; see blue players section for example */ ] }, { "team": "SPECTATORS", "possession": false, "stats": { "points": 0, "possession_time": 0.0, "interceptions": 0, "blocks": 0, "steals": 0, "catches": 0, "passes": 0, "saves": 0, "goals": 0, "stuns": 0, "assists": 0, "shots_taken": 0 }, "players": [ /* ...spectators here; see blue players section for example */ ] } ] }
Properties
The response is a JSON object, with the following properties:
client_name
The username of the currently signed-in user.
sessionid
A 128-bit string-encoded GUID.
match_type
Represents the type of match being played.
Possible values:
"Echo_Arena_Private"
"Echo_Arena"
"Social_2.0"
"INVALID GAMETYPE"
- TODO: What else?
map_name
Represents the current "map" (environment) the user is playing in.
Possible values:
"mpl_arena_a"
- Standard Echo Arena map"mpl_lobby_b2"
- Lobby"INVALID LEVEL"
- TODO: What else?
private_match
Whether the current session is a private match.
tournament_match
Whether the current session is being used for an official tournament orchestrated in collaboration with the Echo Arena developers. This is for possible future integration with ESL and other organized tournaments.
game_clock_display
A human-readable representation of the current game clock time.
game_clock
The current game clock time, in seconds.
game_status
The current game's status.
Possible values:
"pre_match"
"round_start"
"playing"
"score"
"round_over"
"round_start"
"post_match"
"pre_sudden_death"
"sudden_death"
"post_sudden_death"
possession
An array of two integers representing which team currently possesses the disk.
TODO: Unclear exactly how this data is encoded.
blue_points
The current score of the blue team. This differs from teams[].stats.points
in that it includes points scored as self goals.
orange_points
The current score of the orange team. This differs from teams[].stats.points
in that it includes points scored as self goals.
orange_team_restart_request
True
when the orange team has a restart request pending.
blue_team_restart_request
True
when the blue team has a restart request pending.
sessionip
The IP address of the current game server.
player
An object representing the current state of the local VR player. This is used for positions of the player within their playspace.
player.vr_left
The direction that the left side of the player's head is facing within their playspace.
player.vr_position
An array representing the player's position within their playspace.
player.vr_forward
The direction that the player's head is facing within their playspace.
player.vr_up
The direction that the top side of the player's head is facing within their playspace.
disc
An object representing the current state of the disk.
disc.position
An array representing the disk's position within the arena.
disc.forward
The direction that the disc is facing.
disc.left
The direction that the left side of the disc is facing.
disc.up
The direction that the top of the disc is facing.
disc.velocity
An array representing the disk's velocity.
disc.bounce_count
The number of times the disk has bounced. (TODO: Since the last time someone grabbed it? Do headbutts count as bounces?)
last_score
An object containing facts and statistics related to the last goal that that was scored in-game. (This is roughly the same information displayed on the Shield after a goal.)
Note that in some cases (such as when the disk is slapped into the goal) bugs may result in this information being inaccurate.
last_score.disc_speed
The speed of the disk in meters/second when it impacted the goal. This is 0
by default when no goal has been scored.
last_score.team
The team that scored. This is "blue"
by default when no goal has been scored. Note that in the case of self goals, this value will still represent the team receiving points for the goal, not the team of the player who actually scored the goal. (TODO: This is probably accurate, but check to make sure.)
Possible values:
"blue"
"orange"
last_score.goal_type
A human-readable explanation of the type of goal scored. This is "[NO GOAL]"
by default when no goal has been scored.
Possible values:
"[NO GOAL]"
"SLAM DUNK"
"INSIDE SHOT"
"LONG SHOT"
"BOUNCE SHOT"
"LONG BOUNCE SHOT"
last_score.point_amount
The number of points scored (2 or 3). This is 0
by default when no goal has been scored.
last_score.distance_thrown
The distance the goal was scored from. This is 0
by default when no goal has been scored.
last_score.person_scored
The username of the player who scored the goal. This is "[INVALID]"
by default when no goal has been scored since you first joined the match.
last_score.assist_scored
The username of the player who assisted the goal. This is "[INVALID]"
by default when no goal has been scored since you first joined the match, or when a goal was scored, but no player was credited with the assist.
teams
An array of objects containing data used to instantiate the game's two teams. The first element in the array is always the blue team, while the second is always the orange team.
teams[].team
A human-readable team name. Usually either "ORANGE TEAM" or "BLUE TEAM", but if all the players on a team have the same team name (set by pressing F11 while in a match or the lobby) it will be that instead.
teams[].possession
Indicates whether this team currently has possession of the disk.
teams[].stats
An object containing data used to instantiate the team's current stats.
teams[].stats.possession_time
Time in seconds that the subject possessed the disk.
teams[].stats.points
Points scored by the subject.
teams[].stats.assists
Number of goals assisted by the subject.
teams[].stats.saves
Number of opposing team goals prevented by the subject.
teams[].stats.stuns
Number of times the subject has stunned the opposing team.
teams[].stats.goals
Number of goals scored by the subject.
API always returns zero for teams
teams[].stats.passes
Number of times the subject successfully completed a pass
API always returns zero for teams
teams[].stats.catches
Number of times the subject successfully caught a pass by a team member
teams[].stats.steals
Number of times the subject stole the disk from the opposing team
teams[].stats.blocks
Number of times the subject blocked a punch
API always returns zero for teams
teams[].stats.interceptions
Number of times the subject intercepted a pass by the opposing team
API always returns zero for teams
teams[].stats.shots_taken
Number of times the subject attempted a shot on goal
teams[].players
An array of objects containing data used to instantiate the team's players.
teams[].players[].name
The username of the player.
teams[].players[].playerid
A number representing ID of the player within the current game session.
teams[].players[].userid
A unique number identifying the player across all game sessions.
teams[].players[].level
A number (1-50) representing the player's experience "level". New accounts start as level 1, and will usually reach level 50 after a few hundred games in public matchmaking.
Note that there a rare bug where this number may be 0 in the UI in some cases; it's possible this bug may also affect the API (though this has yet to be verified).
teams[].players[].number
The number a player chose for themselves in the customization room.
teams[].players[].possession
Indicates whether this player currently has possession of the disk.
teams[].players[].stunned
Whether the player is currently stunned.
teams[].players[].ping
Current ping (network latency to server) of this player.
teams[].players[].blocking
Whether the player is currently blocking (and will therefore deflect stuns).
teams[].players[].invulnerable
Whether or not the player is currently immune to stuns. Players will be in this state for 3 seconds after they are stunned.
teams[].players[].velocity
The current velocity (speed and direction of movement) of the player.
teams[].players[].lhand
An object containing position and rotation data for the left hand.
teams[].players[].lhand.pos
The position of the player's left hand within the arena.
teams[].players[].lhand.forward
The direction that the player's left hand is facing.
teams[].players[].lhand.left
The direction that the left side of the player's left hand is facing.
teams[].players[].lhand.up
The direction that the top side of the player's left hand is facing.
teams[].players[].rhand
An object containing position and rotation data for the right hand.
teams[].players[].rhand.pos
The position of the player's right hand within the arena.
teams[].players[].rhand.forward
The direction that the player's right hand is facing.
teams[].players[].rhand.left
The direction that the left side of the player's right hand is facing.
teams[].players[].rhand.up
The direction that the top side of the player's right hand is facing.
teams[].players[].head
An object containing position and rotation of the head of the player
teams[].players[].head.position
The position of the player's head in the arena.
teams[].players[].head.forward
The direction that the player's head is facing.
teams[].players[].head.left
The direction that the left side of the player's head is facing.
teams[].players[].head.up
The direction that the top side of the player's head is facing.
teams[].players[].body
An object containing position and rotation of the body of the player
teams[].players[].body.position
The position of the player's body in the arena.
teams[].players[].body.forward
The direction that the player's body is facing.
teams[].players[].body.left
The direction that the left side of the player's body is facing.
teams[].players[].body.up
The direction that the top side of the player's body is facing.
teams[].players[].stats
An object containing data used to instantiate the player's current stats. See teams[].stats
for a list of available stats.
Concepts
Throughout the API there are a number of concepts that get reused in multiple places. These concepts are documented in this section.
Vectors
Position, direction, and velocity are represented within the API as an array of 3D vector coordinates in Cartesian space. That's a fancy way of saying the array contains three numbers, each representing a distance/speed in either the left-right (x
), up-down (y
), or forward-back (z
) directions. These directions are arranged as [x, y, z]
in the arrays returned by the API.
Distance is measured in meters, and speed in meters per second. So, for example, a vector coordinate [0, 1, 0]
could represent either a distance of 1 meter in the "up" direction, or a speed of 1 meter/second in the "up" direction.
For vectors that contain a mix of several directions, you can calculate the total distance or speed (r) using a 3-dimensional version of the Pythagorean theorem: r2 = x2 + y2 + z2
In Echo Arena, distances are measured from the center of the Arena, where the disk spawns (at [0, 0, 0]
). Positive z
is in the direction of the orange side of the arena, negative z
is in the direction of the blue side of the arena. If you're on the blue side of the arena facing the orange team's goal, positive x
would be towards your left, and negative x
would be to your right (with left/right reversed for a player on the orange team's side of the arena facing the blue team's side). Positive y
is "up" (relative to a player's orientation when they spawn) and negative y
is "down".
So, for example, a player located at [10.0, -5.0, -15.0] would be, from the perspective of someone sitting on the blue team's goal facing the orange team's goal, 10 meters to the left of the center of the arena, on the blue team's side, near the floor.
The Arena is 80m long (counting from orange to blue launch tube exits), 30m wide (counting from the widest point of the side walls) and 20m tall (counting from the tallest part of the arena, in the trenches).
Possession
The API defines "possession" a little more broadly than you might expect (depending on what other sports you may be familiar with that use this term). Not only do players/teams that are currently holding the disk have possession, but teams also maintain possession for 7 seconds after releasing the disk as well, unless the disk is recovered by the opposing team. If the disk is glowing with the color of a specific team, the game considers that team as having "possession".
Session
A "session" is what users typically think of as the "server" you're playing on. When you join a new match, a new session is created, and the session will remain active until all players leave. Sessions IDs are unique, and have no correspondence to the actual, physical or virtual server hardware that's hosting the game.