Skip to main content

Packet Serializer

Project description

BridgeStream

BridgeStream is a order oriented binary serialization library developed for performance and efficiency.

BridgeStream is used as a part of an real-time online game to transmit data between the client and servers.

You can encode/decode primitive types, collection on primitives, custom serializers and other BridgeStream's easily and efficiently.

Install

pip install bridgestream

Basic Usage

Create a stream

from bridgestream import BridgeStream

stream = BridgeStream()

Write some data

stream.write_int(1)
stream.write_string("test")
stream.write_float(0.1)
stream.write_bool(True)

Encode

data = stream.encode()

Decode

stream = BridgeStream(data)

Read in order

stream.read_int()  # 1
stream.read_string()  # test
stream.read_float()  # 0.1
stream.read_bool()  # True

Custom Types

You can define your own serializers to abstract your common data types using BridgeSerializer.

You must implement the write method of BridgeSerializer to be able to encode it as a stream and you must implement the read method to be able to decode it as a stream.

from bridgestream import BridgeSerializer

@dataclass  # dataclass is not required but recommended
class Vector3(BridgeSerializer):
    x: int
    y: int
    z: int

    def write(self, stream: BridgeStream):
        stream.write_int(self.x)
        stream.write_int(self.y)
        stream.write_int(self.z)

    def read(self, stream: BridgeStream):
        self.x = stream.write_int(x)
        self.y = stream.write_int(y)
        self.z = stream.write_int(z)

You can encode custom serializers using the write method of BridgeStream.

vector = Vector3(1, 0, 2)

stream = BridgeStream()
stream.write(vector)

data = stream.encode()

You can decode a custom serializer using the read(BirdgeSerializer) method of BridgeStream.

stream = BridgeStream(data)

vector = stream.read(Vector3)  # Vector3(x=1, y=0, z=2)

You can also read/write list of custom serializers.

vectors = [Vector3(1, 0, 2), Vector3(3, -1, 4)]

stream = BridgeStream()
stream.write_list(vector)

data = stream.encode()


stream = BridgeStream(data)

vector = stream.read_list(Vector3)  # [Vector3(x=1, y=0, z=2), ector3(x=3, y=-1, z=4)]

Nested BridgeStream

Some times it is necessary to write a bridgestream within another bridgestream. In this example; we have 2 different serializers that have the same purposes. Each Serializer can do its business logic within its own read/write methods and still can be serialized as a whole.

Class definitions

@dataclass
class WarriorLevel(BridgeSerializer):
    health: int
    attack_radious: int
    shield: int

    def write(self, stream: BridgeStream):
        stream.write_int(self.health)
        stream.write_int(self.attack_radious)
        stream.write_int(self.shield)

    def read(self, stream: BridgeStream):
        self.health = stream.read_int()
        self.attack_radious = stream.read_int()
        self.shield = stream.read_int()

@dataclass
class MageLevel(BridgeSerializer):
    health: int
    projectile_damage: int
    regeneration: int

    def write(self, stream: BridgeStream):
        stream.write_int(self.health)
        stream.write_int(self.projectile_damage)
        stream.write_int(self.regeneration)

    def read(self, stream: BridgeStream):
        self.health = stream.read_int()
        self.projectile_damage = stream.read_int()
        self.regeneration = stream.read_int()


@dataclass
class Warrior(BridgeSerializer):
    id: str
    attack_speed: float
    atack_cooldown: float
    levels: List[WarriorLevel]

    def write(self, stream):
        stream.write_string(self.id)
        stream.write_float(self.attack_speed)
        stream.write_float(self.atack_cooldown)
        stream.write_list(self.levels)


    def read(self, stream):
        self.id = stream.read_string()
        self.attack_speed = stream.read_float()
        self.atack_cooldown = stream.read_float()
        self.levels = stream.read_list(WarriorLevel)


@dataclass
class Mage(BridgeSerializer):
    id: str
    projectile_range: float
    projectile_speed: float
    levels: List[MageLevel]

    def write(self, stream: BridgeStream):
        stream.write_string(self.id)
        stream.write_float(self.projectile_range)
        stream.write_float(self.projectile_speed)
        stream.write_list(self.levels)


    def read(self, stream: BridgeStream):
        self.id = stream.read_string()
        self.attack_speed = stream.read_float()
        self.atack_cooldown = stream.read_float()
        self.levels = stream.read_list(MageLevel)


