Skip to content
This repository has been archived by the owner on Sep 3, 2022. It is now read-only.

4.11 How to add packets

danil179 edited this page Jan 1, 2019 · 9 revisions

Currently, the project uses many incorrect packet structers, as a result many features in the game doesn't work. In this section we will learn how to implement packet correctly.

LeaguePacket

First you should know that every packet has its structure in [LeaguePackets|https://github.com/moonshadow565/LeaguePackets/tree/420/LeaguePackets/GamePackets], so you can use the structure from there.

Work flow

Every packet is either C2S (Client to Server) or S2C (similarly), we will denote these as Requests and Responses

Responses

There are 2 parts:

  1. GameServerLib - the framework issue the sending, called here 'the server'.
  2. PacketNotifier - the actual sender, called here 'the notifier'

In the server (GameServerLib) you just call Notify function in PacketNotifier, for example:

https://github.com/LeagueSandbox/GameServer/blob/b2ca11d9197a5800d58fdad36c40fdddd161967a/GameServerLib/GameObjects/AttackableUnits/AttackableUnit.cs#L86

As you can see, in the server we use just API object like IAttackableUnit.

In the notifier you will need to have of course the packetsending scheme that you want, for example:

public void NotifySkillUp(int userId, uint netId, byte skill, byte level, byte pointsLeft)
{
    var skillUpResponse = new SkillUpResponse(netId, skill, level, pointsLeft);
    _packetHandlerManager.SendPacket(userId, skillUpResponse, Channel.CHL_GAMEPLAY);
}

What is happening here is actualy sending of BasePacket object that actually converted to byte[] later when Enet sending the packet (Enet - the network lib we use). We don't enforced to send BasePacket as you can see here:

public void NotifyMinionSpawned(IMinion minion, TeamId team)
{
            var spawnPacket = new LeaguePackets.GamePackets.SpawnMinionS2C();
            spawnPacket.SkinName = minion.Model;
            spawnPacket.Name = minion.Name;
            spawnPacket.VisibilitySize = minion.VisionRadius; // Might be incorrect
            spawnPacket.IsTargetableToTeam = SpellFlags.TargetableToAll;
            spawnPacket.IsTargetable = true;
            spawnPacket.IsBot = minion.IsBot;
            spawnPacket.IsLaneMinion = minion.IsLaneMinion;
            spawnPacket.IsWard = minion.IsWard;
            spawnPacket.IgnoreCollision = false;
            spawnPacket.TeamID = (TeamID)minion.Team;
            // CloneNetID, clones not yet implemented
            spawnPacket.SkinID = 0;
            spawnPacket.Position = new Vector3(minion.GetPosition().X, minion.GetZ(), minion.GetPosition().Y);
            spawnPacket.SenderNetID = (NetID)minion.NetId;
            spawnPacket.NetNodeID = NetNodeID.Spawned;
            if (minion.IsLaneMinion) // Should probably change/optimize at some point
            {
                spawnPacket.OwnerNetID = (NetID)minion.Owner.NetId;
            }
            else
            {
                spawnPacket.OwnerNetID = (NetID)minion.NetId;
            }
            spawnPacket.NetID = (NetID)minion.NetId;
            spawnPacket.InitialLevel = 1;
            var visionPacket = new LeaguePackets.GamePackets.OnEnterVisiblityClient();
            var vd = new LeaguePackets.CommonData.VisibilityDataAIMinion();
            vd.LookAtPosition = new Vector3(1, 0, 0);
            var md = new LeaguePackets.CommonData.MovementDataStop();
            md.Position = minion.GetPosition();
            md.Forward = new Vector2(0, 1);
            vd.MovementSyncID = 0x0006E4CF;
            vd.MovementData = md;
            visionPacket.VisibilityData = vd;
            visionPacket.Packets.Add(spawnPacket);
            visionPacket.SenderNetID = (NetID)minion.NetId;
            _packetHandlerManager.BroadcastPacketVision(minion, visionPacket.GetBytes(), Channel.CHL_S2C);
}

This is more complex packet, but you see how LeaguePackets handle all the field and then you use GetBytes() method to get just byte[] to send with Enet.

Requests

WIP