-
Notifications
You must be signed in to change notification settings - Fork 438
4.11 How to add packets
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.
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.
Every packet is either C2S (Client to Server) or S2C (similarly), we will denote these as Requests and Responses
There are 2 parts:
- GameServerLib - the framework issue the sending, called here 'the server'.
- PacketNotifier - the actual sender, called here 'the notifier'
In the server (GameServerLib) you just call Notify
function in PacketNotifier
, for example:
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.
WIP
LeagueSandbox is a AGPL-3.0 open-source project