Valkyrien Skies Help

How to migrate to VS 2.4

Valkyrien Skies 2.4 introduced a number of breaking API changes. Addon developers and other mod developers with VS integration will need to update their mods.

Required changes

These changes are required for your mod or addon to continue functioning with VS 2.4.

Migrate to the new attachments system

Change your attachment imports

The extension functions in org.valkyrienskies.core.api.ships.* have been moved to org.valkyrienskies.core.api.attachments.*.

Original

Replacement

org.valkyrienskies.core.api.ships.saveAttachment

org.valkyrienskies.core.api.attachments.setAttachment

org.valkyrienskies.core.api.ships.setAttachment

org.valkyrienskies.core.api.attachments.setAttachment

org.valkyrienskies.core.api.ships.getAttachment

org.valkyrienskies.core.api.attachments.getAttachment

Get and set attachments on LoadedServerShip, not ServerShip

Attachments on potentially unloaded ships are no longer supported.

val ship: ServerShip = ... ship.saveAttachment(MyAttachment())
val ship: ServerShip = ... if (ship is LoadedServerShip) { ship.setAttachment(MyAttachment()) }
ServerShip ship = ... ship.saveAttachment(new MyAttachment())
ServerShip ship = ... if (ship instanceof LoadedServerShip loadedShip) { loadedShip.setAttachment(new MyAttachment()); }

Register your attachments

Your attachments now need to be registered.

To migrate legacy attachments in a backwards compatible way, make sure to call useLegacySerializer() while registering the attachments.

vsApi.registerAttachment(MyAttachment::class.java) { useLegacySerializer() }
AttachmentRegistration registration = ValkyrienSkies.api() .newAttachmentRegistrationBuilder(MyAttachment.class) .useLegacySerializer() .build(); ValkyrienSkies.api().registerAttachment(registration);

Make your attachments final

Attachment classes are now required to be final - meaning they can't be interfaces and they can't be extended.

class MyAttachment { // ... }
final class MyAttachment { // ... }

Migrate from constraints to joints

Constraints are now joints, and everything in org.valkyrienskies.core.apigame.constraints has been removed.

Migrate to new force application methods

Force application has been revamped. The old methods in org.valkyrienskies.core.api.ships.PhysShip have been marked as deprecated, and point to their new counterparts.

Original

Replacement

applyInvariantForce(force) && applyInvariantForceToPos(force, pos)

applyWorldForce(force, pos) OR applyWorldForceToBodyPos(force, pos)

applyInvariantTorque(torque)

applyWorldTorque(torque)

applyRotDependentForce(force) && applyRotDependentForceToPos(force, pos)

applyBodyForce(force, pos)

applyRotDependentTorque(torque)

applyBodyTorque(torque)

Additionally, there are new methods to apply forces/torques in ship-space coordinates; you can find all of these methods and further documentation in the javadocs for PhysShip.

Migrate from ShipForceAppliers to ShipPhysicsListeners

The ShipForceApplier interface has been removed. Use ShipPhysicsListener instead, which takes advantage of the new PhysLevels to provide a more cohesive way to access things that reside on the Physics Thread.

applyForces and applyForcesToNearbyShips have been replaced with physTick(physShip, physLevel). This allows you to add/update/remove joints, enable and disable collision pairs, and access other ships through the provided PhysLevel. Experimental API features such as retrieving all joints in the world can be accessed through VsiPhysLevel, though this is not advised for general use, as it may change in future versions.

These changes aren't strictly required, but they will make your life easier during future updates and improve the quality of your code.

Use rebuild and toBuilder instead of ShipTransform.copy

val transform: ShipTransform = ... val newTransform: ShipTransform = transform.copy( positionInWorld = Vector3d(123) )
val transform: ShipTransform = ... val newTransform: BodyTransform = transform.rebuild { position.set(Vector3d(123)) }
ShipTransform transform = ... ShipTransform newTransform = transform.copy( new Vector3d(123), transform.getPositionInShip(), transform.getRotation(), transform.getScaling() );
ShipTransform transform = ... BodyTransform newTransform = transform.toBuilder() .position(new Vector3d(123)) .build();

Java users:

  • Use ValkyrienSkies instead of VSGameUtilsKt and VectorConversionsMCKt.

  • Remove imports from org.valkyrienskies.mod.common.

Kotlin users:

  • Remove imports from org.valkyrienskies.mod.common.

Use getShipManagingBlock/getShipManagingChunk instead of getShipManagingPos

getShipManagingPos has been renamed and moved. We'll keep the old versions around, but try not to use them.

import org.valkyrienskies.mod.common.getShipManagingPos val level: Level = ... val pos: BlockPos = ... val ship = level.getShipManagingPos(level, pos)
import org.valkyrienskies.mod.api.getShipManagingBlock val level: Level = ... val pos: BlockPos = ... val ship = level.getShipManagingBlock(level, pos)
import org.valkyrienskies.mod.common.VSGameUtilsKt Level level = ... BlockPos pos = ... Ship ship = VSGameUtilsKt.getShipManagingPos(level, pos);
import org.valkyrienskies.mod.api.ValkyrienSkies Level level = ... BlockPos pos = ... Ship ship = ValkyrienSkies.getShipManagingBlock(level, pos);

Use vsApi.xxEvent instead of VSEvents.XxEvent

VSEvents.ShipLoadEvent.on { ev -> }
vsApi.shipLoadEvent.on { ev -> }
VSEvents.ShipLoadEvent.Companion.on(ev -> {});
ValkyrienSkies.api().getShipLoadEvent().on(ev -> {});
Last modified: 03 June 2026