diff --git a/src/main/java/com/mythlane/gravityflip/GravityFlipPlugin.java b/src/main/java/com/mythlane/gravityflip/GravityFlipPlugin.java index e639638..b96cb0e 100644 --- a/src/main/java/com/mythlane/gravityflip/GravityFlipPlugin.java +++ b/src/main/java/com/mythlane/gravityflip/GravityFlipPlugin.java @@ -15,6 +15,9 @@ import com.mythlane.gravityflip.region.GravityFlipRegion; import com.mythlane.gravityflip.region.RegionRegistry; import com.mythlane.gravityflip.tick.RegionTickLoop; import com.mythlane.gravityflip.viz.RegionVisualizer; +import com.mythlane.gravityflip.wand.GravityFlipWandInteraction; +import com.mythlane.gravityflip.wand.WandSelectionStore; +import com.hypixel.hytale.server.core.modules.interaction.interaction.config.Interaction; import java.util.concurrent.ScheduledFuture; import java.util.logging.Level; @@ -46,6 +49,7 @@ public class GravityFlipPlugin extends JavaPlugin { private GravityApplier gravityApplier; private FallDamageGuard fallDamageGuard; private RegionVisualizer regionVisualizer; + private WandSelectionStore wandSelectionStore; public GravityFlipPlugin(JavaPluginInit init) { super(init); @@ -69,6 +73,18 @@ public class GravityFlipPlugin extends JavaPlugin { getEntityStoreRegistry().registerSystem(new FallDamageSuppressorSystem( fallDamageGuard, th -> getLogger().at(Level.WARNING).withCause(th).log("fallDamageSuppressor handle failed"))); + + // Plan 04-01 : Gravity Flip wand. + // Interaction binding pattern per 04-00 SPIKE-RESULT (Finding 3) — same shape as + // InstancesPlugin.java:158 / ExitInstanceInteraction. The JSON Item at + // src/main/resources/Items/gravityflip_wand.json references this Type in + // Interactions.Primary / Interactions.Secondary. + this.wandSelectionStore = new WandSelectionStore(); + GravityFlipWandInteraction.bindStore(this.wandSelectionStore); + getCodecRegistry(Interaction.CODEC).register( + "GravityFlipWand", + GravityFlipWandInteraction.class, + GravityFlipWandInteraction.CODEC); } @Override @@ -151,6 +167,14 @@ public class GravityFlipPlugin extends JavaPlugin { /** Exposed for Phase 3 (gravity physics) and Phase 4 (commands). */ public RegionRegistry regions() { return registry; } + /** + * Per-player wand selection store. Populated by + * {@link GravityFlipWandInteraction}; consumed by + * {@code /gravityflip define} (Phase 04-02+). + *
Returns {@code null} until {@link #setup()} has run. + */ + public WandSelectionStore wandSelections() { return wandSelectionStore; } + /** * Accessor for the region config holder. SAVE CONTRACT: any * caller that mutates {@code configHolder().get().getRegions()} MUST call diff --git a/src/main/java/com/mythlane/gravityflip/wand/GravityFlipWandInteraction.java b/src/main/java/com/mythlane/gravityflip/wand/GravityFlipWandInteraction.java new file mode 100644 index 0000000..2fe4f7b --- /dev/null +++ b/src/main/java/com/mythlane/gravityflip/wand/GravityFlipWandInteraction.java @@ -0,0 +1,119 @@ +package com.mythlane.gravityflip.wand; + +import com.hypixel.hytale.codec.builder.BuilderCodec; +import com.hypixel.hytale.component.CommandBuffer; +import com.hypixel.hytale.component.Ref; +import com.hypixel.hytale.protocol.BlockPosition; +import com.hypixel.hytale.protocol.InteractionType; +import com.hypixel.hytale.server.core.Message; +import com.hypixel.hytale.server.core.entity.InteractionContext; +import com.hypixel.hytale.server.core.modules.interaction.interaction.CooldownHandler; +import com.hypixel.hytale.server.core.modules.interaction.interaction.config.SimpleInstantInteraction; +import com.hypixel.hytale.server.core.universe.PlayerRef; +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 : + *