roblox-aurora / rbx-net

Advanced multi-language networking framework for Roblox
https://rbxnet.australis.dev/
MIT License
94 stars 12 forks source link

Serialization & Buffer Support #96

Open Vorlias opened 1 month ago

Vorlias commented 1 month ago

I have an prototype working version of Serialization and buffer encoding using static type declarations. Will likely port it to RbxNet soon.

Vorlias commented 1 month ago

Example:

const TestStaticEvent = Net.Remote(NetType.Array(NetType.Int16)) 
// would type as number[] but effectively be short[]

by default RN not using buffers

However, if you want a more efficient way:

const TestStaticEvent = Net.Remote(NetType.Array(NetType.Int16)).SetUseBuffer(true)
// This would end up converting signals into a buffer like

[ u32 size, ...i16 data ] (where data is the length of size)

This is a bit like tools like zap where you define the static types, but through the net API.

So if we had

type NetworkInventorySlot = struct {
    SlotIndex: u8,
    ItemId: u16,
    Amount: u16,
}

type NetworkInventoryData = struct {
    InventoryId: u8,
    InventorySize: u8,
    InventoryDto: NetworkInventorySlot[],
}

event NetworkPlayerInventoryUpdated = {
    from: Server,
    type: Reliable,
    call: ManyAsync,
    data: NetworkInventoryData[],
}

In Net we could do a similar setup:

const NetworkInventorySlot = NetType.Interface({
    SlotIndex: NetType.UInt8,
    ItemId: NetType.UInt16,
    Amount: NetType.UInt16,
})

const NetworkInventoryData = NetType.Interface({
    InventoryId: NetType.UInt8,
    InventorySize: NetType.UInt8,
    InventoryDto: NetType.Array(NetworkInventorySlot),
})

const NetworkPlayerInventoryUpdated = Net.Remote(NetType.Array(NetworkInventoryData)).SetUseBuffer(true)

export default Net.Create()
    .AddServer("NetworkPlayerInventoryUpdated", NetworkPlayerInventoryUpdated)
    .Build();
Vorlias commented 1 month ago

here's an example of a custom serialized type (a Roblox player)

    /**
     * The player network type
     */
    export const Player: NetworkSerializer<Player, number> = {
        Name: "Player",
        Message: "Expected a Player",
        NetworkBuffer: NetEncoding.f64, // Roblox UserIds are uuuge
        $serializer: true,
        Validate(value): value is Player {
            return typeIs(value, "Instance") && value.IsA("Player");
        },
        Serialize(value) {
            return value.UserId;
        },
        Deserialize(value) {
            const player = Players.GetPlayerByUserId(value);
            assert(player);
            return player;
        },
    };

If buffers are used, it will use the NetworkBuffer for the buffer translation, otherwise you will see a double number instead.

Vorlias commented 1 month ago

Feel free to comment feedback on this - it's been a bit of a process to figure this all out. :-)