#Help designing a packet registry and abstraction

1 messages · Page 1 of 1 (latest)

sick nebula
#

I've been working on a minecraft server implementation in zig for a bit and I wanted to make a better packet parsing and handling system. I understand that sounds high level and not really help appropriate but I need help with understanding how something like this can be laid out in zig:

interface Packet
impl HandshakePacket {
field1: []const u8
field2: i32
}

fn readPacket(reader: std.net.Stream.Reader) Packet {
    // return the interface but still retain ability to access the implementation and sort of "cast" it
    
}

I originally thought of using packed structs and using readStruct in std.net.Stream.Reader but because of how terrible the minecraft network protocol is ,they use different varints than the reader can read and I dont think its possible to implement it using a packed struct. Even if it was id still not know how to "cast" it and keep an abstracted type to return

steep delta
#

how does the packet look in memory?

sick nebula
#

you first read size, then id, then the rest is the payload (size bytes)

steep delta
#

I think it's probably easier to read the fields manually then using readStructEndian. you can read the id with readInt().

you can't really make a struct with the same in-memory representation as the one you receive because it's big-endian and you need little-endian (so you have to byteSwap) and it's variable length, but zig doesn't support variable-length structs

#

a packed struct is only for bitfields, generally you would want an extern struct for defined memory layouts and only use a packed struct for specific parts of it that need it

sick nebula
#

atleast viable

steep delta
#

what do you mean?

#

what's difficult about it?

sick nebula
#

i cant see how i would implement that

#

yet alone abstract it

steep delta
#
fn readPacket(reader: ..) Packet {
    const id = try reader.readInt(i32, .big);
    const body = allocator.alloc(u8, len);
    const read_len = try reader.readAll(body);
}

something like this

#

not sure what your goals are for abstraction

sick nebula
# steep delta not sure what your goals are for abstraction

Yeah i did this exactly but I want to have Packet be like an interface, I have this as a FramedPacket, I want to convert it to any other struct that has ties to a "interface'" packet. So for example my method would be fn sendPacket(self: Player, packet: Packet) void {} where i could pass all the packet types

#

my bad for not being clear enough

#

I hope that makes sense

steep delta
#

you can make packet a union(enum) of all the different packet types

sick nebula
#

same with reading

sick nebula
#

Especially because different connection states have packets with the same id as other states

steep delta
sick nebula
#

I confused union(enum) with enum(union) which is not a real thing

#

whoops

#

I see, I guess that's a good idea yeah, and for writing and reading I could make a big switch statement ig idk

steep delta
#

yeah basically

sick nebula
#

That makes sense