feat(phase-1): scaffold ChainLightning Sceptre plugin

Build infrastructure (Gradle wrapper, shadow, Java 25), manifest, item
JSON + interactions, and ChainLightningPlugin entry with stub handler
that logs sceptre clicks. Cooldown wiring deferred to Phase 3 (real
Hytale API is getCooldown(id).setCooldownMax — not cooldown(Duration)).
This commit is contained in:
2026-04-26 19:22:18 +02:00
parent d06743acbe
commit edca00fa4a
14 changed files with 656 additions and 0 deletions
@@ -0,0 +1,45 @@
package com.mythlane.chainlightning;
import com.hypixel.hytale.server.core.modules.interaction.interaction.config.Interaction;
import com.hypixel.hytale.server.core.plugin.JavaPlugin;
import com.hypixel.hytale.server.core.plugin.JavaPluginInit;
import com.mythlane.chainlightning.sceptre.ChainLightningSceptreInteraction;
import java.util.logging.Level;
/**
* Entry point for the Chain Lightning Sceptre plugin.
*
* Phase 1 scope:
* - Register the {@code ChainLightningSceptre} interaction codec so the runtime
* can dispatch primary/secondary clicks on the chain_lightning_sceptre item.
* - No chain resolution, no VFX, no config — those land in Phases 2/3/4.
*/
public class ChainLightningPlugin extends JavaPlugin {
public ChainLightningPlugin(JavaPluginInit init) {
super(init);
}
@Override
protected void setup() {
// The string "ChainLightningSceptre" MUST match the "Type" field in
// Server/Item/Interactions/chain_lightning_sceptre_click.json (case-sensitive).
getCodecRegistry(Interaction.CODEC).register(
"ChainLightningSceptre",
ChainLightningSceptreInteraction.class,
ChainLightningSceptreInteraction.CODEC);
}
@Override
protected void start() {
super.start();
getLogger().at(Level.INFO).log("ChainLightning started");
}
@Override
protected void shutdown() {
getLogger().at(Level.INFO).log("ChainLightning stopped");
super.shutdown();
}
}
@@ -0,0 +1,70 @@
package com.mythlane.chainlightning.sceptre;
import com.hypixel.hytale.codec.builder.BuilderCodec;
import com.hypixel.hytale.component.CommandBuffer;
import com.hypixel.hytale.component.Ref;
import com.hypixel.hytale.protocol.InteractionType;
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;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* Phase 1 stub interaction handler for the Chain Lightning Sceptre item.
* Logs the click + applies a 4s cooldown smoke-test. Full chain logic lands in Phase 3.
*/
public final class ChainLightningSceptreInteraction extends SimpleInstantInteraction {
private static final Logger LOGGER = Logger.getLogger(ChainLightningSceptreInteraction.class.getName());
@Nonnull
public static final BuilderCodec<ChainLightningSceptreInteraction> CODEC =
((BuilderCodec.Builder) BuilderCodec
.builder(ChainLightningSceptreInteraction.class,
ChainLightningSceptreInteraction::new,
SimpleInstantInteraction.CODEC)
.documentation(
"Chain Lightning sceptre: primary/secondary click chains lightning to up to 5 targets."))
.build();
public ChainLightningSceptreInteraction() {
}
@Override
protected void firstRun(@Nonnull InteractionType type,
@Nonnull InteractionContext context,
@Nonnull CooldownHandler cooldownHandler) {
// Phase 1: stub only. Identify the player for traceability, log, then arm the cooldown
// (smoke test of the CooldownHandler API — actual chain resolution lands in Phase 3).
UUID playerUuid = null;
try {
Ref<EntityStore> entityRef = context.getEntity();
CommandBuffer<EntityStore> commandBuffer = context.getCommandBuffer();
if (entityRef != null && commandBuffer != null) {
PlayerRef playerRef = commandBuffer.getComponent(entityRef, PlayerRef.getComponentType());
if (playerRef != null) {
playerUuid = playerRef.getUuid();
}
}
} catch (Throwable ignored) {
// Defensive: never fail the click because of telemetry.
}
LOGGER.log(Level.INFO,
"[ChainLightning] sceptre clicked by player {0} (type={1})",
new Object[]{playerUuid, type});
// TODO Phase 3: wire cooldown via CooldownHandler.
// Confirmed API (javap on Server-2026.03.26-89796e57b.jar):
// CooldownHandler has NO cooldown(Duration) method.
// Use: cooldownHandler.getCooldown("primary").setCooldownMax(4f)
// then cooldownHandler.resetCooldown("primary", ...) on next tick.
// Full cooldown integration deferred to Phase 3 to keep Phase 1 build green.
}
}