Valkyrien Skies Help

How to use the VS networking system

Valkyrien Skies uses its own loader-abstracted networking system, which addons can use too.

This means your networking can be the same on both forge and fabric easily, without libraries like Architectury API (or your own abstractions).

Setting up your packet class

First, you need a packet class. This class just needs to store the data that is being sent across the network. It should extend SimplePacket, no matter the direction it will go (server -> client or client -> server).

(The integer data is an example, the data can be multiple properties and can be different types)

data class MyPacket(val myData: Int): SimplePacket
public record MyPacket(int myData) implements SimplePacket {}

Registering your packet

To use your packet, it must be registered to Valkyrien Skies.

with(vsCore.simplePacketNetworking) { MyPacket::class.register() }
ValkyrienSkiesMod.getVsCore().getSimplePacketNetworking().register( JvmClassMappingKt.getKotlinClass(MyPacket.class) );

Adding listeners

This is where you specify whether your packet is server -> client (s2c) or client -> server (c2s).

The listener setup is very similar to the initial packet registration.

You have the option to register a server handler (for a c2s packet) or a client handler (for a s2c packet).

The server listener receives a VsiPlayer, representing the client which sent the packet. Both listener types receive an instance of the packet class itself (after it has been deserialized)

VsiPlayer is an abstraction of the Minecraft Player that VS-Core uses to stay Minecraft agnostic. You can obtain a normal Player from the VsiPlayer using:

val player = (vsiPlayer as MinecraftPlayer).player as ServerPlayer
ServerPlayer player = (ServerPlayer) ((MinecraftPlayer) vsiPlayer).getPlayer();

To register your listeners:

with(vsCore.simplePacketNetworking) { MyToServerPacket::class.registerServerHandler { packet, vsiPlayer -> // Do stuff (on server) } MyToClientPacket::class.registerClientHandler { packet -> // Do stuff (on client) } }
ValkyrienSkiesMod.getVsCore().getSimplePacketNetworking().registerServerHandler( JvmClassMappingKt.getKotlinClass(MyToServerPacket.class), (packet, vsiPlayer) -> { // Do stuff (on server) return null; } ); ValkyrienSkiesMod.getVsCore().getSimplePacketNetworking().registerClientHandler( JvmClassMappingKt.getKotlinClass(MyToClientPacket.class), (packet) -> { // Do stuff (on client) return null; } );

Sending your packets

Now you've got a packet registered, and you've got it running code when it is recieved. How do you actually send it out?

Here's how you would send a packet from a client to the server:

with(vsCore.simplePacketNetworking) { // We put 0 here because our example MyPacket // from earlier stored an integer as its data MyPacket(0).sendToServer() }
ValkyrienSkiesMod.getVsCore().getSimplePacketNetworking().sendToServer( // We put 0 here because our example MyPacket // from earlier stored an integer as its data new MyPacket(0) );

And here's from the server to a specific client:

// The client to send the packet to val player: Player = // ... with(vsCore.simplePacketNetworking) { // We put 0 here because our example MyPacket // from earlier stored an integer as its data MyPacket(0).sendToClient(player.playerWrapper) }
// The client to send the packet to Player player = // ... ValkyrienSkiesMod.getVsCore().getSimplePacketNetworking().sendToClient( // We put 0 here because our example MyPacket // from earlier stored an integer as its data new MyPacket(0), ((PlayerDuck) player).vs_getPlayer() );

There's also sendToClients and sendToAllClients but those should hopefully be self-explanatory.

How serialization works

The Valkyrien Skies networking uses a CBORMapper Jackson Serializer, which is configured to be able to serialize:

  • All primitive types (numbers, strings, maps, lists, etc)

  • Data/record classes

  • All JOML types (Vector3d, Quaterniond, etc)

  • ShipData and VsBodyData

The mapper will also ignore (not serialize/deserialize) any property annotated with @JsonIgnore

Keep in mind that Minecraft classes (e.g. BlockPos or Vec3) can't be serialized. Often they can be converted to/from a lower primitive.

For example BlockPos can do the following:

val pos: BlockPos = // ... val posToLong = pos.asLong() // Send the long through the packet val posFromLong = BlockPos.of(posToLong) assert(pos == posFromLong) // always true
BlockPos pos = // ... long posToLong = pos.asLong(); // Send the long through the packet BlockPos posFromLong = BlockPos.of(posToLong); assert pos == posFromLong; // always true

Note that at the moment, it is not possible to add custom serializers/deserializers to the Valkyrien Skies networking mapper.

Last modified: 01 October 2026