diff --git a/src/main/java/com/mythlane/gravityflip/wand/GravityFlipWandInteraction.java b/src/main/java/com/mythlane/gravityflip/wand/GravityFlipWandInteraction.java
index 2fe4f7b..c76d5e1 100644
--- a/src/main/java/com/mythlane/gravityflip/wand/GravityFlipWandInteraction.java
+++ b/src/main/java/com/mythlane/gravityflip/wand/GravityFlipWandInteraction.java
@@ -15,38 +15,7 @@ import com.hypixel.hytale.server.core.universe.world.storage.EntityStore;
import javax.annotation.Nonnull;
import java.util.UUID;
-/**
- * Gravity Flip wand interaction — reads Primary / Secondary clicks and pushes
- * the targeted block position into a {@link WandSelectionStore} keyed by the
- * clicker's player UUID.
- *
- *
Binding : registered at {@code setup()} time via
- * {@code getCodecRegistry(Interaction.CODEC).register("GravityFlipWand", …)} —
- * same pattern as {@code ExitInstanceInteraction} (cf. 04-00 SPIKE-RESULT,
- * Finding 3). The matching {@code "Type": "GravityFlipWand"} reference in
- * {@code Items/gravityflip_wand.json} wires the click packet to this class.
- *
- *
One class for both click types : {@link #firstRun} receives the
- * {@link InteractionType}. Primary → {@code setPos1}, Secondary → {@code setPos2}.
- * Centralising both in one class keeps a single registration entry and a
- * single CODEC — any other split would duplicate wiring for no gain.
- *
- *
Store injection : the Hytale CODEC instantiates interactions via a
- * no-arg constructor, so we cannot inject the store through the constructor.
- * Instead, {@link #bindStore(WandSelectionStore)} installs a {@code volatile}
- * reference at plugin start. If the store is not bound (mis-wired plugin),
- * {@link #firstRun} is a safe no-op — fail-silent.
- *
- *
Threat surface :
- *
- * - Chat feedback uses {@link PlayerRef#sendMessage} — directed to the
- * clicker only, no broadcast (T-04-01-03).
- * - {@code TargetBlock} coordinates are stored raw as {@code int[]} — no
- * numeric processing in this plan; {@code /gravityflip define} (04-03)
- * is responsible for clamping / validating before region creation
- * (T-04-01-01).
- *
- */
+/** Wand interaction: Primary click sets pos1, Secondary click sets pos2 in the shared selection store. */
public final class GravityFlipWandInteraction extends SimpleInstantInteraction {
@Nonnull
@@ -60,19 +29,14 @@ public final class GravityFlipWandInteraction extends SimpleInstantInteraction {
+ "Secondary click sets pos2, for the clicker's selection."))
.build();
- /**
- * Store shared by every instance of this interaction — injected at plugin
- * start via {@link #bindStore}. Volatile so the writer thread ({@code setup()})
- * publishes a safe reference to the reader threads (interaction dispatch).
- */
+ // Volatile: writer (setup thread) must publish safely to reader threads (interaction dispatch).
private static volatile WandSelectionStore STORE;
- /** Wire the selection store before any click can be processed. Call once at {@code setup()}. */
+ /** Wire the selection store before any click can be processed. */
public static void bindStore(WandSelectionStore store) {
STORE = store;
}
- /** Required no-arg constructor used by the CODEC factory. */
public GravityFlipWandInteraction() {
}
@@ -82,7 +46,6 @@ public final class GravityFlipWandInteraction extends SimpleInstantInteraction {
@Nonnull CooldownHandler cooldownHandler) {
WandSelectionStore store = STORE;
if (store == null) {
- // Plugin mis-wired (bindStore never called). Silent no-op — don't crash the click.
return;
}
@@ -94,7 +57,6 @@ public final class GravityFlipWandInteraction extends SimpleInstantInteraction {
PlayerRef playerRef = commandBuffer.getComponent(entityRef, PlayerRef.getComponentType());
if (playerRef == null) {
- // Clicker is not a player (mob, arrow, …) — ignore.
return;
}
@@ -114,6 +76,5 @@ public final class GravityFlipWandInteraction extends SimpleInstantInteraction {
playerRef.sendMessage(Message.raw(
"[gravityflip] pos2 set: (%d, %d, %d)".formatted(bp.x, bp.y, bp.z)));
}
- // Any other InteractionType (Ability1, Pick, Equipped, …) is ignored.
}
}
diff --git a/src/main/java/com/mythlane/gravityflip/wand/WandSelectionStore.java b/src/main/java/com/mythlane/gravityflip/wand/WandSelectionStore.java
index 0b99f17..3a1ecf5 100644
--- a/src/main/java/com/mythlane/gravityflip/wand/WandSelectionStore.java
+++ b/src/main/java/com/mythlane/gravityflip/wand/WandSelectionStore.java
@@ -3,29 +3,12 @@ package com.mythlane.gravityflip.wand;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
-/**
- * Thread-safe per-player wand selection store. Tracks the two corner positions
- * ({@code pos1} = Primary click, {@code pos2} = Secondary click) of each
- * builder's current selection, keyed by player {@link UUID}.
- *
- * Pure-data : no Hytale runtime dependency — same philosophy as
- * {@code FallDamageGuard}. Testable with JUnit alone, reusable by future
- * {@code /gravityflip define} command (Phase 04-02+) without runtime coupling.
- *
- *
Thread-safety : backed by a {@link ConcurrentHashMap} whose
- * {@code compute(...)} mutations are atomic. Safe for concurrent
- * {@link #setPos1}/{@link #setPos2} calls on the same UUID (STRIDE T-04-01-04).
- *
- *
Lifecycle : in-memory only — selections are discarded on plugin
- * shutdown. Conscious design : a builder will not quit mid-{@code define}.
- */
+/** Thread-safe per-player wand selection store (pos1/pos2 keyed by player UUID). */
public final class WandSelectionStore {
/** Immutable holder for a (possibly partial) selection. */
public static final class Selection {
- /** {@code {x,y,z}} of the Primary click, or {@code null} if unset. */
public final int[] pos1;
- /** {@code {x,y,z}} of the Secondary click, or {@code null} if unset. */
public final int[] pos2;
Selection(int[] pos1, int[] pos2) {
@@ -43,7 +26,7 @@ public final class WandSelectionStore {
private final ConcurrentHashMap byUuid = new ConcurrentHashMap<>();
- /** Record the Primary-click corner for {@code uuid}. Keeps any existing pos2. */
+ /** Record the Primary-click corner for the given player. */
public void setPos1(UUID uuid, int x, int y, int z) {
if (uuid == null) return;
byUuid.compute(uuid, (k, prev) -> new Selection(
@@ -51,7 +34,7 @@ public final class WandSelectionStore {
prev != null ? prev.pos2 : null));
}
- /** Record the Secondary-click corner for {@code uuid}. Keeps any existing pos1. */
+ /** Record the Secondary-click corner for the given player. */
public void setPos2(UUID uuid, int x, int y, int z) {
if (uuid == null) return;
byUuid.compute(uuid, (k, prev) -> new Selection(
@@ -59,23 +42,20 @@ public final class WandSelectionStore {
new int[]{x, y, z}));
}
- /**
- * Return the current selection for {@code uuid}. Never returns {@code null} :
- * an unknown UUID yields a {@link Selection} with both corners {@code null}.
- */
+ /** Return the current selection for the given player (never null). */
public Selection get(UUID uuid) {
if (uuid == null) return EMPTY;
Selection s = byUuid.get(uuid);
return s != null ? s : EMPTY;
}
- /** Forget the selection for {@code uuid} (e.g. after {@code /gravityflip define}). */
+ /** Forget the selection for the given player. */
public void clear(UUID uuid) {
if (uuid == null) return;
byUuid.remove(uuid);
}
- /** Diagnostic : number of players with an in-flight selection. */
+ /** Number of players with an in-flight selection. */
public int size() {
return byUuid.size();
}
diff --git a/src/test/java/com/mythlane/gravityflip/wand/WandSelectionStoreTest.java b/src/test/java/com/mythlane/gravityflip/wand/WandSelectionStoreTest.java
index d9d7eae..c25ee8f 100644
--- a/src/test/java/com/mythlane/gravityflip/wand/WandSelectionStoreTest.java
+++ b/src/test/java/com/mythlane/gravityflip/wand/WandSelectionStoreTest.java
@@ -12,11 +12,7 @@ import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
-/**
- * Pure-data tests for {@link WandSelectionStore} — no Hytale runtime dependency.
- * Covers set/get per UUID, overwrite semantics, unknown UUID default, clear,
- * and concurrent writes.
- */
+/** Tests for {@link WandSelectionStore}: set/get per UUID, overwrite, clear, concurrency. */
class WandSelectionStoreTest {
@Test