Peek Into Halo Infinite Playlist Weights - With The Halo Infinite API
Table of Contents
Introduction #
If you’ve played Halo Infinite for some time, you might’ve noticed that every game selection from the main menu is actually a playlist - a combination of different match modes that you can play with ever-so-slightly different configurations and maps.
My personal favorite playlist is Husky Raid - and honestly, why wouldn’t you jump into Husky Raid, the only game mode where you can easily hit an Overkill and Extermination combo with the Skewer?
So, each playlist can have different combinations of maps and game modes, collectively known as map-mode pairs. Given that there are different combinations within the same playlist, you might also have noticed that certain game modes and maps do occur a bit more frequently in a given playlist than others. That is controlled by weights - values that determine how likely a map-mode pair will be picked when you press Play.
But before we get into the weights, let’s talk a bit about the overall play structure. It can be defined as such, where the game can have one or more playlist, which in turn encompasses several map-mode pairs that represent a combination of game mode and a map:
There are, of course, more than two playlists in the game, and then the chart would become even messier if you consider that every asset also has a version. The example above is purely illustrative and oversimplifies the breakdown.
Hey, in the example above Map-Mode Pair C belongs to both example playlists, and there is a mix of maps and modes crossing over many times. Is that accurate? How can that be true?
Indeed, that is correct. The same game mode and map combination can belong to more than one playlist. Every map can be used in many map-mode pairs, and every mode can, just like the maps, belong to more than one combo. To demonstrate this, let’s make our example less hypothetical and look at the current configuration, up-to-date as of build 6.10025.11703.0.
Where do playlists come from #
I’ll start off by mentioning that if you’ve used Fiddler to inspect the traffic from Halo Infinite, you likely noticed that the game does request data for each playlist when launched without the data already cached:
The problem is that there is seemingly not a pre-emptive call to get the list of playlists. So, where exactly does the game get the list of available playlists, especially since a few of them rotate weekly and we do not get a new build update weekly? The answer lies in a secondary protocol that is used by Halo Infinite that carries some of this information - Advanced Message Queuing Protocol (AMQP).
When the game starts, a connection is established to lobby-hi.svc.halowaypoint.com
and some application/x-bond-compact-binary
(i.e., Bond) data is being exchanged before the fireteam is established over a long-running WebSocket connection. I was actually thankful when I saw that it was WebSockets because WireShark was oddly silent when I tried to filter for AMQP traffic, but Fiddler was more than happy to help me intercept the binary material that was exchanged. After some trial and error with the help of my homebrew Bond Reader utility, trying every binary blob for Bond contents, I managed to extract some nuggets that seemed oddly familiar (the offset for this blob was a whopping 57 bytes that I needed to skip):
█░░░░░░░░░░░░░░░░░░░░░░░░░ STR ░░░░░░░░░░░░░░░░░░░░░░░░░█
Data type: BT_UINT32 Field ID: 0
1200999239
Data type: BT_UINT16 Field ID: 1
23346
Data type: BT_UINT16 Field ID: 2
19591
Data type: BT_UINT64 Field ID: 3
3587842982486911896
Data type: BT_STOP Field ID: 0
█░░░░░░░░░░░░░░░░░░░░░░░░░ EST ░░░░░░░░░░░░░░░░░░░░░░░░░█
Or, if you really want a quick-and-dirty check, see if you can pass these numbers through this C# snippet:
uint a = 1200999239;
ushort b = 23346;
ushort c = 19591;
byte[] d = BitConverter.GetBytes(3587842982486911896);
Console.WriteLine(new Guid(a, b, c, d[0], d[1], d[2], d[3], d[4], d[5], d[6], d[7]));
The result of that was 4795cb47-5b32-4c87-98ab-02f12e94ca31
- an asset GUID that identified one of the playlists that you saw in the request screenshot above. Bingo - we now know that the list of playlists comes through the AMQP pipe.
Mapping out existing playlists #
When the game boots for the first time, and if there are no cached playlists metadata entries already, it will request each playlist separately. In the latest build, there are 16 requests in the format:
https://discovery-infiniteugc.svc.halowaypoint.com
/hi
/playlists
/{ASSET_ID}
/versions
/{VERSION_ID}
?clearanceId={FLIGHT_ID}
A request to this endpoint will yield a very long JSON response that we will dissect in a bit.
If you look at the earlier video, you will notice that there are quite a few options for a player to pick from when they want to play in Multiplayer mode. Mapping back to the 16 requests I mentioned earlier, there are currently 16 active playlists:
Playlist Name | Asset ID | Version ID |
---|---|---|
Infection | 00cd3ab8-4b24-4181-8493-7aee34751f52 |
6ec76c9b-5134-4444-8e6a-b736413d0af3 |
Lone Wolves | d22aa90d-3091-4214-a85e-c968037cef2f |
b5439adc-6100-44a3-bc37-012d618e8c9f |
Squad Battle | 52392a40-5a75-4205-abc6-b51cdc84918c |
dc1a0dde-24cf-4e26-a94f-0a5d76854959 |
Husky Raid | da024c44-7c2a-49bb-a6ff-8d91ac179900 |
19bfb62e-76dd-46bf-ab6e-180e69b8873c |
Team Slayer | aa41f6a9-51be-4f25-a53f-48192ce14de7 |
a5e4c224-89cb-49f8-88e0-b2f04e74b59f |
Super Fiesta | 4829f027-a9af-4b2f-86dd-7b290d6bb0a4 |
9bd2d072-e579-4b54-b603-d4801111ce53 |
Ranked Slayer | dcb2e24e-05fb-4390-8076-32a0cdb4326e |
d4165aad-2cc0-4130-a93a-4742f6606c0b |
Quick Play | bdceefb3-1c52-4848-a6b7-d49acd13109d |
01949da1-ae38-460a-a27c-e95aac0db9b6 |
Big Team Battle | dc4929de-216c-43bc-b207-1702253f4576 |
c487b0af-5b4a-4576-8ae7-34ff9773a20f |
Tactical Slayer | 70bb9184-e674-4307-8846-239ab4a30cb6 |
e2d74d94-9cec-4286-b4d8-ded9ccc8d858 |
Extraction 24/7 | 4795cb47-5b32-4c87-98ab-02f12e94ca31 |
58a0c3d9-d906-4c07-bc48-af757c0fe580 |
Team Doubles | 73b48e1e-05c4-4004-927d-965549b28396 |
17b616fb-f128-46c9-b966-7850b38445f9 |
Ranked Arena | edfef3ac-9cbe-4fa2-b949-8f29deafd483 |
5dfe7c2b-8d15-4049-933e-eb9c0fa113a6 |
Social Slayer | f336c231-e55c-46c9-af11-d9acf1b3245d |
0e498c69-56a9-43cd-b8af-a73d9f14d016 |
WORKSHOP BTB INFECTION | 7071b932-18c1-4f9b-b80e-266aec1d6770 |
f5dd07b9-a22e-4ccc-a9a1-a489a0d1269f |
Bot Bootcamp | a446725e-b281-414c-a21e-31b8700e95a1 |
b108af37-38b3-45f4-af18-9e1f59f930b3 |
Now that we have actual data, let’s re-build the graphic that shows playlist association with map-mode pairs. To start, I am looking at the breakdown of game modes and the associated map-mode pairs, which is already producing a massive graph.
Associations between playlist and map-mode pairs #
There is a limited number of playlists, but all of them have quite a few map-mode pairs associated with them. In the current configuration, there is no map-mode pair overlap.
Because the graph is big, you can skip right to the next section.
Associations between map-mode pairs and maps #
What if we connected out map-mode pairs to maps now? Let’s try this with a slightly different pivot, because fitting all of the data in a single chart will require that chart to be the size of Times Square, and the arrows will blend in. There are less maps than map-mode pairs - one map can be included in many different game modes.
As an aside, looks like Launch Site has lost its initial appeal - you can only get it in Fiesta and Infection. And speaking of Launch Site, an eagle-eyed engineer spotted that Event:Infection on Launch Site
is mapped to Bazaar
. This is not a bug in the chart. The map-mode pair is actually called that despite the fact that MapLink
points to Bazaar. This is very likely just a small issue with the configuration on the game content management system (CMS) side.
To learn more about how game modes snap to individual map-mode pairs, you can skip to the next section.
Associations between map-mode pairs and game variants #
Lastly, let’s take a look at how individual game modes are associated with map-mode pairs. I don’t think the breakdown will come as a surprise to anyone who’s been playing Halo Infinite in more than one game mode.
Skip to the next section to learn about exact map-mode pair weights.
The weights #
Above, we looked at how playlists are associated with map-mode pairs, which in turn represent a combination of a map and game mode. But not every combination is made equal within a playlist, and the first clue to that is given to us if we look inside the JSON response when obtaining playlist metadata (all within CustomData\PlaylistEntries
). Let’s use Infection as an example:
"PlaylistEntries": [
{
"MapModePairAssetId": "b347c8c1-be08-4fc8-8d76-61cccde62be3",
"Metadata": {
"Weight": 60.0
}
},
{
"MapModePairAssetId": "e3777308-c0cc-4e4d-bbcd-dfe7d026c7e1",
"Metadata": {
"Weight": 60.0
}
},
{
"MapModePairAssetId": "38c98e94-2e3e-4f5b-8801-770b6935f849",
"Metadata": {
"Weight": 60.0
}
},
{
"MapModePairAssetId": "4cafa572-74cd-4333-9629-b9c1915bccfd",
"Metadata": {
"Weight": 60.0
}
},
{
"MapModePairAssetId": "8b91c712-989a-4e1e-9609-7afbb11f0dbd",
"Metadata": {
"Weight": 60.0
}
},
{
"MapModePairAssetId": "482f7c56-0d18-4b72-b736-5521bc3ba191",
"Metadata": {
"Weight": 60.0
}
},
{
"MapModePairAssetId": "17a3fe3d-3ff0-4238-bf3c-05012e421ae7",
"Metadata": {
"Weight": 60.0
}
},
{
"MapModePairAssetId": "26b0efcd-c113-411b-ab1b-b1fd8bf91299",
"Metadata": {
"Weight": 60.0
}
},
{
"MapModePairAssetId": "10eb5282-c451-48dc-be8e-6e96393f5788",
"Metadata": {
"Weight": 145.0
}
},
{
"MapModePairAssetId": "ca1b98fa-2dd1-4e8a-a8a6-fea4d14455a6",
"Metadata": {
"Weight": 145.0
}
},
{
"MapModePairAssetId": "e2ec56af-44b0-4e31-a6c9-090762dfcfb3",
"Metadata": {
"Weight": 260.0
}
},
{
"MapModePairAssetId": "4729a201-9942-4835-bb92-59bfce8a5a58",
"Metadata": {
"Weight": 260.0
}
},
{
"MapModePairAssetId": "4c93ef81-342e-4071-8744-044311721df9",
"Metadata": {
"Weight": 145.0
}
}
]
Or, if we look at that in a slightly more readable format:
Name | Asset ID | Asset Version | Weight |
---|---|---|---|
Event:Infection on Launch Site | e3777308-c0cc-4e4d-bbcd-dfe7d026c7e1 |
37db76e4-eb41-4722-9f17-f965de8903f2 |
60 |
Event:Infection on Aquarius | b347c8c1-be08-4fc8-8d76-61cccde62be3 |
c95cc9d5-b120-4f41-b8a5-cbfc8d4fb012 |
60 |
Event:Infection on Cliffhanger | 8b91c712-989a-4e1e-9609-7afbb11f0dbd |
184f9001-6bb2-4900-a177-cf0a033a7c23 |
60 |
Event:Infection on Forest | 482f7c56-0d18-4b72-b736-5521bc3ba191 |
9e6cba33-b7b3-447d-9123-ed3578e1c4d2 |
60 |
Arena:Infection on Launch Site | 10eb5282-c451-48dc-be8e-6e96393f5788 |
90f0f63f-e758-4a44-8327-60b8a1f2b435 |
145 |
Arena:Infection on Prism | 4729a201-9942-4835-bb92-59bfce8a5a58 |
4336e873-abbf-4df9-bdd0-e36df8e6a9ec |
260 |
Event:Infection on Recharge | 17a3fe3d-3ff0-4238-bf3c-05012e421ae7 |
35e58535-22a2-48c1-9201-a84f1edb11d3 |
60 |
Event:Infection on Streets | 26b0efcd-c113-411b-ab1b-b1fd8bf91299 |
2877f4ad-487c-4cc4-8036-85ecc1aa9ab2 |
60 |
Arena:Infection on Live Fire | ca1b98fa-2dd1-4e8a-a8a6-fea4d14455a6 |
30dcf5d7-a9fc-4f32-b49a-ecd5339a6604 |
145 |
Event:Infection on Chasm | 4cafa572-74cd-4333-9629-b9c1915bccfd |
4533f06c-6071-439c-857d-db7ea890602a |
60 |
Arena:Infection on Catalyst | 4c93ef81-342e-4071-8744-044311721df9 |
bd7c6e7a-93dd-418c-9708-0bcf7a0b7582 |
145 |
Arena:Infection on Forbidden | e2ec56af-44b0-4e31-a6c9-090762dfcfb3 |
86eec4a9-34b4-482d-b663-7bd930cb8464 |
260 |
Event:Infection on Behemoth | 38c98e94-2e3e-4f5b-8801-770b6935f849 |
fd4969e2-ce21-4b1f-a582-dcce4aead780 |
60 |
If you are playing Infection, you are much more likely to play on Forbidden and Prism (the new maps introduced in Season 5), followed by Catalyst, Live Fire, and Launch Site. Then there’s all the other maps.
So, looking at the weights, it doesn't seem like they are at all representative of percentages, are they? These are just arbitrary values within the playlist to represent the relative weight?
Indeed, it seems to be that way! If we look at other playlists, such as Lone Wolves, we see values in the range from 30 to 275, so even higher than what we see in Infection. This tells me that the weights are likely (keep in mind - I don’t work at 343 Industries and all knowledge is extrapolation from public API data) relative within the playlist.
To visualize this better, let’s take a look at how all of the playlists stack-up weight-wise today. My running assumption is that if the weight is relative, then we can also compute the percentage likelihood of a given combination to land in a given game.
Hover over the slices in the doughnut to see the values.
Infection #
Forbidden and Prism are the stars of the show, by a pretty large margin.
Lone Wolves #
The playlist is mostly balanced. There is a slight increase in weights for map-mode pairs on Forbidden and Prism, but not much compared to the wide array of others.
Squad Battle #
Fun fact - this playlist is perfectly balanced, because every map-mode pair has equal weight (100).
Husky Raid #
What do you know - another perfectly balanced playlist.
Team Slayer #
Modes that use newer maps (Forbidden and Prism) have ever so slightly higher likelihood of popping up, but that can be attributed to the desire to likely give players more time to get accustomed to the environment (as well as test the maps for playability).
Super Fiesta #
Lots of maps to choose from, with a bit of bias towards Super Fiesta (i.e., Fiesta with campaign weapons).
Ranked Slayer #
Slayer on Forbidden is the only map-mode pair that is slightly heavier weighted than others. Otherwise, it’s equally balanced.
Quick Play #
The developers really want you to play Strongholds on Streets and King Of The Hill on Argyle. I don’t disagree with that decision.
Big Team Battle #
Big Team Battle (BTB) is not my cup of tea, but if it’s yours - you’re more likely to play BTB Slayer on Scarr, Oasis, Fragmentation, Highpower, Deadlock, and Breaker.
Tactical Slayer #
I like Tactical Slayer (i.e., SWAT) because it really forces me to improve my reaction times. I also got used to playing with the Battle Rifle (BR) instead of the Bandit. Lucky for me, the skew (at least for now) is still in favor of BR-based SWAT.
Extraction 24/7 #
No surprises here - new mode, with new maps (Forbidden and Prism) being more heavily weighted.
Team Doubles #
You’re significantly more likely to play any mode that is not Slayer in this playlist.
Ranked Arena #
It took me some time to get used to non-Slayer game modes. That said, Slayer on Aquarius is still the most heavily-weighted map-mode pair in this playlist. Color me surprised.
Social Slayer #
Prepare to play some Mini Slayer on both small and large maps.
WORKSHOP BTB INFECTION #
No comment - it’s basically three maps for large-scale Infection.
Bot Bootcamp #
You’ll be playing bots on Forbidden and Prism.
Conclusion #
The more I started digging through this data, the more I realized that I want to be able to track this over time, similar to how I track my own match performance. That could be a project for OpenSpartan that I will (somehow) will need to find time for. Not only that, but looks like I need to be learning more about AMQP if I want to have an up-to-date view of currently active playlist.