From f3cbcf78bb59737d383b749348fc0e7962deadea Mon Sep 17 00:00:00 2001 From: Jacob <124112219+jacobwojoski@users.noreply.github.com> Date: Fri, 30 Jan 2026 13:43:07 -0500 Subject: [PATCH 1/6] Update example-ecs-plugin.mdx Update the plugin to store the componentType in the component class. Also add in a component codec builder to allow component storage to disk. --- .../docs/en/guides/ecs/example-ecs-plugin.mdx | 50 ++++++++++++++++--- 1 file changed, 44 insertions(+), 6 deletions(-) diff --git a/content/docs/en/guides/ecs/example-ecs-plugin.mdx b/content/docs/en/guides/ecs/example-ecs-plugin.mdx index 781124c5..84912b3a 100644 --- a/content/docs/en/guides/ecs/example-ecs-plugin.mdx +++ b/content/docs/en/guides/ecs/example-ecs-plugin.mdx @@ -4,6 +4,8 @@ description: "In this guide you will learn how to create a simple poison system authors: - name: "oskarscot" url: "https://oskar.scot" + - name: "jacobwojoski" + url: "https://github.com/jacobwojoski" --- ## Practical Example: Poison System @@ -25,6 +27,43 @@ public class PoisonComponent implements Component { private int remainingTicks; private float elapsedTime; + // Add static getter and setter to store componentType in the component instead of getting it from the plugin singleton. + // - This allows anyone to call PoisonComponent.getComponentType() instead of ExamplePlugin.get().getPoisonComponentType(); + ComponentType type; + public static ComponentType getComponentType(){ + return this.type; + } + public static void setComponentType(ComponentType type){ + this.type = type; + } + + // A builder codec is needed to allow components to be saved and loaded from disk + public static final BuilderCodec CODEC = BuilderCodec + .builder(PoisonComponent.class, PoisonComponent::new) + .append( + new KeyedCodec<>("DamagePerTick", Codec.FLOAT), + (component, value) -> component.damagePerTick = value, + component -> component.damagePerTick + ).add() + .append( + new KeyedCodec<>("TickInterval", Codec.FLOAT), + (component, value) -> component.tickInterval = value, + component -> component.tickInterval + ).add() + .append( + new KeyedCodec<>("RemainingTicks", Codec.INTEGER), + (component, value) -> component.remainingTicks = value, + component -> component.remainingTicks + ) + .add() + .append( + new KeyedCodec<>("ElapsedTime", Codec.FLOAT), + (component, value) -> component.elapsedTime = value, + component -> component.elapsedTime + ) + .add() + .build(); + public PoisonComponent() { this(5f, 1.0f, 10); } @@ -115,6 +154,7 @@ public class PoisonSystem extends EntityTickingSystem { public void tick(float dt, int index, @Nonnull ArchetypeChunk archetypeChunk, @Nonnull Store store, @Nonnull CommandBuffer commandBuffer) { + // You could also just call PoisonComponent.getComponentType() instead of taking in the passed in variable here. PoisonComponent poison = archetypeChunk.getComponent(index, poisonComponentType); Ref ref = archetypeChunk.getReferenceTo(index); @@ -162,7 +202,7 @@ public class ExampleCommand extends AbstractPlayerCommand { @Nonnull Ref ref, @Nonnull PlayerRef playerRef, @Nonnull World world) { Player player = store.getComponent(ref, Player.getComponentType()); PoisonComponent poison = new PoisonComponent(3f, 0.5f, 8); - store.addComponent(ref, ExamplePlugin.get().getPoisonComponentType(), poison); + store.addComponent(ref, PoisonComponent.getComponentType(), poison); player.sendMessage(Message.raw("You have been poisoned!").color(Color.GREEN).bold(true)); } } @@ -187,13 +227,11 @@ public final class ExamplePlugin extends JavaPlugin { this.getEventRegistry().registerGlobal(PlayerReadyEvent.class, ExampleEvent::onPlayerReady); this.getEventRegistry().registerGlobal(PlayerChatEvent.class, ChatFormatter::onPlayerChat); - this.poisonComponent = this.getEntityStoreRegistry() + ComponentType poisonComponentType = this.getEntityStoreRegistry() .registerComponent(PoisonComponent.class, PoisonComponent::new); - this.getEntityStoreRegistry().registerSystem(new PoisonSystem(this.poisonComponent)); - } + PoisonComponent.setComponentType(poisonComponentType); - public ComponentType getPoisonComponentType() { - return poisonComponent; + this.getEntityStoreRegistry().registerSystem(new PoisonSystem(this.poisonComponent)); } public static ExamplePlugin get() { From 483f2c9985a3510100353b5715e850fd823f9cb1 Mon Sep 17 00:00:00 2001 From: Jacob <124112219+jacobwojoski@users.noreply.github.com> Date: Fri, 30 Jan 2026 13:47:47 -0500 Subject: [PATCH 2/6] fix: Add a few additional comments Add a few additional comments --- content/docs/en/guides/ecs/example-ecs-plugin.mdx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/content/docs/en/guides/ecs/example-ecs-plugin.mdx b/content/docs/en/guides/ecs/example-ecs-plugin.mdx index 84912b3a..a57027b1 100644 --- a/content/docs/en/guides/ecs/example-ecs-plugin.mdx +++ b/content/docs/en/guides/ecs/example-ecs-plugin.mdx @@ -29,7 +29,8 @@ public class PoisonComponent implements Component { // Add static getter and setter to store componentType in the component instead of getting it from the plugin singleton. // - This allows anyone to call PoisonComponent.getComponentType() instead of ExamplePlugin.get().getPoisonComponentType(); - ComponentType type; + // - You could also update the setter to be a singleton if desired. + private static ComponentType type; public static ComponentType getComponentType(){ return this.type; } @@ -214,7 +215,6 @@ package scot.oskar.hytaletemplate; public final class ExamplePlugin extends JavaPlugin { private static ExamplePlugin instance; - private ComponentType poisonComponent; public ExamplePlugin(@Nonnull JavaPluginInit init) { super(init); @@ -227,6 +227,7 @@ public final class ExamplePlugin extends JavaPlugin { this.getEventRegistry().registerGlobal(PlayerReadyEvent.class, ExampleEvent::onPlayerReady); this.getEventRegistry().registerGlobal(PlayerChatEvent.class, ChatFormatter::onPlayerChat); + // Register the component & set the type in the component class so its easier to retrieve. ComponentType poisonComponentType = this.getEntityStoreRegistry() .registerComponent(PoisonComponent.class, PoisonComponent::new); PoisonComponent.setComponentType(poisonComponentType); From 8284d30a2510e655d026fa00f78e1f9388a67b54 Mon Sep 17 00:00:00 2001 From: Jacob <124112219+jacobwojoski@users.noreply.github.com> Date: Fri, 30 Jan 2026 13:59:45 -0500 Subject: [PATCH 3/6] fix: Add comment Add aditional comment about throw comdition --- content/docs/en/guides/ecs/example-ecs-plugin.mdx | 1 + 1 file changed, 1 insertion(+) diff --git a/content/docs/en/guides/ecs/example-ecs-plugin.mdx b/content/docs/en/guides/ecs/example-ecs-plugin.mdx index a57027b1..9571161c 100644 --- a/content/docs/en/guides/ecs/example-ecs-plugin.mdx +++ b/content/docs/en/guides/ecs/example-ecs-plugin.mdx @@ -30,6 +30,7 @@ public class PoisonComponent implements Component { // Add static getter and setter to store componentType in the component instead of getting it from the plugin singleton. // - This allows anyone to call PoisonComponent.getComponentType() instead of ExamplePlugin.get().getPoisonComponentType(); // - You could also update the setter to be a singleton if desired. + // - Adding a throw condition if getComponentType() returns null could also be good. private static ComponentType type; public static ComponentType getComponentType(){ return this.type; From f1cfdd09b2ee811cc058b9cafbd7f79f0c3a9323 Mon Sep 17 00:00:00 2001 From: Jacob <124112219+jacobwojoski@users.noreply.github.com> Date: Fri, 30 Jan 2026 14:10:04 -0500 Subject: [PATCH 4/6] fix: Forgot to remove this call to poisoncomponent Fix this call to comp thats not local anymore --- content/docs/en/guides/ecs/example-ecs-plugin.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/docs/en/guides/ecs/example-ecs-plugin.mdx b/content/docs/en/guides/ecs/example-ecs-plugin.mdx index 9571161c..31f8235c 100644 --- a/content/docs/en/guides/ecs/example-ecs-plugin.mdx +++ b/content/docs/en/guides/ecs/example-ecs-plugin.mdx @@ -233,7 +233,7 @@ public final class ExamplePlugin extends JavaPlugin { .registerComponent(PoisonComponent.class, PoisonComponent::new); PoisonComponent.setComponentType(poisonComponentType); - this.getEntityStoreRegistry().registerSystem(new PoisonSystem(this.poisonComponent)); + this.getEntityStoreRegistry().registerSystem(new PoisonSystem(PoisonComponent.getComponentType())); } public static ExamplePlugin get() { From bee7627f6a13c00c6c6e0bc878b0cb4f66a25eff Mon Sep 17 00:00:00 2001 From: Jacob <124112219+jacobwojoski@users.noreply.github.com> Date: Tue, 10 Feb 2026 13:22:45 -0500 Subject: [PATCH 5/6] Update example-ecs-plugin.mdx --- content/docs/en/guides/ecs/example-ecs-plugin.mdx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/content/docs/en/guides/ecs/example-ecs-plugin.mdx b/content/docs/en/guides/ecs/example-ecs-plugin.mdx index 5f166f9b..5631412b 100644 --- a/content/docs/en/guides/ecs/example-ecs-plugin.mdx +++ b/content/docs/en/guides/ecs/example-ecs-plugin.mdx @@ -40,6 +40,7 @@ public class PoisonComponent implements Component { } // A builder codec is needed to allow components to be saved and loaded from disk + // NOTE: You must specify the codec when adding the component to the store for it to save and load data. public static final BuilderCodec CODEC = BuilderCodec .builder(PoisonComponent.class, PoisonComponent::new) .append( @@ -204,7 +205,7 @@ public class ExampleCommand extends AbstractPlayerCommand { @Nonnull Ref ref, @Nonnull PlayerRef playerRef, @Nonnull World world) { Player player = store.getComponent(ref, Player.getComponentType()); PoisonComponent poison = new PoisonComponent(3f, 0.5f, 8); - store.addComponent(ref, PoisonComponent.getComponentType(), poison); + store.addComponent(ref, PoisonComponent.getComponentType(), poison, PoisonComponent.CODEC); player.sendMessage(Message.raw("You have been poisoned!").color(Color.GREEN).bold(true)); } } From f6abb1a346a8467881287f2f3ce40b62dd03aad1 Mon Sep 17 00:00:00 2001 From: Jacob <124112219+jacobwojoski@users.noreply.github.com> Date: Tue, 10 Feb 2026 13:25:45 -0500 Subject: [PATCH 6/6] Update example-ecs-plugin.mdx --- content/docs/en/guides/ecs/example-ecs-plugin.mdx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/content/docs/en/guides/ecs/example-ecs-plugin.mdx b/content/docs/en/guides/ecs/example-ecs-plugin.mdx index 5631412b..183213d2 100644 --- a/content/docs/en/guides/ecs/example-ecs-plugin.mdx +++ b/content/docs/en/guides/ecs/example-ecs-plugin.mdx @@ -40,7 +40,7 @@ public class PoisonComponent implements Component { } // A builder codec is needed to allow components to be saved and loaded from disk - // NOTE: You must specify the codec when adding the component to the store for it to save and load data. + // NOTE: You must specify the codec when registering the component for it to save and load data. public static final BuilderCodec CODEC = BuilderCodec .builder(PoisonComponent.class, PoisonComponent::new) .append( @@ -205,7 +205,7 @@ public class ExampleCommand extends AbstractPlayerCommand { @Nonnull Ref ref, @Nonnull PlayerRef playerRef, @Nonnull World world) { Player player = store.getComponent(ref, Player.getComponentType()); PoisonComponent poison = new PoisonComponent(3f, 0.5f, 8); - store.addComponent(ref, PoisonComponent.getComponentType(), poison, PoisonComponent.CODEC); + store.addComponent(ref, PoisonComponent.getComponentType(), poison); player.sendMessage(Message.raw("You have been poisoned!").color(Color.GREEN).bold(true)); } } @@ -231,7 +231,7 @@ public final class ExamplePlugin extends JavaPlugin { // Register the component & set the type in the component class so its easier to retrieve. ComponentType poisonComponentType = this.getEntityStoreRegistry() - .registerComponent(PoisonComponent.class, PoisonComponent::new); + .registerComponent(PoisonComponent.class, PoisonComponent::new, PoisonComponent.CODEC); PoisonComponent.setComponentType(poisonComponentType); this.getEntityStoreRegistry().registerSystem(new PoisonSystem(PoisonComponent.getComponentType()));