@dataclass
class Player(BridgeSerializer):
    name: str
    level: int
    heroes: List[str]

    def write(self, stream: BridgeStream):
        stream.write_string(self.name)
        stream.write_int(self.level)
        stream.write_string_list(self.heroes)


    def read(self, stream: BridgeStream):
        self.name = stream.read_string()
        self.level = stream.read_int()
        self.heroes = stream.read_string_list()

Initialization

player = Player(name="player-1", level=5, heroes=["w-1", "m-1"])

hero_cofigurations = {
    "warrior": Warrior(
        id="w-1",
        attack_speed=0.4,
        atack_cooldown=0.2,
        levels=[WarriorLevel(300, 50, 1), WarriorLevel(340, 55, 1.2)]
    ),
    "mage": Mage(
        id="m-1",
        projectile_range=400,
        projectile_speed=1.4,
        levels=[MageLevel(1.5, 30, 5), MageLevel(340, 35, 10)]
    ),
}

Nested encoding & decoding

stream = BridgeStream()
stream.write(player)

hero_config_stream = BridgeStream()
for class_name, config in hero_cofigurations.items():
    hero_config_stream.write_string(class_name)
    hero_config_stream.write(config)

stream.write_stream(hero_config_stream)

data = stream.encode()


stream = BridgeStream(data)

player = stream.read(Player)  # Player(name="player-1", level=5, heroes=["w-1", "m-1"])

# Read the stream to the end and create config by types

hero_classes = {"warrior": Warrior, "mage": Mage}
hero_cofigurations = {}
while stream.has_more():
    class_name = stream.read_string()
    config = stream.read(hero_classes[class_name])
    hero_cofigurations[class_name] = config


hero_cofigurations
"""
{
    "warrior": Warrior(
        id="w-1",
        attack_speed=0.4,
        atack_cooldown=0.2,
        levels=[WarriorLevel(300, 50, 1), WarriorLevel(340, 55, 1.2)]
    ),
    "mage": Mage(
        id="m-1",
        projectile_range=400,
        projectile_speed=1.4,
        levels=[MageLevel(1.5, 30, 5), MageLevel(340, 35, 10)]
    ),
}
"""

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

bridgestream-1.2.1.tar.gz (8.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

bridgestream-1.2.1-py3-none-any.whl (5.9 kB view details)

Uploaded Python 3

File details

Details for the file bridgestream-1.2.1.tar.gz.

File metadata

  • Download URL: bridgestream-1.2.1.tar.gz
  • Upload date:
  • Size: 8.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.2.0 pkginfo/1.6.1 requests/2.24.0 setuptools/49.2.1 requests-toolbelt/0.9.1 tqdm/4.51.0 CPython/3.9.0

File hashes

Hashes for bridgestream-1.2.1.tar.gz
Algorithm Hash digest
SHA256 97d8aa173cf45b3145950857aab106b16848dedb2936bd327b4ee70928594a52
MD5 ae940d69ebaf84417e621707fd1ad2f0
BLAKE2b-256 dd3a655856a23787c9c13de0fd971a5b4c3daca7ee7b28f0f1603382576b31dd

See more details on using hashes here.

File details

Details for the file bridgestream-1.2.1-py3-none-any.whl.

File metadata

  • Download URL: bridgestream-1.2.1-py3-none-any.whl
  • Upload date:
  • Size: 5.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.2.0 pkginfo/1.6.1 requests/2.24.0 setuptools/49.2.1 requests-toolbelt/0.9.1 tqdm/4.51.0 CPython/3.9.0

File hashes

Hashes for bridgestream-1.2.1-py3-none-any.whl
Algorithm Hash digest
SHA256 e1b7cf2d523e4a39e90e23ede056aee0c78e1bcbf81f6b8842cfc360d2e2ee86
MD5 ca0094d1dbeed51deda8e23bb5d0c664
BLAKE2b-256 43eefb6cb6dc32275b4993c309e91e96953a4095a06e9effb2498a56fb6c7c53

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page