Skip to content

Instantly share code, notes, and snippets.

@Ensamisten
Created April 14, 2026 12:56
Show Gist options
  • Select an option

  • Save Ensamisten/e5b155c30fbf49edd84d65350a248aef to your computer and use it in GitHub Desktop.

Select an option

Save Ensamisten/e5b155c30fbf49edd84d65350a248aef to your computer and use it in GitHub Desktop.
package io.github.ensamisten.command.brigadier;
import com.mojang.brigadier.Command;
import com.mojang.brigadier.CommandDispatcher;
import com.mojang.brigadier.arguments.IntegerArgumentType;
import com.mojang.serialization.Codec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import it.unimi.dsi.fastutil.ints.IntArrayList;
import net.minecraft.commands.CommandSourceStack;
import net.minecraft.commands.Commands;
import net.minecraft.commands.arguments.EntityArgument;
import net.minecraft.commands.arguments.coordinates.BlockPosArgument;
import net.minecraft.core.BlockPos;
import net.minecraft.core.component.DataComponents;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.projectile.FireworkRocketEntity;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
import net.minecraft.world.item.component.FireworkExplosion;
import net.minecraft.world.item.component.Fireworks;
import net.minecraft.world.level.Level;
import org.jspecify.annotations.NonNull;
import java.util.List;
import java.util.random.RandomGenerator;
public class FireworkCommand {
// ── Codec for FireworkParams (used for SavedData / DataAttachment) ──
public record FireworkParams(int shape, int color, int flight) {
public static final Codec<FireworkParams> CODEC = RecordCodecBuilder.create(instance -> instance.group(
Codec.INT.fieldOf("shape").forGetter(FireworkParams::shape),
Codec.INT.fieldOf("color").forGetter(FireworkParams::color),
Codec.INT.fieldOf("flight").forGetter(FireworkParams::flight)
).apply(instance, FireworkParams::new));
}
public static void register(CommandDispatcher<CommandSourceStack> dispatcher) {
dispatcher.register(Commands.literal("firework")
// ── /firework <pos> [count] [shape] [color] [flight] ──
.then(Commands.argument("pos", BlockPosArgument.blockPos())
.executes(ctx -> execute(ctx.getSource().getLevel(),
BlockPosArgument.getLoadedBlockPos(ctx, "pos"),
1, 0, 0xFFFFFF, 1))
.then(Commands.argument("count", IntegerArgumentType.integer(1))
.then(Commands.argument("shape", IntegerArgumentType.integer(0, 4))
.then(Commands.argument("color", IntegerArgumentType.integer(0, 0xFFFFFF))
.then(Commands.argument("flight", IntegerArgumentType.integer(1, 3))
.executes(ctx -> execute(
ctx.getSource().getLevel(),
BlockPosArgument.getLoadedBlockPos(ctx, "pos"),
IntegerArgumentType.getInteger(ctx, "count"),
IntegerArgumentType.getInteger(ctx, "shape"),
IntegerArgumentType.getInteger(ctx, "color"),
IntegerArgumentType.getInteger(ctx, "flight")
))
)
)
)
)
)
// ── /firework entity <targets> <count> <shape> <color> <flight> ──
.then(Commands.literal("entity")
.then(Commands.argument("targets", EntityArgument.entities())
.then(Commands.argument("count", IntegerArgumentType.integer(1))
.then(Commands.argument("shape", IntegerArgumentType.integer(0, 4))
.then(Commands.argument("color", IntegerArgumentType.integer(0, 0xFFFFFF))
.then(Commands.argument("flight", IntegerArgumentType.integer(1, 3))
.executes(ctx -> executeFromEntities(
ctx.getSource().getLevel(),
EntityArgument.getEntities(ctx, "targets"),
IntegerArgumentType.getInteger(ctx, "count"),
IntegerArgumentType.getInteger(ctx, "shape"),
IntegerArgumentType.getInteger(ctx, "color"),
IntegerArgumentType.getInteger(ctx, "flight")
))
)
)
)
)
)
)
);
}
// ── Spawn at block pos ────────────────────────────────────────────────
private static int execute(Level level, BlockPos pos,
int count, int shape, int color, int flight) {
RandomGenerator rng = RandomGenerator.getDefault();
for (int i = 0; i < count; i++) {
double ox = (rng.nextDouble() - 0.5) * 5.0;
double oy = (rng.nextDouble() - 0.5) * 5.0;
double oz = (rng.nextDouble() - 0.5) * 5.0;
spawnFirework(level,
pos.getX() + 0.5 + ox,
pos.getY() + 0.5 + oy,
pos.getZ() + 0.5 + oz,
shape, color, flight);
}
return Command.SINGLE_SUCCESS;
}
// ── Spawn at entity positions ─────────────────────────────────────────
private static int executeFromEntities(Level level, Iterable<? extends Entity> targets,
int count, int shape, int color, int flight) {
RandomGenerator rng = RandomGenerator.getDefault();
for (Entity target : targets) {
for (int i = 0; i < count; i++) {
double ox = (rng.nextDouble() - 0.5) * 5.0;
double oy = (rng.nextDouble() - 0.5) * 5.0;
double oz = (rng.nextDouble() - 0.5) * 5.0;
spawnFirework(level,
target.getX() + 0.5 + ox,
target.getY() + target.getBbHeight() + oy,
target.getZ() + 0.5 + oz,
shape, color, flight);
}
}
return Command.SINGLE_SUCCESS;
}
// ── Core spawn logic using modern DataComponents ──────────────────────
private static void spawnFirework(Level level, double x, double y, double z,
int shape, int color, int flight) {
// ── Map int → FireworkExplosion.Shape ─────────────────────
FireworkExplosion explosion = getFireworkExplosion(shape, color);
// ── Build the rocket ItemStack with DataComponents ────────
ItemStack rocket = new ItemStack(Items.FIREWORK_ROCKET);
rocket.set(DataComponents.FIREWORKS, new Fireworks(flight, List.of(explosion)));
// ── Spawn entity ──────────────────────────────────────────
FireworkRocketEntity entity = new FireworkRocketEntity(level, x, y, z, rocket);
entity.setDeltaMovement(entity.getDeltaMovement().add(0, 0.05, 0));
level.addFreshEntity(entity);
}
private static @NonNull FireworkExplosion getFireworkExplosion(int shape, int color) {
FireworkExplosion.Shape explosionShape = switch (shape) {
case 1 -> FireworkExplosion.Shape.LARGE_BALL;
case 2 -> FireworkExplosion.Shape.STAR;
case 3 -> FireworkExplosion.Shape.CREEPER;
case 4 -> FireworkExplosion.Shape.BURST;
default -> FireworkExplosion.Shape.SMALL_BALL;
};
// ── Build explosion via DataComponent (replaces CompoundTag) ──
// ── Build explosion via DataComponent ─────────────────────
return new FireworkExplosion(
explosionShape,
new IntArrayList(new int[]{color}), // colors — IntList not int[]
new IntArrayList(new int[]{0xFFFFFF}), // fade — IntList not int[]
true, // trail
true // flicker
);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment