From cc41b1900063da89953c63244ef68ad8c3690a04 Mon Sep 17 00:00:00 2001 From: blockninja124 Date: Fri, 28 Mar 2025 00:13:09 +0000 Subject: [PATCH 1/6] Start re-using some documentation stuff from the unofficial docs https://github.com/alex-s168/vs2-doc --- Writerside/topics/Events.md | 77 +++++ .../topics/The-Attachment-System-Explained.md | 272 ++++++++++++++++-- Writerside/vs.tree | 1 + 3 files changed, 330 insertions(+), 20 deletions(-) create mode 100644 Writerside/topics/Events.md diff --git a/Writerside/topics/Events.md b/Writerside/topics/Events.md new file mode 100644 index 0000000..b539efe --- /dev/null +++ b/Writerside/topics/Events.md @@ -0,0 +1,77 @@ + +# Events +VS2 provides some useful events in `VSEvents` and `VSGameEvents` + +## All events + +`org.valkyrienskies.core.impl.hooks.VSEvents`: + +| Name | Description | Arguments | +| - | - | - | +| `shipLoadEvent` | Will be called once a ship gets (chunk) loaded on the server | `ship: ShipObjectServer` | +| `shipLoadEventClient` | Will be called once a ship gets (chunk) loaded on the client | `ship: ShipObjectClient` | +| `tickEndEvent` | Will be called at the end of the server ticking a world | `world: ShipObjectServerWorld` | + + +`org.valkyrienskies.mod.common.hooks.VSGameEvents`: + +| Name | Description | Arguments | +| - | - |--------------------------------------------| +| `registriesCompleted` | Will be called once the mass & similar registries are filled with data | | +| `tagsAreLoaded` | Will be called after Minecraft tags are loaded | | +| `renderShip` | Will be called before a ship is rendered | `event: VSGameEvents.ShipRenderEvent` | +| `postRenderShip` | Will be called after a ship is rendered | `event: VSGameEvents.ShipRenderEvent` | +| `shipsStartRendering` | Will be called before all ships are rendered | `event: VSGameEvents.ShipStartRenderEvent` | + +## How to listen to events +There is a `on` method in all of those events. Register event listeners to the event through this method. +Its recommended to do this in your mods on-load (init) method. Use it like so: + + + + +```java +[DesiredEvent].Companion.on((event) -> { + // ... +}); +``` + + + + +```kotlin +[DesiredEvent].on {(event) -> { + // ... +}} +``` + + + + +## Example +Print the slug (name) of every ship in a world every tick: + + + + +```java +VSEvents.TickEndEvent.Companion.on((e) -> { + e.getWorld().getAllShips().forEach((ship) -> { + System.out.println(ship.getSlug()); + }); +}); +``` + + + + +```kotlin +VSEvents.tickEndEvent.on { e -> + e.world.allShips.forEach { ship -> + println(ship.slug) + } +} +``` + + + \ No newline at end of file diff --git a/Writerside/topics/The-Attachment-System-Explained.md b/Writerside/topics/The-Attachment-System-Explained.md index 28fe89d..bf1f4b7 100644 --- a/Writerside/topics/The-Attachment-System-Explained.md +++ b/Writerside/topics/The-Attachment-System-Explained.md @@ -1,9 +1,11 @@ + # The Attachment System > Much of the attachment system is marked with `@VsBeta` and may change in the future. > {style="note"} + The **attachment system** is a part of vs-core which addons and third parties can use to attach data to ships and other objects managed by vs-core. @@ -13,39 +15,269 @@ objects managed by vs-core. - You want to persist/serialize data with a ship - You want to apply forces to a ship -## (Optional) Comparison of {(thing being compared)} +## Saving, Loading and removing + +In the package `org.valkyrienskies.core.api.ships` +there are two extension functions for saving and loading attachments. + +To save an attachment you can do: + + + + +```java + serverShip.saveAttachment(MyAttachmentClass.class, new MyAttachmentClass()); +``` + + + + +```kotlin + serverShip.saveAttachment(MyAttachmentClass()) +``` + + + + +And to load the attachment: + + + + +```java +var attachment = serverShip.getAttachment(MyAttachmentClass.class); +``` + + + + +```kotlin +val attachment = serverShip.getAttachment() +``` + + + + +> The attachment class needs to have a constructor without arguments. +> You can use a constructor with arguments for `saveAttachment` if you wish, +> but you still need one without arguments. +> +{style="note"} + +And finally, to remove the attachment: + + + + +```java +serverShip.saveAttachment(MyAttachmentClass.class, null); +``` + + + + +```kotlin +serverShip.saveAttachment(null) +``` + + + + +## Attachment class fields +Every class you use as an attachment needs to follow these rules: + +- All fields that you don't want to be saved in the attachment need to be marked + with `@com.fasterxml.jackson.annotation.JsonIgnore`. This includes ships because otherwise they would recursively save themselves. +- All types of the fields that are not marked with + `@com.fasterxml.jackson.annotation.JsonIgnore` need to be classes with a default + constructor without arguments. This means that you can't use interfaces as types of these fields + +## World "corruption" +If you change anything related to fields that get saved in a ship attachment class, +you will get an error when loading ships with the old data. This is because the ship attachment +class is not compatible with the old data anymore. To fix this, you should create a new ship attachment class +and make the old one copy everything over to the new one, and then delete the old one from a ship. + +To migrate or remove old attachments, +you can register an event listener to migrate ships as soon as they are loaded. +Simply hook into the ShipLoadEvent in your mods on-load (init) method: + +> For ship force inducers, you can also use the `applyForces` method as your event instead. +> +{style="tip"} + + + + +```java +VSEvents.ShipLoadEvent.Companion.on((shipLoadEvent) -> { + ServerShip serverShip = shipLoadEvent.getShip(); + // Update / remove your attachments here +}); +``` + + + + +```kotlin +VSEvents.shipLoadEvent.on {(serverShip) -> { + // Update / remove your attachments here +}} +``` + + + + + +> For more information about events in VS2, go to [Events](Events.md) +> +{style="tip"} + +## Force inducers +To apply forces to a ship, you need a force inducer class. This class will extend the `ShipForcesInducer` interface, +and override the `applyForces(PhysShip)` method. Then, once you save this class as an attachment to a ship, the `applyForces` +method will be called each physics tick. You can then use the PhysShip object in `applyForces` to apply forces to your ship. + +The `ShipForcesInducer` interface class: +```kotlin +package org.valkyrienskies.core.api.ships + +import org.valkyrienskies.core.api.ships.PhysShip +import org.valkyrienskies.core.api.ships.properties.ShipId + +@Deprecated("sus") +interface ShipForcesInducer { + fun applyForces( + physShip: PhysShip + ) + + fun applyForcesAndLookupPhysShips( + physShip: PhysShip, + lookupPhysShip: (ShipId) -> PhysShip? + ) { + // Default implementation to not break existing implementations + } +} +``` +{collapsible="true" collapsed-title="ShipForcesInducer.kt"} + +> VS2 physic ticks run in a different thread than the minecraft server thread. +> This means that you need to be careful when accessing the same fields in applyForces and elsewhere +> +{style="warning" title="Thread Safety"} + +## Examples + +### Ship fuel tracking + + + +```java +import com.fasterxml.jackson.annotation.JsonIgnore; +import org.valkyrienskies.core.api.ships.ServerShip; +import org.valkyrienskies.core.impl.api.ServerShipUser; + +public class ShipFuelStorage { + @JsonIgnore + private ServerShip ship = null; + int fuel = 0; + + public ShipFuelStorage() {} + + public ShipFuelStorage(ServerShip ship) { + this.ship = ship; + } + + public static ShipFuelStorage getOrCreate(ServerShip ship) { + ShipFuelStorage attachment = ship.getAttachment(ShipFuelStorage.class); + if (attachment == null) { + attachment = new ShipFuelStorage(ship); + ship.saveAttachment(ShipFuelStorage.class, attachment); + } + return attachment; + } +} +``` + + + + +```kotlin +import com.fasterxml.jackson.annotation.JsonIgnore +import org.valkyrienskies.core.api.ships.ServerShip +import org.valkyrienskies.core.impl.api.ServerShipUser + +class ShipFuelStorage( + @JsonIgnore + var ship: ServerShip? = null +) { + var fuel: Int = 0 + + companion object { + fun getOrCreate(ship: ServerShip): ShipFuelStorage = + ship.getAttachment() + ?: ShipFuelStorage(ship).also { + ship.saveAttachment(it) + } + } +} +``` -{(Use this section to compare options or alternatives.)} + + -Table: {(Table title which concisely explains the comparison.)} -## (Optional) Related resources +### Ship thruster force inducer -{(Use this section to provide links to documentation related to the concept that the user can read for more information. -If you can name this section manually (it is not generated automatically or has a heading pre-agreed within a team), -we recommend to use "Related concepts" or "Additional information" as more descriptive ones.)} + + -If you would like to dive deeper or start implementing {(concept)}, -check out the following resources: +```java +import org.valkyrienskies.core.api.ships.PhysShip; +import org.valkyrienskies.core.api.ships.ShipForcesInducer; -How-to guides +public class ShipThrusterController implements ShipForcesInducer { -1. Item 1 + @Override + public void applyForces(@NotNull PhysShip physShip) { + // go through each thruster on ship and apply force + } -2. Item 2 + public static ShipThrusterController getOrCreate(ServerShip ship) { + ShipThrusterController attachment = ship.getAttachment(ShipThrusterController.class); + if (attachment == null) { + attachment = new ShipThrusterController(ship); + ship.saveAttachment(ShipThrusterController.class, attachment); + } + return attachment; + } +} +``` -Linked concepts + + -1. Concept 1 +```kotlin +import org.valkyrienskies.core.api.ships.PhysShip +import org.valkyrienskies.core.api.ships.ShipForcesInducer -2. Concept 2 +class ShipThrusterController: ShipForcesInducer { -External resources + override fun applyForces(physShip: PhysShip) { + // go through each thruster on ship and apply force + } -1. Resource 1 + companion object { + fun getOrCreate(ship: ServerShip): ShipThrusterControler = + ship.getAttachment() + ?: ShipThrusterControler().also { + ship.saveAttachment(it) + } + } +} +``` -2. Resource 2 + + ---- -> Explore other templates from [The Good Docs Project](https://thegooddocsproject.dev/). Use our [feedback form](https://thegooddocsproject.dev/feedback/?template=Concept%20template) to give feedback on this template. diff --git a/Writerside/vs.tree b/Writerside/vs.tree index 377b49f..8c7fc56 100644 --- a/Writerside/vs.tree +++ b/Writerside/vs.tree @@ -20,6 +20,7 @@ + From 7216ad2ae123f2354c523c13b595510f284af24e Mon Sep 17 00:00:00 2001 From: blockninja124 Date: Fri, 28 Mar 2025 00:46:42 +0000 Subject: [PATCH 2/6] Add dimension ids and chunk claims. Also add groups to the kotlin-java tabs --- Writerside/topics/Dimension-Ids.md | 58 +++++++++++++++++++ Writerside/topics/Events.md | 12 ++-- Writerside/topics/Ship-Chunk-Claims.md | 56 ++++++++++++++++++ .../topics/The-Attachment-System-Explained.md | 36 ++++++------ Writerside/topics/starter.md | 2 +- Writerside/vs.tree | 2 + 6 files changed, 141 insertions(+), 25 deletions(-) create mode 100644 Writerside/topics/Dimension-Ids.md create mode 100644 Writerside/topics/Ship-Chunk-Claims.md diff --git a/Writerside/topics/Dimension-Ids.md b/Writerside/topics/Dimension-Ids.md new file mode 100644 index 0000000..db8ede7 --- /dev/null +++ b/Writerside/topics/Dimension-Ids.md @@ -0,0 +1,58 @@ +# Dimension IDs +Dimension IDs are slightly different in VS2, so you need to keep that in mind when using vanilla dimension ids + +VS Dimension IDs are in the format `minecraft:dimension:[mod]:[dimension name]`. +To convert this to a `ResourceKey` (which is how Minecraft stores level IDs), you can do this: + + + + +```java +public static ResourceKey VSToDimensionKey(String vsDimId) { + // Split 'minecraft:dimension:namespace:dimension_name' into + // [minecraft, dimension, namespace, dimension_name] + String split = vsDimId.split(":"); + ResourceLocation re = ResourceLocation(split[split.size - 2], split[split.size - 1]) + return ResourceKey.create(Registry.DIMENSION_REGISTRY, rl); +} +``` + + + + +```kotlin +/* DimensionId in VS2 is a type alias for String */ +fun DimensionId.toDimensionKey() { + // Split 'minecraft:dimension:namespace:dimension_name' into + // [minecraft, dimension, namespace, dimension_name] + val split = this.split(":") + val rl = ResourceLocation(split[split.size - 2], split[split.size - 1]) + return ResourceKey.create(Registry.DIMENSION_REGISTRY, rl) +} +``` + + + + +This can now be used to, for example, get the `ServerLevel` of a ship when given a `MinecraftServer` object. Something like: + + + + +```java +public static ServerLevel fromLevelRL(ResourceKey rl) { + return server.getLevel(rl); +} +``` + + + + +```kotlin +fun fromLevelRL(rl: ResourceKey?): ServerLevel { + return server.getLevel(rl) +} +``` + + + \ No newline at end of file diff --git a/Writerside/topics/Events.md b/Writerside/topics/Events.md index b539efe..013edb4 100644 --- a/Writerside/topics/Events.md +++ b/Writerside/topics/Events.md @@ -27,8 +27,8 @@ VS2 provides some useful events in `VSEvents` and `VSGameEvents` There is a `on` method in all of those events. Register event listeners to the event through this method. Its recommended to do this in your mods on-load (init) method. Use it like so: - - + + ```java [DesiredEvent].Companion.on((event) -> { @@ -37,7 +37,7 @@ Its recommended to do this in your mods on-load (init) method. Use it like so: ``` - + ```kotlin [DesiredEvent].on {(event) -> { @@ -51,8 +51,8 @@ Its recommended to do this in your mods on-load (init) method. Use it like so: ## Example Print the slug (name) of every ship in a world every tick: - - + + ```java VSEvents.TickEndEvent.Companion.on((e) -> { @@ -63,7 +63,7 @@ VSEvents.TickEndEvent.Companion.on((e) -> { ``` - + ```kotlin VSEvents.tickEndEvent.on { e -> diff --git a/Writerside/topics/Ship-Chunk-Claims.md b/Writerside/topics/Ship-Chunk-Claims.md new file mode 100644 index 0000000..b1b3069 --- /dev/null +++ b/Writerside/topics/Ship-Chunk-Claims.md @@ -0,0 +1,56 @@ +# Ship Chunk Claims +Every ship has a chunk claim. +This chunk claim specifies what section of the shipyard the ship "owns". +Currently, chunk claims are hardcoded to 256 by 256 chunks, so ships can't be bigger than that. + +## `chunkClaim` field in `Ship` +The function +```kotlin +fun getTotalVoxelRegion(yRange: LevelYRange, destination: AABBi = AABBi()): AABBi +``` +in `ChunkClaim` can be used to get the AABB of the chunk claim (= Shipyard area) +It takes an argument of the type `LevelYRange` which can be easily created from a level: + + + + +```java +new LevelYRange(level.getMinBuildHeight(), level.getMaxBuildHeight()); +``` + + + + +```kotlin +LevelYRange(level.minBuildHeight, level.maxBuildHeight) +``` + + + + +This creates a Y-Range using the build height of the level given. + +## `chunkClaimDimension` field in `Ship` + + + + +```java +String dim = ship.getChunkClaimDimension(); +``` + + + + +```kotlin +var dim = ship.chunkClaimDimension +``` + + + + +The dimension ID of the chunk claim. + +The ship always has to be in the same dimension as the chunk claim, so this is also the dimension ID of the ship. + +You can find more information about dimension IDs [here](Dimension-Ids.md) \ No newline at end of file diff --git a/Writerside/topics/The-Attachment-System-Explained.md b/Writerside/topics/The-Attachment-System-Explained.md index bf1f4b7..517ecea 100644 --- a/Writerside/topics/The-Attachment-System-Explained.md +++ b/Writerside/topics/The-Attachment-System-Explained.md @@ -22,15 +22,15 @@ there are two extension functions for saving and loading attachments. To save an attachment you can do: - - + + ```java serverShip.saveAttachment(MyAttachmentClass.class, new MyAttachmentClass()); ``` - + ```kotlin serverShip.saveAttachment(MyAttachmentClass()) @@ -41,15 +41,15 @@ To save an attachment you can do: And to load the attachment: - - + + ```java var attachment = serverShip.getAttachment(MyAttachmentClass.class); ``` - + ```kotlin val attachment = serverShip.getAttachment() @@ -66,15 +66,15 @@ val attachment = serverShip.getAttachment() And finally, to remove the attachment: - - + + ```java serverShip.saveAttachment(MyAttachmentClass.class, null); ``` - + ```kotlin serverShip.saveAttachment(null) @@ -106,8 +106,8 @@ Simply hook into the ShipLoadEvent in your mods on-load (init) method: > {style="tip"} - - + + ```java VSEvents.ShipLoadEvent.Companion.on((shipLoadEvent) -> { @@ -117,7 +117,7 @@ VSEvents.ShipLoadEvent.Companion.on((shipLoadEvent) -> { ``` - + ```kotlin VSEvents.shipLoadEvent.on {(serverShip) -> { @@ -169,8 +169,8 @@ interface ShipForcesInducer { ## Examples ### Ship fuel tracking - - + + ```java import com.fasterxml.jackson.annotation.JsonIgnore; @@ -200,7 +200,7 @@ public class ShipFuelStorage { ``` - + ```kotlin import com.fasterxml.jackson.annotation.JsonIgnore @@ -229,8 +229,8 @@ class ShipFuelStorage( ### Ship thruster force inducer - - + + ```java import org.valkyrienskies.core.api.ships.PhysShip; @@ -255,7 +255,7 @@ public class ShipThrusterController implements ShipForcesInducer { ``` - + ```kotlin import org.valkyrienskies.core.api.ships.PhysShip diff --git a/Writerside/topics/starter.md b/Writerside/topics/starter.md index b24eda4..9b8daf4 100644 --- a/Writerside/topics/starter.md +++ b/Writerside/topics/starter.md @@ -31,7 +31,7 @@ For example, this is how you inject a procedure: ### Tabs To add switchable content, you can make use of tabs (inject them by starting to type `tab` on a new line): - + ![Alt Text](new_topic_options.png){ width=450 } diff --git a/Writerside/vs.tree b/Writerside/vs.tree index 8c7fc56..86638bc 100644 --- a/Writerside/vs.tree +++ b/Writerside/vs.tree @@ -21,6 +21,8 @@ + + From 20bb63b6bd5afcf615a977710fac3c8a1b8bb5d7 Mon Sep 17 00:00:00 2001 From: blockninja124 Date: Fri, 28 Mar 2025 16:32:51 +0000 Subject: [PATCH 3/6] Organise the pages a bit --- Writerside/topics/{ => concepts}/Joints.md | 0 Writerside/topics/{ => concepts}/Ship-Chunk-Claims.md | 0 Writerside/topics/{ => concepts}/The-Shipyard.md | 7 +++++-- Writerside/topics/{ => docs}/Dimension-Ids.md | 0 Writerside/topics/{ => docs}/Events.md | 0 .../topics/{ => docs}/The-Attachment-System-Explained.md | 0 .../How-to-get-a-ship-from-a-block.md} | 6 ++++-- .../How-to-transform-coordinates-from-shipyard-to-world.md | 0 Writerside/topics/{ => todo}/Compatibility.md | 0 Writerside/topics/{ => todo}/Dependency-Architecture.md | 0 .../How-Valkyrien-Skies-Works-From-a-Birds-Eye.md | 0 Writerside/topics/{ => todo}/starter.md | 0 Writerside/vs.tree | 4 +++- 13 files changed, 12 insertions(+), 5 deletions(-) rename Writerside/topics/{ => concepts}/Joints.md (100%) rename Writerside/topics/{ => concepts}/Ship-Chunk-Claims.md (100%) rename Writerside/topics/{ => concepts}/The-Shipyard.md (94%) rename Writerside/topics/{ => docs}/Dimension-Ids.md (100%) rename Writerside/topics/{ => docs}/Events.md (100%) rename Writerside/topics/{ => docs}/The-Attachment-System-Explained.md (100%) rename Writerside/topics/{How-to-get-the-ship-managing-a-shipyard-position.md => guides/How-to-get-a-ship-from-a-block.md} (60%) rename Writerside/topics/{ => guides}/How-to-transform-coordinates-from-shipyard-to-world.md (100%) rename Writerside/topics/{ => todo}/Compatibility.md (100%) rename Writerside/topics/{ => todo}/Dependency-Architecture.md (100%) rename Writerside/topics/{ => todo}/How-Valkyrien-Skies-Works-From-a-Birds-Eye.md (100%) rename Writerside/topics/{ => todo}/starter.md (100%) diff --git a/Writerside/topics/Joints.md b/Writerside/topics/concepts/Joints.md similarity index 100% rename from Writerside/topics/Joints.md rename to Writerside/topics/concepts/Joints.md diff --git a/Writerside/topics/Ship-Chunk-Claims.md b/Writerside/topics/concepts/Ship-Chunk-Claims.md similarity index 100% rename from Writerside/topics/Ship-Chunk-Claims.md rename to Writerside/topics/concepts/Ship-Chunk-Claims.md diff --git a/Writerside/topics/The-Shipyard.md b/Writerside/topics/concepts/The-Shipyard.md similarity index 94% rename from Writerside/topics/The-Shipyard.md rename to Writerside/topics/concepts/The-Shipyard.md index 6e939d4..8db61c1 100644 --- a/Writerside/topics/The-Shipyard.md +++ b/Writerside/topics/concepts/The-Shipyard.md @@ -83,5 +83,8 @@ from existing performance mods like Lithium and Sodium. ## Chunk claims -In the shipyard, each ship is assigned a **chunk claim** inside the shipyard. In VS2, each chunk claim is 256x256 -chunks. The chunks in the chunk claim are then "projected" into the world using the corresponding ship's transform. \ No newline at end of file +In the shipyard, each ship is assigned a **chunk claim**. +The chunks in the chunk claim are then "projected" into the world using the ship's transform. +> See [Ship Chunk Claims](Ship-Chunk-Claims.md) for more info on how chunk claims are used +> +{style="note"} \ No newline at end of file diff --git a/Writerside/topics/Dimension-Ids.md b/Writerside/topics/docs/Dimension-Ids.md similarity index 100% rename from Writerside/topics/Dimension-Ids.md rename to Writerside/topics/docs/Dimension-Ids.md diff --git a/Writerside/topics/Events.md b/Writerside/topics/docs/Events.md similarity index 100% rename from Writerside/topics/Events.md rename to Writerside/topics/docs/Events.md diff --git a/Writerside/topics/The-Attachment-System-Explained.md b/Writerside/topics/docs/The-Attachment-System-Explained.md similarity index 100% rename from Writerside/topics/The-Attachment-System-Explained.md rename to Writerside/topics/docs/The-Attachment-System-Explained.md diff --git a/Writerside/topics/How-to-get-the-ship-managing-a-shipyard-position.md b/Writerside/topics/guides/How-to-get-a-ship-from-a-block.md similarity index 60% rename from Writerside/topics/How-to-get-the-ship-managing-a-shipyard-position.md rename to Writerside/topics/guides/How-to-get-a-ship-from-a-block.md index fbb5a0a..d0076fe 100644 --- a/Writerside/topics/How-to-get-the-ship-managing-a-shipyard-position.md +++ b/Writerside/topics/guides/How-to-get-a-ship-from-a-block.md @@ -1,6 +1,8 @@ -# How to get the ship managing a shipyard position +# How to get a ship from a block -Every ship has a chunk claim in the [shipyard](The-Shipyard.md) which contains the ship's chunks. +Every ship has a [chunk claim](Ship-Chunk-Claims.md) in the [shipyard](The-Shipyard.md) which contains the ship's blocks. +If you are given one of these shipyard blocks, for example if a `level.clip()` hits a ship, you may need to get the Ship +object so that you can transform that shipyard position back to a world position. > **Highlight important information** > diff --git a/Writerside/topics/How-to-transform-coordinates-from-shipyard-to-world.md b/Writerside/topics/guides/How-to-transform-coordinates-from-shipyard-to-world.md similarity index 100% rename from Writerside/topics/How-to-transform-coordinates-from-shipyard-to-world.md rename to Writerside/topics/guides/How-to-transform-coordinates-from-shipyard-to-world.md diff --git a/Writerside/topics/Compatibility.md b/Writerside/topics/todo/Compatibility.md similarity index 100% rename from Writerside/topics/Compatibility.md rename to Writerside/topics/todo/Compatibility.md diff --git a/Writerside/topics/Dependency-Architecture.md b/Writerside/topics/todo/Dependency-Architecture.md similarity index 100% rename from Writerside/topics/Dependency-Architecture.md rename to Writerside/topics/todo/Dependency-Architecture.md diff --git a/Writerside/topics/How-Valkyrien-Skies-Works-From-a-Birds-Eye.md b/Writerside/topics/todo/How-Valkyrien-Skies-Works-From-a-Birds-Eye.md similarity index 100% rename from Writerside/topics/How-Valkyrien-Skies-Works-From-a-Birds-Eye.md rename to Writerside/topics/todo/How-Valkyrien-Skies-Works-From-a-Birds-Eye.md diff --git a/Writerside/topics/starter.md b/Writerside/topics/todo/starter.md similarity index 100% rename from Writerside/topics/starter.md rename to Writerside/topics/todo/starter.md diff --git a/Writerside/vs.tree b/Writerside/vs.tree index 86638bc..d16c278 100644 --- a/Writerside/vs.tree +++ b/Writerside/vs.tree @@ -19,9 +19,11 @@ + + + - From 3f79f9c476570d54969b1d33f2aad1de4bec823e Mon Sep 17 00:00:00 2001 From: blockninja124 Date: Fri, 28 Mar 2025 18:03:19 +0000 Subject: [PATCH 4/6] Remove some errors --- Writerside/topics/How-to-migrate-to-VS-2.5.md | 2 +- Writerside/topics/Section-Starting-Page.topic | 4 ++-- Writerside/topics/docs/Dimension-Ids.md | 2 +- Writerside/topics/docs/Events.md | 22 +++++++++---------- Writerside/vs.tree | 3 ++- 5 files changed, 17 insertions(+), 16 deletions(-) diff --git a/Writerside/topics/How-to-migrate-to-VS-2.5.md b/Writerside/topics/How-to-migrate-to-VS-2.5.md index b1360a8..ed138ef 100644 --- a/Writerside/topics/How-to-migrate-to-VS-2.5.md +++ b/Writerside/topics/How-to-migrate-to-VS-2.5.md @@ -137,7 +137,7 @@ final class MyAttachment { ### Migrate from constraints to joints -> Try to avoid using `apigame` - we don't make any [backwards compatibility](Compatibility.md#backwards-compatibility) +> Try to avoid using `apigame` - we don't make any [backwards compatibility](todo/Compatibility.md#backwards-compatibility) > guarantees for it. > {style="warning"} diff --git a/Writerside/topics/Section-Starting-Page.topic b/Writerside/topics/Section-Starting-Page.topic index 89e11c2..eefad36 100644 --- a/Writerside/topics/Section-Starting-Page.topic +++ b/Writerside/topics/Section-Starting-Page.topic @@ -23,8 +23,8 @@ - Custom card title - Another custom title + Getting started + Migrating to VS 2.5 diff --git a/Writerside/topics/docs/Dimension-Ids.md b/Writerside/topics/docs/Dimension-Ids.md index db8ede7..2da9b7a 100644 --- a/Writerside/topics/docs/Dimension-Ids.md +++ b/Writerside/topics/docs/Dimension-Ids.md @@ -12,7 +12,7 @@ public static ResourceKey VSToDimensionKey(String vsDimId) { // Split 'minecraft:dimension:namespace:dimension_name' into // [minecraft, dimension, namespace, dimension_name] String split = vsDimId.split(":"); - ResourceLocation re = ResourceLocation(split[split.size - 2], split[split.size - 1]) + ResourceLocation re = ResourceLocation(split[split.size - 2], split[split.size - 1]); return ResourceKey.create(Registry.DIMENSION_REGISTRY, rl); } ``` diff --git a/Writerside/topics/docs/Events.md b/Writerside/topics/docs/Events.md index 013edb4..e660c79 100644 --- a/Writerside/topics/docs/Events.md +++ b/Writerside/topics/docs/Events.md @@ -6,22 +6,22 @@ VS2 provides some useful events in `VSEvents` and `VSGameEvents` `org.valkyrienskies.core.impl.hooks.VSEvents`: -| Name | Description | Arguments | -| - | - | - | -| `shipLoadEvent` | Will be called once a ship gets (chunk) loaded on the server | `ship: ShipObjectServer` | -| `shipLoadEventClient` | Will be called once a ship gets (chunk) loaded on the client | `ship: ShipObjectClient` | -| `tickEndEvent` | Will be called at the end of the server ticking a world | `world: ShipObjectServerWorld` | +| Name | Description | Arguments | +|-----------------------|--------------------------------------------------------------|--------------------------------| +| `shipLoadEvent` | Will be called once a ship gets (chunk) loaded on the server | `ship: ShipObjectServer` | +| `shipLoadEventClient` | Will be called once a ship gets (chunk) loaded on the client | `ship: ShipObjectClient` | +| `tickEndEvent` | Will be called at the end of the server ticking a world | `world: ShipObjectServerWorld` | `org.valkyrienskies.mod.common.hooks.VSGameEvents`: -| Name | Description | Arguments | -| - | - |--------------------------------------------| +| Name | Description | Arguments | +|-----------------------|------------------------------------------------------------------------|--------------------------------------------| | `registriesCompleted` | Will be called once the mass & similar registries are filled with data | | -| `tagsAreLoaded` | Will be called after Minecraft tags are loaded | | -| `renderShip` | Will be called before a ship is rendered | `event: VSGameEvents.ShipRenderEvent` | -| `postRenderShip` | Will be called after a ship is rendered | `event: VSGameEvents.ShipRenderEvent` | -| `shipsStartRendering` | Will be called before all ships are rendered | `event: VSGameEvents.ShipStartRenderEvent` | +| `tagsAreLoaded` | Will be called after Minecraft tags are loaded | | +| `renderShip` | Will be called before a ship is rendered | `event: VSGameEvents.ShipRenderEvent` | +| `postRenderShip` | Will be called after a ship is rendered | `event: VSGameEvents.ShipRenderEvent` | +| `shipsStartRendering` | Will be called before all ships are rendered | `event: VSGameEvents.ShipStartRenderEvent` | ## How to listen to events There is a `on` method in all of those events. Register event listeners to the event through this method. diff --git a/Writerside/vs.tree b/Writerside/vs.tree index d16c278..25aeeeb 100644 --- a/Writerside/vs.tree +++ b/Writerside/vs.tree @@ -8,7 +8,7 @@ - + @@ -24,6 +24,7 @@ + From 22be474bbcbb12e3e86a5979ffa73619eeac62b5 Mon Sep 17 00:00:00 2001 From: blockninja124 Date: Fri, 28 Mar 2025 20:37:15 +0000 Subject: [PATCH 5/6] Remove networking --- Writerside/vs.tree | 1 - 1 file changed, 1 deletion(-) diff --git a/Writerside/vs.tree b/Writerside/vs.tree index 25aeeeb..1ff24a0 100644 --- a/Writerside/vs.tree +++ b/Writerside/vs.tree @@ -24,7 +24,6 @@ - From 7af2180680e872f2a9e2d10e77acc774317e9804 Mon Sep 17 00:00:00 2001 From: blockninja124 Date: Wed, 16 Apr 2025 18:27:45 +0100 Subject: [PATCH 6/6] Update ship attachments page to 2.5 api --- ...ained.md => Ship-Attachments-Pre-2.5.0.md} | 20 +- Writerside/topics/docs/Ship-Attachments.md | 367 ++++++++++++++++++ Writerside/vs.tree | 3 +- 3 files changed, 375 insertions(+), 15 deletions(-) rename Writerside/topics/docs/{The-Attachment-System-Explained.md => Ship-Attachments-Pre-2.5.0.md} (94%) create mode 100644 Writerside/topics/docs/Ship-Attachments.md diff --git a/Writerside/topics/docs/The-Attachment-System-Explained.md b/Writerside/topics/docs/Ship-Attachments-Pre-2.5.0.md similarity index 94% rename from Writerside/topics/docs/The-Attachment-System-Explained.md rename to Writerside/topics/docs/Ship-Attachments-Pre-2.5.0.md index 517ecea..bb6481a 100644 --- a/Writerside/topics/docs/The-Attachment-System-Explained.md +++ b/Writerside/topics/docs/Ship-Attachments-Pre-2.5.0.md @@ -1,19 +1,12 @@ +# The Attachment System (Pre-VS 2.5.0) -# The Attachment System - -> Much of the attachment system is marked with `@VsBeta` and may change in the future. -> -{style="note"} +This page is just for information on attachments in VS 2.3.0, +mostly for addon development while 2.5.0 is still in development. +You can view more up-to-date information on the ship attachment system [here](Ship-Attachments.md). -The **attachment system** is a part of vs-core which addons and third parties can use to attach data to ships and other -objects managed by vs-core. - -## Use cases - -- You want to associate some data with a ship temporarily -- You want to persist/serialize data with a ship -- You want to apply forces to a ship +Also check out [Migrating to VS 2.5.0](How-to-migrate-to-VS-2.5.md) for how to update your 2.3 +attachments to VS 2.5 ## Saving, Loading and removing @@ -280,4 +273,3 @@ class ShipThrusterController: ShipForcesInducer { - diff --git a/Writerside/topics/docs/Ship-Attachments.md b/Writerside/topics/docs/Ship-Attachments.md new file mode 100644 index 0000000..382c623 --- /dev/null +++ b/Writerside/topics/docs/Ship-Attachments.md @@ -0,0 +1,367 @@ +# The Attachment System + +> Much of the attachment system is marked with `@VsBeta` and may change in the future. +> +{style="note"} + + +The **attachment system** is a part of vs-core which addons and third parties can use to attach data to ships and other +objects managed by vs-core. + +## Use cases + +- You want to associate some data with a ship temporarily +- You want to persist/serialize data with a ship +- You want to apply forces to a ship + +> You can view the documentation for ship attachments pre-VS 2.5.0 [here](Ship-Attachments-Pre-2.5.0.md) +> +{style="tip"} + +## Registering your attachment + + + +Setup your attachment class. This must be a `final` class, but it doesn't need to extend/implement anything. +(Unless your making a force inducer). + + + Make sure your class has a constructor with no arguments. + +

