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
| Identifier | Width | Formed | No one |
|---|---|---|---|
| Player id | 64 bits, signed | the player’s account; a client is given its own when started | -1, every bit set |
| Client id | 32 bits, unsigned | chosen by the server for each player at registration, counting from 0 | 4294967295 |
| Seat | a place in a side list | the order of a side’s player ids in Roster | an empty place |
| Net id | 32 bits, unsigned | chosen by the server for what it creates; worked out from a name for what a map holds | 0 |
| Node | 8 bits, unsigned | the owning client’s client id plus 1, or 0 for an object no client owns | 0 |
| Region id | 32 bits, unsigned | chosen by the server for each region, and carried by RegionAdded | see below |
| Name hash | 32 bits, unsigned | worked out from the name of a spell, an effect, a particle or a bone | 0 |
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
RegionAddedcarrying 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
Registeredalone 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
Registerwith oneRegisteredfor 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:
| Name | Identifier |
|---|---|
Barracks_T1_C1 | 0xFF4A20F1 |
Barracks_T1_L1 | 0xFFD23C3E |
Barracks_T1_R1 | 0xFF9303E1 |
Barracks_T2_C1 | 0xFFFF8F1F |
Barracks_T2_L1 | 0xFF6793D0 |
Barracks_T2_R1 | 0xFF26AC0F |
__P_Order_Spawn_Barracks__C01 | 0xFFB77171 |
__P_Order_Spawn_Barracks__L01 | 0xFFEB364C |
__P_Order_Spawn_Barracks__R01 | 0xFF53B836 |
__P_Chaos_Spawn_Barracks__C01 | 0xFFBA00E8 |
__P_Chaos_Spawn_Barracks__L01 | 0xFFE647D5 |
__P_Chaos_Spawn_Barracks__R01 | 0xFF5EC9AF |
____P_Chaos_Spawn_Barracks__C01 | 0xFF707D61 |
ChaosShop01 | 0xFF3A98D9 |
chaosShop01 | 0xFFA6170E |
HQ_T1 | 0xFFF97DB5 |
HQ_T2 | 0xFFF02C0F |
OrderShop01 | 0xFF8C490C |
orderShop01 | 0xFF10C6DB |
In 0.8.13.26–0.9.22.13
Map 1 holds the six
Barracksnames,HQ_T1,HQ_T2, the six spawn points named__P_Order_Spawn_Barracks__and__P_Chaos_Spawn_Barracks__withC01,L01orR01, and the shopsOrderShop01andChaosShop, whose identifier is 4279618595. Its turret buildings carry the identifiers their names give too:Turret_T1_C_00toTurret_T1_C_07,Turret_T1_L_02,Turret_T1_L_03,Turret_T1_R_02,Turret_T1_R_03,Turret_T2_C_00toTurret_T2_C_05,Turret_T2_L_01toTurret_T2_L_03, andTurret_T2_R_01toTurret_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
Map Holds 1, 2 the six Barracksnames,HQ_T1,HQ_T2,orderShop01,chaosShop01, the six spawn points named__P_…, and turrets namedTurret_T1_…andTurret_T2_…,Turret_OrderTurretShrineandTurret_ChaosTurretShrineamong them3 Barracks_T1_C1,Barracks_T2_C1,HQ_T1,HQ_T2,OrderShop01,ChaosShop01,____P_Chaos_Spawn_Barracks__C01, and turrets,Turret_T1_C_08among 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
CreateTurretcreates 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 eachPlaceTurretmakes another turret.
In 0.9.25.24–1.0.0.24
CreateTurretgives 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
CreateTurretmatches 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
SpawnPetfor 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
BuildingDiednames it, and can fail as it does. An inhibitorBuildingDiednames 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:
CreateFollowerdoes nothing where the unit it follows is not held.- A
Replicationbatch skips the units a client does not hold, and goes unanswered (see Ordering). SoundPlayednaming 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’sWaypointAckbefore 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.
| Name | Number |
|---|---|
SummonerFlash | 0x06496EA8 |
RegenerationPotion | 0x0E75DC7E |
EzrealMysticShotMissile | 0x05FE9CE5 |
global_ss_flash.troy | 0x0058E369 |
L_HAND | 0x0725E844 |
A server MUST name each such thing by the number its name gives.