Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Objects and identifiers

How the things a match is about are named on the wire, and when an object enters and leaves a client’s world.

The identifiers

IdentifierWidthFormedNo one
Player id64 bits, signedthe player’s account; a client is given its own when started-1, every bit set
Client id32 bits, unsignedchosen by the server for each player at registration, counting from 04294967295
Seata place in a side listthe order of a side’s player ids in Rosteran empty place
Net id32 bits, unsignedchosen by the server for what it creates; worked out from a name for what a map holds0
Node8 bits, unsignedthe owning client’s client id plus 1, or 0 for an object no client owns0
Region id32 bits, unsignedchosen by the server for each region, and carried by RegionAddedsee below
Name hash32 bits, unsignedworked out from the name of a spell, an effect, a particle or a bone0

A field’s own definition gives its exact type. Where a field carries one of these, it carries it whole, at the width above.

In 0.8.13.26–0.9.22.13

No region id stands for no region.

In 0.9.25.24–0.9.25.35

A region id of 0 names no region: given a RegionAdded carrying 0, a client gives the region an id of its own, its own node in the top byte and a count below it, which no message from a server can name.

A server MUST give each player a client id from 0 to 252.

A client takes a client id only from 0 to 252, and leaves on any other.

How they relate

A player is known by a player id. A server answers a client’s Register with Registered, and the one carrying the client’s own player id gives the client its own client id.

In 0.8.13.26–0.9.22.13

A client acts on that Registered alone and ignores every other, so it pairs no other player’s player id with a client id. A server MUST send it before any create message, because a client given a create message before it has its own client id stops.

In 0.9.25.24–0.9.25.35

Registration pairs each player id with a client id: a server answers a client’s Register with one Registered for every seat. Every later message that names a player by client id is read through that pairing.

Roster lists each side’s player ids in order, and a player’s seat is their place in that list. A client finds a seat’s client id through its player id. SeatName, SeatChampion and the VersionSync seats name a player by player id; SeatLoadProgress names both.

A champion carries the client id of the player it belongs to. The CreateChampion carrying a client’s own client id makes that champion the client’s own.

In 0.9.25.24–0.9.25.35

A bot’s champion carries 4294967295.

Net ids

A net id names one object in a client’s world: a unit, a missile, a particle, a marker, a prop. The header of every game message carries one, and fields naming a unit, an owner or a target carry one too.

  • A server MUST NOT give an object net id 0, which names nothing.
  • A server SHOULD NOT give an object a net id whose top byte is 0xFF, which the identifiers of what a map holds use, nor one whose top byte is any client’s client id plus 1, which a client uses for objects of its own making.
  • A server MUST NOT give a new object a net id it has given another object in the same match, except in a soft reconnect (see below).

In 0.8.13.26–0.9.22.13

A client given a create message for a net id it already holds stops.

In 0.9.25.24–1.0.0.24

A client that still holds the earlier object gives the net id to the new one, so messages naming it reach the new object, and removing either leaves the id naming neither.

A create message carries a node beside the object’s net id.

Net ids of what a map holds

Some objects are on the field before any message puts them there, and no message ever does: the buildings a side defends, the shops beside them, and the spawn points a side’s minions come from. A receiving end knows them from the map it loaded, and every message naming one names it by an identifier worked out from that object’s name in the map.

The identifier is the CRC-32 of the name, with the top byte set:

identifier = crc32(name) | 0xFF000000

The name is taken byte for byte with its case kept, so OrderShop01 and orderShop01 are two names and give two identifiers. The CRC-32 is the common one: the polynomial 0x04C11DB7 read reflected, starting from 0xFFFFFFFF and finishing with every bit inverted, so the nine bytes 123456789 give 0xCBF43926.

Among the identifiers with that top byte are these:

NameIdentifier
Barracks_T1_C10xFF4A20F1
Barracks_T1_L10xFFD23C3E
Barracks_T1_R10xFF9303E1
Barracks_T2_C10xFFFF8F1F
Barracks_T2_L10xFF6793D0
Barracks_T2_R10xFF26AC0F
__P_Order_Spawn_Barracks__C010xFFB77171
__P_Order_Spawn_Barracks__L010xFFEB364C
__P_Order_Spawn_Barracks__R010xFF53B836
__P_Chaos_Spawn_Barracks__C010xFFBA00E8
__P_Chaos_Spawn_Barracks__L010xFFE647D5
__P_Chaos_Spawn_Barracks__R010xFF5EC9AF
____P_Chaos_Spawn_Barracks__C010xFF707D61
ChaosShop010xFF3A98D9
chaosShop010xFFA6170E
HQ_T10xFFF97DB5
HQ_T20xFFF02C0F
OrderShop010xFF8C490C
orderShop010xFF10C6DB

In 0.8.13.26–0.9.22.13