Example minimum class:

+ + + + ```java + public final class MyAttachment { + public MyAttachment() {} + } + ``` + + + + + ```kotlin + class MyAttachment() { + + } + ``` + + + + + Register your attachment (usually in your mod constructor) + + + + ```java +AttachmentRegistration registration = ValkyrienSkies.api() + .newAttachmentRegistrationBuilder(MyAttachment.class) + // Use if your migrating a pre-2.5 attachment + .useLegacySerializer() + .build(); + +ValkyrienSkies.api().registerAttachment(registration); + ``` + + + + + ```kotlin +vsApi.registerAttachment(MyAttachment::class.java) { + // Use if your migrating a pre-2.5 attachment + useLegacySerializer() +} + ``` + + + +
+ + + + +## Saving, Loading and removing + +In the package `org.valkyrienskies.core.api.attachments` +there are two extension functions for saving and loading attachments. + +> You can only get and save attachments from a LoadedServerShip +> +{style="warning"} + +To save an attachment you can do: + + + + +```java + ServerShip ship = ... + if (ship instanceof LoadedServerShip loadedShip) { + loadedShip.setAttachment(MyAttachment.class, new MyAttachment()); + } +``` + + + + +```kotlin +val ship: ServerShip = ... +if (ship is LoadedServerShip) { + ship.setAttachment(MyAttachment()) +} +``` + + + + +And to load the attachment: + + + + +```java +ServerShip ship = ... +if (ship instanceof LoadedServerShip loadedShip) { + var attachment = serverShip.getAttachment(MyAttachment.class); +} +``` + + + + +```kotlin +val attachment = serverShip.getAttachment() +``` + + + + +> The attachment class needs to have a constructor without arguments. +> You can use a constructor with arguments for `setAttachment` if you wish, +> but you still need one without arguments. +> +{style="note"} + +And finally, to remove the attachment: + + + + +```java +ServerShip ship = ... +if (ship instanceof LoadedServerShip loadedShip) { + loadedShip.setAttachment(MyAttachment.class, null); +} +``` + + + + +```kotlin +val ship: ServerShip = ... +if (ship is LoadedServerShip) { + ship.setAttachment(null) +} +``` + + + + +## Attachment class fields +Every class you use as an attachment needs to follow these rules: + +- All fields that you don't want to be saved in the attachment need to be marked + with `@com.fasterxml.jackson.annotation.JsonIgnore`. This includes ships because otherwise they would recursively save themselves. +- All types of the fields that are not marked with + `@com.fasterxml.jackson.annotation.JsonIgnore` need to be classes with a default + constructor without arguments. This means that you can't use interfaces as types of these fields + +## World "corruption" +If you change anything related to fields that get saved in a ship attachment class, +you will get an error when loading ships with the old data. This is because the ship attachment +class is not compatible with the old data anymore. To fix this, you should create a new ship attachment class +and make the old one copy everything over to the new one, and then delete the old one from a ship. + +To migrate or remove old attachments, +you can register an event listener to migrate ships as soon as they are loaded. +Simply hook into the ShipLoadEvent in your mods on-load (init) method: + +> For ship force inducers, you can also use the `applyForces` method as your event instead. +> +{style="tip"} + + + + +```java +VSEvents.ShipLoadEvent.Companion.on((shipLoadEvent) -> { + ServerShip serverShip = shipLoadEvent.getShip(); + // Update / remove your attachments here +}); +``` + + + + +```kotlin +VSEvents.shipLoadEvent.on {(serverShip) -> { + // Update / remove your attachments here +}} +``` + + + + + +> For more information about events in VS2, go to [Events](Events.md) +> +{style="tip"} + +## Force inducers +To apply forces to a ship, you need a force inducer class. This class will extend the `ShipForcesInducer` interface, +and override the `applyForces(PhysShip)` method. Then, once you save this class as an attachment to a ship, the `applyForces` +method will be called each physics tick. You can then use the PhysShip object in `applyForces` to apply forces to your ship. + +The `ShipForcesInducer` interface class: +```kotlin +package org.valkyrienskies.core.api.ships + +import org.valkyrienskies.core.api.ships.PhysShip +import org.valkyrienskies.core.api.ships.properties.ShipId + +@Deprecated("sus") +interface ShipForcesInducer { + fun applyForces( + physShip: PhysShip + ) + + fun applyForcesAndLookupPhysShips( + physShip: PhysShip, + lookupPhysShip: (ShipId) -> PhysShip? + ) { + // Default implementation to not break existing implementations + } +} +``` +{collapsible="true" collapsed-title="ShipForcesInducer.kt"} + +> VS2 physic ticks run in a different thread than the minecraft server thread. +> This means that you need to be careful when accessing the same fields in applyForces and elsewhere +> +{style="warning" title="Thread Safety"} + +## Examples + +### Ship fuel tracking + + + +```java +import com.fasterxml.jackson.annotation.JsonIgnore; +import org.valkyrienskies.core.api.ships.ServerShip; +import org.valkyrienskies.core.impl.api.ServerShipUser; + +public final class ShipFuelStorage { + @JsonIgnore + private LoadedServerShip ship = null; + int fuel = 0; + + public ShipFuelStorage() {} + + public ShipFuelStorage(LoadedServerShip ship) { + this.ship = ship; + } + + public static ShipFuelStorage getOrCreate(LoadedServerShip ship) { + ShipFuelStorage attachment = ship.getAttachment(ShipFuelStorage.class); + if (attachment == null) { + attachment = new ShipFuelStorage(ship); + ship.setAttachment(ShipFuelStorage.class, attachment); + } + return attachment; + } +} +``` + + + + +```kotlin +import com.fasterxml.jackson.annotation.JsonIgnore +import org.valkyrienskies.core.api.ships.ServerShip +import org.valkyrienskies.core.impl.api.ServerShipUser + +class ShipFuelStorage( + @JsonIgnore + var ship: LoadedServerShip? = null +) { + var fuel: Int = 0 + + companion object { + fun getOrCreate(ship: LoadedServerShip): ShipFuelStorage = + ship.getAttachment() + ?: ShipFuelStorage(ship).also { + ship.setAttachment(it) + } + } +} +``` + + + + + +### Ship thruster force inducer + + + + +```java +import org.valkyrienskies.core.api.ships.PhysShip; +import org.valkyrienskies.core.api.ships.ShipForcesInducer; + +public class ShipThrusterController implements ShipForcesInducer { + + @Override + public void applyForces(@NotNull PhysShip physShip) { + // go through each thruster on ship and apply force + } + + public static ShipThrusterController getOrCreate(ServerShip ship) { + ShipThrusterController attachment = ship.getAttachment(ShipThrusterController.class); + if (attachment == null) { + attachment = new ShipThrusterController(ship); + ship.saveAttachment(ShipThrusterController.class, attachment); + } + return attachment; + } +} +``` + + + + +```kotlin +import org.valkyrienskies.core.api.ships.PhysShip +import org.valkyrienskies.core.api.ships.ShipForcesInducer + +class ShipThrusterController: ShipForcesInducer { + + override fun applyForces(physShip: PhysShip) { + // go through each thruster on ship and apply force + } + + companion object { + fun getOrCreate(ship: ServerShip): ShipThrusterControler = + ship.getAttachment() + ?: ShipThrusterControler().also { + ship.saveAttachment(it) + } + } +} +``` + + + + diff --git a/Writerside/vs.tree b/Writerside/vs.tree index 1ff24a0..15ba4cb 100644 --- a/Writerside/vs.tree +++ b/Writerside/vs.tree @@ -22,7 +22,7 @@ - + @@ -32,4 +32,5 @@ +