ProtankiNetworking 3.0.1
dotnet add package ProtankiNetworking --version 3.0.1
NuGet\Install-Package ProtankiNetworking -Version 3.0.1
<PackageReference Include="ProtankiNetworking" Version="3.0.1" />
<PackageVersion Include="ProtankiNetworking" Version="3.0.1" />
<PackageReference Include="ProtankiNetworking" />
paket add ProtankiNetworking --version 3.0.1
#r "nuget: ProtankiNetworking, 3.0.1"
#:package ProtankiNetworking@3.0.1
#addin nuget:?package=ProtankiNetworking&version=3.0.1
#tool nuget:?package=ProtankiNetworking&version=3.0.1
ProtankiNetworking
NuGet package: ProtankiNetworking on NuGet
A C# library for ProTanki game communication. This project is based on code from the ProboTanki-Lib Python library, but it is not exact port.
Related Project
- ProtankiProxy uses this networking library in a real-world proxy setup.
- It can also be very useful when debugging this library, especially for inspecting packet flow and validating encode/decode behavior.
TCP Networking Components
The library provides three main components for TCP networking:
TankiTcpListener: Base class for TCP server implementation that accepts client connectionsTankiTcpClientHandler: Base class for handling individual client connections to TankiTcpListenerTankiTcpClient: Base class for TCP client implementation
Usage Examples
1. Creating a Custom TCP Server
public class MyTankiServer : TankiTcpListener
{
public MyTankiServer(IPEndPoint localEndPoint)
: base(localEndPoint)
{
}
protected override TankiTcpClientHandler CreateClientHandler(
TcpClient client,
CancellationToken cancellationToken)
{
return new MyClientHandler(client, new Protection(), cancellationToken);
}
protected override async Task OnErrorAsync(Exception exception, string context)
{
Console.WriteLine($"Server error in {context}: {exception.Message}");
}
protected override Task OnClientConnectedAsync(TcpClient client)
{
return Task.CompletedTask;
}
protected override Task OnClientDisconnectedAsync(TcpClient client)
{
return Task.CompletedTask;
}
}
// Usage:
var endPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 8080);
var server = new MyTankiServer(endPoint);
server.Start();
2. Creating a Custom Client Handler
public class MyClientHandler : TankiTcpClientHandler
{
public MyClientHandler(
TcpClient client,
Protection protection,
CancellationToken cancellationToken)
: base(client, protection, cancellationToken)
{
}
protected override async Task OnRawPacketReceivedAsync(byte[] rawPacket)
{
Console.WriteLine($"Received raw packet of length {rawPacket.Length}");
}
protected override async Task OnPacketReceivedAsync(Packet packet)
{
Console.WriteLine($"Received packet of type {packet.GetType().Name}");
}
protected override async Task OnErrorAsync(Exception exception, string context)
{
Console.WriteLine($"Handler error in {context}: {exception.Message}");
}
protected override Task OnConnectedAsync()
{
return Task.CompletedTask;
}
protected override Task OnDisconnectedAsync()
{
return Task.CompletedTask;
}
protected override Task OnPacketUnwrapFailureAsync(Type packetType, int packetId, Exception exception)
{
Console.WriteLine($"Unwrap failed for {packetType.Name} ({packetId}): {exception.Message}");
return Task.CompletedTask;
}
}
3. Creating a Custom TCP Client
public class MyTankiClient : TankiTcpClient
{
public MyTankiClient(IPEndPoint serverEndPoint, Protection protection)
: base(serverEndPoint, protection)
{
}
protected override async Task OnRawPacketReceivedAsync(byte[] rawPacket)
{
Console.WriteLine($"Received raw packet of length {rawPacket.Length}");
}
protected override async Task OnPacketReceivedAsync(Packet packet)
{
Console.WriteLine($"Received packet of type {packet.GetType().Name}");
}
protected override async Task OnErrorAsync(Exception exception, string context)
{
Console.WriteLine($"Client error in {context}: {exception.Message}");
}
protected override Task OnConnectedAsync()
{
return Task.CompletedTask;
}
protected override Task OnDisconnectedAsync()
{
return Task.CompletedTask;
}
protected override Task OnPacketUnwrapFailureAsync(Type packetType, int packetId, Exception exception)
{
Console.WriteLine($"Unwrap failed for {packetType.Name} ({packetId}): {exception.Message}");
return Task.CompletedTask;
}
}
// Usage:
var endPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 8080);
var protection = new Protection(); // Configure protection as needed
var client = new MyTankiClient(endPoint, protection);
await client.ConnectAsync();
Project Structure
Code/Codec/- Data encoding/decoding systemCode/Networking/- Network communication utilitiesCode/Packets/- Game packet definitionsCode/Security/- Security and protection mechanisms
Packets
Naming Convention
Packet direction is named from the point of view of your app using this library:
In...Packet= packet comes in to your app (server → client)Out...Packet= packet goes out from your app (client → server)
Examples:
LoginSuccessInPacketis received by the client from server.LoginOutPacketis sent by the client to server.
Packet Class Structure
Every packet class inherits from Packet and usually defines:
ID_CONST(the packet id constant)Idoverride returningID_CONSTDescriptionoverride- fields/properties marked with
[Encode(order)]for payload serialization
Minimal example:
public class LoginOutPacket : Packet
{
[Encode(0)] public string? Username { get; set; }
[Encode(1)] public string? Password { get; set; }
[Encode(2)] public bool RememberMe { get; set; }
public const int ID_CONST = -739684591;
public override int Id => ID_CONST;
}
What [Encode(order)] Means
- Only members with
[Encode(...)]are serialized/deserialized. orderdefines exact write/read order in payload.
Unknown or Failed Packet Mapping
PacketManagermapspacketId→ packet type using reflection.- If id is unknown, or decoding fails, library falls back to
UnknownPacket. RawDatakeeps original full bytes (header + payload).DecryptedDatakeeps decrypted payload bytes only.
Encodable Data
Encodable Class Structure
Every encodable data class implements IEncodable and usually defines:
IsOptionalflag for nullable object encoding metadata.IsArrayOptionalflag for nullable array/vector encoding metadata.- fields/properties marked with
[Encode(order)]for payload serialization.
Minimal example:
public class AssaultCC : IEncodable
{
public bool IsOptional { get; } = false;
public bool IsArrayOptional { get; } = false;
[Encode(0)] public ClientAssaultFlag?[]? BlueFlags { get; set; }
[Encode(1)] public Resource? FlagPedestalModel { get; set; }
[Encode(2)] public Resource? FlagSprite { get; set; }
}
What [Encode(order)] Means
- Only members with
[Encode(...)]are serialized/deserialized. orderdefines exact write/read order in payload.
Optional Flags (IEncodable)
IsOptional = trueadds a leading boolean marker indicating whether the object isnull.IsArrayOptional = trueadds a leading boolean marker when this type is used in arrays/vectors.
Disclaimer
This library is for educational purposes only. Use of this library should comply with ProTanki's terms of service. (so you can't use it at all 😄)
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net8.0
- SharpZipLib (>= 1.4.2)
- System.Text.Json (>= 9.0.6)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.