Map 1 holds the six Barracks names, HQ_T1, HQ_T2, the six spawn points named __P_Order_Spawn_Barracks__ and __P_Chaos_Spawn_Barracks__ with C01, L01 or R01, and the shops OrderShop01 and ChaosShop, whose identifier is 4279618595. Its turret buildings carry the identifiers their names give too: Turret_T1_C_00 to Turret_T1_C_07, Turret_T1_L_02, Turret_T1_L_03, Turret_T1_R_02, Turret_T1_R_03, Turret_T2_C_00 to Turret_T2_C_05, Turret_T2_L_01 to Turret_T2_L_03, and Turret_T2_R_01 to Turret_T2_R_03.

In 0.9.25.24–1.0.0.24

Every object a map places carries the identifier its name gives, turrets, navigation points and props among them.

In 0.9.25.24–0.9.25.35

MapHolds
1, 2the six Barracks names, HQ_T1, HQ_T2, orderShop01, chaosShop01, the six spawn points named __P_…, and turrets named Turret_T1_… and Turret_T2_…, Turret_OrderTurretShrine and Turret_ChaosTurretShrine among them
3Barracks_T1_C1, Barracks_T2_C1, HQ_T1, HQ_T2, OrderShop01, ChaosShop01, ____P_Chaos_Spawn_Barracks__C01, and turrets, Turret_T1_C_08 among them

The Barracks names above belong to inhibitors, whatever the name says. The minions a side sends out come from spawn points of their own, which are among the objects a map holds.

A client puts a minion on the field for a SpawnFromBarracks naming a spawn point, and creates nothing for one naming an inhibitor such as Barracks_T1_C1.

A server MUST name each object a map holds by the identifier its name gives.

In 0.8.13.26–0.9.22.13

CreateTurret creates a turret of its own at the place its body gives, rather than naming one the map holds. PlaceTurret, whose header names a turret building the map holds, creates a new turret at that building’s place: the building keeps its own identifier, and each PlaceTurret makes another turret.

In 0.9.25.24–1.0.0.24

CreateTurret gives a net id to a turret the map already holds, matched by name. Given to a turret that already has one, it gives it a second, and both name it.

In 0.9.25.24–1.0.0.24

CreateTurret matches a turret’s name without regard to case, and does nothing where the map holds no turret of that name.

What a client holds

A client holds an object from the message that creates it until the message, or the end of its life, that removes it. Creating messages are listed in Units. What a map holds, a client holds from the moment it loads the map.

EnterSight and EnterLocalSight carry no other message, and act only on a unit the client already holds.

Leaving a client’s sight removes nothing: LeaveSight and LeaveTeamSight hide an object, and it is held as before.

LeaveLocalSight hides an object too, and it is held as before.

In 0.8.13.26–0.9.25.35

A new SpawnPet for an owner removes that owner’s pet before it.

In 0.9.25.24–0.9.25.35

A client removes a nexus about 4 seconds after BuildingDied names it, and can fail as it does. An inhibitor BuildingDied names is held.

A soft reconnect

SoftReconnect rebuilds a client’s world without a new connection, in two halves. The first marks every unit and every object kept until a checkpoint, inhibitors aside. A create message for a marked net id replaces the marked object rather than keeping the id on it. The second removes every object still marked. In between, a server sends again each object the client is to keep. Each stage either marks or removes.

Messages about objects a client does not hold

A message whose header names a net id the client does not hold, or whose body names one it needs, does nothing, and the client answers nothing for it. Creating messages are the exception, and so are these:

  • CreateFollower does nothing where the unit it follows is not held.
  • A Replication batch skips the units a client does not hold, and goes unanswered (see Ordering).
  • SoundPlayed naming an owner the client does not hold plays the sound with no place.

SpawnPet names the pet’s owner in its header and carries the new pet’s net id in its body, and does nothing where that owner is not held.

In 0.9.25.24–1.0.0.24

A client sends a WaypointGroup’s WaypointAck before it reads any path, whatever units the paths name. A path for a unit not held is read through and dropped, and is not applied once an object takes that net id.

Nothing else is held back for later: a message that arrives before the message creating what it names is lost. Ordering says what that requires of a server.

A message naming its sender

A server MUST set any field naming the sender from the connection the message arrived on, and MUST NOT copy the value the message carried; otherwise one player can send messages every other client attributes to another.

Name hashes

Some things a message names are known to a client by name: a spell, an effect a unit carries, a particle, and a place on a unit that particles hang from. A message names one of these by a number worked out from its name.

The number is the ELF hash of the name with its capital letters lowered:

number = 0
for each byte b of the name, with A to Z made a to z:
    number = (number << 4) + b
    high = number & 0xF0000000
    if high != 0:
        number = number ^ (high >> 24)
    number = number & ~high

Every step is worked in 32 bits. Only A to Z change, so SummonerFlash and summonerflash give one number. A particle’s name includes its extension, so the number comes from global_ss_flash.troy and not from global_ss_flash. The nine bytes 123456789 give 0x0678AEE9.

A byte from 128 to 255 enters the hash as its value less 256, worked in 32 bits, rather than as itself.

NameNumber
SummonerFlash0x06496EA8
RegenerationPotion0x0E75DC7E
EzrealMysticShotMissile0x05FE9CE5
global_ss_flash.troy0x0058E369
L_HAND0x0725E844

A server MUST name each such thing by the number its name gives.