Minestom 2026 · Java 25 · Active Dev

MineGun

A firearms library built on Minestom. Raycasted hitscan weapons, custom health & shield management, and a clean event-driven API — all in pure Java.

GitHub ↗
2
Weapons
25ms
Fire Cooldown
100
Range (blocks)
Java 25
Target
What's Included
🎯
Raycasted Hitscan
Step-based raycast at 0.5 block increments, 100 block range. Sneak-aware hitbox detection (1.8 / 1.5 height). Shared via RaycastWeapons interface.
Health + Shield System
Custom 100HP / 100SP using Minestom Tags. Boss bar HUD, kill tracking, death title + respawn. Wired via dedicated event handler classes.
🔫
Rifle
WOODEN_HOE item. 25ms cooldown. CRIT particles. 25 custom damage. Server-wide kill broadcast.
🚀
Rocket Launcher
WOODEN_AXE item. FLAME particles. Terrain explosion (radius 10) on block impact.
Health Event Wiring
A single HealthManagement.register() call wires both the PlayerLoadedEvent (boss bar init) and PlayerTickEvent (HUD + death) listeners in one shot.
📋
minegunLogger
ANSI-coloured INFO / WARN / ERROR / OK console logger with ASCII art startup banner.
🎮
Demo Server
Flat stone arena, /give command, zombie test dummy, and F3+F4 gamemode support. Online-mode auth.

Architecture

MineGun uses a multi-project Gradle build split into two subprojects: :lib (the publishable library) and :demo (the runnable reference server). JitPack only publishes :lib since it is the only subproject with maven-publish applied — the demo is invisible to JitPack entirely.

Both HealthManagement and RaycastWeapons are designed as interfaces with static methods, letting weapon classes implement them and call shared logic without instantiation overhead. HealthManagement.register() is a single call that internally registers both the PlayerLoadedEvent (boss bar setup) and PlayerTickEvent (HUD updates + death logic) listeners.

Package Tree
minegun/                          ← repo root
├── settings.gradle.kts
├── build.gradle.kts              ← shared repo config
├── lib/                          ← published library (JitPack)
│   └── src/main/java/org/vardinsdev/minegun/
│       ├── HealthManagement.java
│       ├── minegunLogger.java
│       └── Weapons/
│           ├── RaycastWeapons.java
│           ├── Rifle.java
│           └── RocketLauncher.java
└── demo/                         ← runnable demo (not published)
    └── src/main/java/org/vardinsdev/minegun/demo/
        ├── Main.java
        ├── giveCommand.java
        └── TestDummy.java
Library vs Demo: Depend only on :lib in production. The :demo subproject has a hardcoded arena, online-mode auth, and a zombie dummy — it exists purely as a runnable reference and is never published.

How Hitscan Works

When a player right-clicks a weapon item, the server casts a ray from their eye position in their look direction:

  1. Eye position = player.getPosition().add(0, eyeHeight, 0)
  2. Steps at 0.5 block increments along the look vector
  3. At each point: checks for a solid block (stops / explodes on hit)
  4. Calls RaycastWeapons.isPlayerAtPosition() to check for player hitbox overlap
  5. On player hit: applies damage, sounds, kill detection
  6. On miss: spawns a particle at the step point

Quick Start

Minimum code to get the Rifle and health system working inside an existing Minestom server.

1. Register Weapons

java
import org.vardinsdev.minegun.Weapons.Rifle;
import org.vardinsdev.minegun.Weapons.RocketLauncher;

InstanceContainer ic = instanceManager.createInstanceContainer();

// Each weapon grabs the GlobalEventHandler internally
Rifle.register(ic);
RocketLauncher.register(ic);

2. Set Up Health Management

A single HealthManagement.register() call wires both the PlayerLoadedEvent (boss bar initialisation) and PlayerTickEvent (HUD refresh + death/respawn) listeners internally.

java
import org.vardinsdev.minegun.HealthManagement;

HealthManagement.register();

3. Give a Weapon to a Player

java
geh.addListener(AsyncPlayerConfigurationEvent.class, event -> {
    event.setSpawningInstance(ic);
    event.getPlayer().setRespawnPoint(new Pos(0, 42, 0));
    Rifle.givePlayer(event.getPlayer());
});

Full Minimal Example

java
public class MyServer {
    public static void main(String[] args) {
        MinecraftServer server = MinecraftServer.init();

        InstanceContainer ic = MinecraftServer.getInstanceManager()
            .createInstanceContainer();
        ic.setGenerator(unit ->
            unit.modifier().fillHeight(39, 40, Block.STONE));
        ic.setChunkSupplier(LightingChunk::new);

        // Register weapons (they use GlobalEventHandler internally)
        Rifle.register(ic);
        RocketLauncher.register(ic);

        // Register health system (boss bars + tick update)
        HealthManagement.register();

        MinecraftServer.getGlobalEventHandler().addListener(
            AsyncPlayerConfigurationEvent.class, e -> {
                e.setSpawningInstance(ic);
                e.getPlayer().setRespawnPoint(new Pos(0, 42, 0));
                Rifle.givePlayer(e.getPlayer());
            });

        server.start("0.0.0.0", 25565);
    }
}
Tip: demo/Main.java is a working version of this pattern with the /give command, F3+F4 gamemode support, and online-mode auth already wired in.

Installation

Add MineGun to your Minestom project via JitPack.

Requirements

DependencyVersionNotes
Java25+Required by the project toolchain
Minestom2026.03.03-1.21.11Maven Central
AdventurebundledShips with Minestom

Clone

bash
git clone https://github.com/AbyssalNetwork/minegun.git
cd minegun

Using MineGun in Your Project (JitPack)

MineGun is published via JitPack. Only :lib is published — add the JitPack repository and declare the dependency in your own project:

kotlin — your project's build.gradle.kts
repositories {
    mavenCentral()
    maven("https://jitpack.io")
}

dependencies {
    implementation("com.github.AbyssalNetwork:minegun:TAG")
}
JitPack: Replace TAG with a git tag, branch name, or commit hash. JitPack builds :lib directly from the GitHub repo on first request and caches it.

Project Structure

The repo is a multi-project Gradle build. :lib is the library that gets published to JitPack. :demo is a self-contained runnable server for testing — it depends on :lib via project(":lib") and is never published.

Directory Layout

tree
minegun/
├── settings.gradle.kts
├── build.gradle.kts                   ← root (shared repo config only)
├── lib/
│   ├── build.gradle.kts               ← java-library + maven-publish
│   └── src/main/java/org/vardinsdev/minegun/
│       ├── HealthManagement.java
│       ├── minegunLogger.java
│       └── Weapons/
│           ├── RaycastWeapons.java
│           ├── Rifle.java
│           └── RocketLauncher.java
└── demo/
    ├── build.gradle.kts               ← application, depends on :lib
    └── src/main/java/org/vardinsdev/minegun/demo/
        ├── Main.java
        ├── giveCommand.java
        └── TestDummy.java

settings.gradle.kts

kotlin
pluginManagement {
    repositories {
        gradlePluginPortal()
    }
}

rootProject.name = "minegun"
include("lib", "demo")

build.gradle.kts (root)

kotlin
// Push shared repository config to all subprojects
subprojects {
    repositories {
        mavenCentral()
        maven("https://jitpack.io")
    }
}

lib/build.gradle.kts

kotlin
plugins {
    `java-library`
    `maven-publish`
}

group = "org.vardinsdev"
version = "1.0.0"

java {
    toolchain {
        languageVersion.set(JavaLanguageVersion.of(25))
    }
    withSourcesJar()
}

publishing {
    publications {
        create<MavenPublication>("mavenJava") {
            from(components["java"])
        }
    }
}

dependencies {
    implementation("net.minestom:minestom:2026.03.03-1.21.11")
}

demo/build.gradle.kts

kotlin
plugins {
    application
}

java {
    toolchain {
        languageVersion.set(JavaLanguageVersion.of(25))
    }
}

application {
    mainClass.set("org.vardinsdev.minegun.demo.Main")
}

dependencies {
    implementation(project(":lib"))
    implementation("net.minestom:minestom:2026.03.03-1.21.11")
}

// Optional fat JAR — no plugin needed
tasks.register<Jar>("fatJar") {
    archiveClassifier.set("all")
    duplicatesStrategy = DuplicatesStrategy.EXCLUDE
    manifest {
        attributes["Main-Class"] = "org.vardinsdev.minegun.demo.Main"
    }
    from(sourceSets.main.get().output)
    dependsOn(configurations.runtimeClasspath)
    from(configurations.runtimeClasspath.get().map { if (it.isDirectory) it else zipTree(it) })
}

Running the Demo

bash
# Preferred — no extra plugin, full classpath via launcher script
./gradlew :demo:installDist
./demo/build/install/demo/bin/demo

# Or via fat JAR
./gradlew :demo:fatJar
java -jar demo/build/libs/demo-all.jar

# Or directly through Gradle (dev only)
./gradlew :demo:run
Don't use the IntelliJ Run button directly. It launches with only demo/build/classes/java/main on the classpath, missing Minestom and lib entirely. Use installDist or ./gradlew :demo:run instead, or fix the run configuration's "Use classpath of module" to demo.main.

Contributing

MineGun is an open project — contributions of all kinds are welcome, from new weapon implementations to bug fixes and documentation improvements. This page covers everything you need to get set up and submit good work.

Local Setup

Clone the repo, import as a Gradle project in IntelliJ, and verify the build before making any changes.

bash
git clone https://github.com/AbyssalNetwork/minegun.git
cd minegun
./gradlew :lib:build        # compile + test the library
./gradlew :demo:installDist # build the runnable demo
IntelliJ tip: After cloning, open the repo root as a Gradle project and let IntelliJ sync. Set the run configuration's "Use classpath of module" to demo.main — otherwise the Run button will miss Minestom and lib on the classpath. Prefer ./gradlew :demo:run for quick iteration.

Code Style

Static Interface Pattern

The core of MineGun is built on Java interfaces with static methods. This is intentional — it avoids instantiation overhead and lets weapon classes compose behaviour by implementing multiple interfaces. When adding new functionality to the library, follow the same pattern: put logic in a static method on an interface, not in a class with instance state.

java — do this
public interface MySystem {
    static void register() {
        MinecraftServer.getGlobalEventHandler().addListener(...);
    }
    static void doThing(Player player) { ... }
}
java — not this
public class MySystem {
    private final GlobalEventHandler geh;
    public MySystem(GlobalEventHandler geh) { this.geh = geh; }
}

Naming

  • Interface names are PascalCase nouns — RaycastWeapons, HealthManagement
  • Static methods are camelCase verbs — register(), givePlayer(), damage()
  • Class names in the logger follow the existing lowercase-first convention — minegunLogger — keep this consistent
  • Weapon classes live in org.vardinsdev.minegun.Weapons with a capital W — match this exactly

Logging

Use minegunLogger for all console output — never System.out.println directly outside the logger itself. Pick the right level:

MethodUse for
minegunLogger.info()Registration events, lifecycle steps
minegunLogger.success()Successful player actions (giving weapons, kills)
minegunLogger.warn()Non-fatal unexpected states
minegunLogger.error()Failures, invalid usage (e.g. console running player-only commands)

Formatting

  • 4-space indentation, no tabs
  • Opening braces on the same line
  • One blank line between methods
  • Keep lambda bodies inline where they fit on one line; extract to a named method if they grow beyond ~5 lines

Adding a New Weapon

All weapons follow the same structure. Create a new interface in org.vardinsdev.minegun.Weapons that extends RaycastWeapons and HealthManagement, then implement two static methods: givePlayer and register.

java — new weapon template
public interface Shotgun extends RaycastWeapons, HealthManagement {

    static void givePlayer(Player player) {
        ItemStack item = ItemStack.builder(Material.WOODEN_SWORD)
            .set(DataComponents.CUSTOM_NAME,
                Component.text("Shotgun", NamedTextColor.YELLOW))
            .build();
        player.setItemInHand(PlayerHand.MAIN, item);
        minegunLogger.success(player.getUsername() + " has been given a Shotgun!");
    }

    static void register(InstanceContainer instanceContainer) {
        MinecraftServer.getGlobalEventHandler()
            .addListener(PlayerUseItemEvent.class, event -> {
                if (event.getPlayer().getItemInMainHand().material()
                        != Material.WOODEN_SWORD) return;

                Player hit = RaycastWeapons.shoot(
                    event.getPlayer(), 500L,
                    instanceContainer, Particle.SMOKE, false);

                if (hit != null) {
                    hit.damage(DamageType.ARROW, 12f);
                    hit.heal();
                    HealthManagement.damage(hit, 40);

                    if (HealthManagement.getHealth(hit) <= 0) {
                        HealthManagement.setKilledBy(hit, event.getPlayer());
                    }
                }
            });
    }
}

Once the class exists, register it in your server setup alongside the other weapons:

java
Rifle.register(instanceContainer);
RocketLauncher.register(instanceContainer);
Shotgun.register(instanceContainer); // your new weapon

And add it to giveCommand.java in the demo so it's accessible in-game:

java — in giveCommand
case "shotgun" -> Shotgun.givePlayer(player);
Choose a unique material. Each weapon uses a distinct Material as its item type — the PlayerUseItemEvent listener filters by material, so two weapons sharing the same material will both fire on every right-click. Pick something not already used by Rifle (WOODEN_HOE) or RocketLauncher (WOODEN_AXE).

Pull Request Guidelines

  • One concern per PR. A new weapon, a bug fix, and a refactor should be three separate PRs — not one. This makes review faster and keeps the git history readable.
  • Branch off master. Name your branch descriptively: feat/shotgun, fix/rocket-damage, docs/health-api.
  • Test with the demo first. Run ./gradlew :demo:installDist and join the server before opening a PR. If the demo breaks, the PR isn't ready.
  • Keep :lib and :demo changes separate. If your change touches both, commit the lib change first, then the demo change that uses it. This makes the dependency direction clear in the history.
  • No new dependencies in :lib without discussion. The library's only dependency is Minestom — keep it that way unless there's a strong reason. Open an issue first.
  • Update the wiki. If you add a weapon, a new API method, or change a method signature, update the corresponding wiki page before the PR is merged.

Reporting Issues

Open an issue on GitHub Issues. Include:

  • A short description of what went wrong and what you expected
  • The Minestom version you're using (net.minestom:minestom:X)
  • Java version (java --version)
  • The relevant stack trace or console output if applicable
  • A minimal reproduction — ideally a modified Main.java that shows the problem
Check the demo first. If the bug also reproduces in the unmodified demo server, include that in the report — it makes it much easier to isolate.
org.vardinsdev.minegun.Weapons
RaycastWeapons
Core raycast interface. Provides the shared player hitbox detection and a full shoot() static method used inside every weapon's raycast loop. Weapon classes implement this interface to access these utilities directly. Also maintains a static lastShotTime cooldown map. Extends ExplosionSupplier.
Javaorg.vardinsdev.minegun.Weaponsinterface

Methods

public static Player isPlayerAtPosition(InstanceContainer instance, Pos targetPos, Player shooter)

Scans all players in the instance. For each player, samples their hitbox in 0.3 block increments from feet up to standing (1.8) or sneaking (1.5) height. Returns the first player whose hitbox contains targetPos within a 0.5 block radius. Returns shooter as a sentinel if no hit.

instanceInstanceContainerThe instance to search for players.
targetPosPosThe point along the ray to check.
shooterPlayerThe firing player — excluded from the scan and returned on miss.

Returns: Hit Player, or shooter if no hit (sentinel pattern).

public static Player shoot(Player player, long cooldownMs, InstanceContainer instanceContainer, Particle particle, Boolean explosion)

Full hitscan shot: enforces per-player cooldown, casts a ray from eye position, spawns the given particle trail, plays hit/fire sounds, and schedules delayed feedback sounds. When explosion is true, an ExplosionPacket (radius 3.5) is broadcast to the instance on both block and player hits. Returns the hit player or null if on cooldown.

playerPlayerThe player firing the weapon.
cooldownMslongMilliseconds between shots.
instanceContainerInstanceContainerUsed for block collision and particle broadcast.
particleParticleParticle type to spawn along the beam (e.g. Particle.CRIT, Particle.FLAME).
explosionBooleanIf true, sends an ExplosionPacket (radius 3.5) at the impact point on both block and player hits.

Returns: The Player that was hit, or null if the cooldown prevented the shot.

Hitbox Detail

java — hitbox loop
double height = player.isSneaking() ? 1.5 : 1.8;
double y = 0.0;
while (y <= height) {
    Pos checkPos = feetPos.add(0.0, y, 0.0);
    if (targetPos.distanceSquared(checkPos) <= 0.25) return player;
    y += 0.3;
}
Sentinel pattern: Callers check if (hit != shooter) — not if (hit != null). The method never returns null.

Static Cooldown Map

The interface declares a static HashMap<UUID, Long> lastShotTime field, shared across all weapon callers via the interface. The shoot() method writes to this map on every successful shot and reads from it to gate cooldowns.

org.vardinsdev.minegun
HealthManagement
Custom health and shield system independent of Minecraft's native HP. Each player gets 100 HP and 100 Shield stored as Minestom Tags, displayed via two boss bars. Handles damage routing, kill tracking, death events, and respawn. All methods are static — no instantiation required. Call HealthManagement.register() once to wire both event listeners.
Javaorg.vardinsdev.mineguninterface

Damage Routing

flow
damage(player, hitDamage)
  ├─ shield >= hitDamage  →  shield -= hitDamage   (health unchanged)
  ├─ shield == hitDamage  →  shield = 0            (health unchanged)
  └─ shield < hitDamage   →  overflow = shield - hitDamage  (negative)
                              shield = 0
                              health += overflow   (subtracts from health)
Known quirk: The overShield variable is computed as shield - hitDamage (a negative number) then added to health, correctly reducing it. The variable name is misleadingly positive — this is a cosmetic code issue, the maths is correct.

Methods

Interface design: HealthManagement is an interface whose static methods contain all logic. register() is the single entry point — it internally calls bossBarMaker() and tickUpdate() which register their respective Minestom event listeners. All other methods (damage, getHealth, etc.) can be called statically at any time.
publicstaticvoid register()

Single entry point. Calls bossBarMaker() and tickUpdate() which register the PlayerLoadedEvent and PlayerTickEvent listeners respectively. Call once during server startup.

publicstaticvoid bossBarMaker()

Registers PlayerLoadedEvent. Creates a green Health bar and blue Shield bar for each player, adds them to the HUD via BossBarManager, and initialises both tags to 100.0. Called internally by register().

publicstaticvoid damage(Player player, double hitDamage)

Applies damage routing through shield first, then health. Updates both tags on the player.

playerPlayerThe player receiving damage.
hitDamagedoubleRaw damage amount.
publicstaticvoid tickUpdate()

Registers PlayerTickEvent. Updates boss bar progress each tick. On health ≤ 0: teleports to respawn point, shows death title, applies blindness, resets HP+SP to 100. Called internally by register().

publicstaticdouble getHealth(Player player)

Returns current health value (0–100) from healthTag.

publicstaticdouble getShield(Player player)

Returns current shield value (0–100) from shieldTag.

publicstaticvoid setKilledBy(Player killed, Player killer)

Records who killed whom. Stored in a HashMap<UUID, Player>.

publicstaticPlayer getKilledBy(Player player)

Returns the player who last killed this player, or null if no kill recorded.

Kill Detection Example

java
HealthManagement.damage(target, 25);
if (HealthManagement.getHealth(target) <= 0) {
    HealthManagement.setKilledBy(target, shooter);
    String msg = target.getUsername() + " was shot by "
                + HealthManagement.getKilledBy(target).getUsername();
    // Broadcast msg to all online players...
}
org.vardinsdev.minegun
minegunLogger
Static ANSI-coloured console logger. All methods are static — no instantiation needed. Prints timestamped, prefixed log lines in four severity levels plus an ASCII art banner.
Javaorg.vardinsdev.minegun

Log Levels

MethodColourLabelUse For
info(msg)Cyan[INFO]Startup / lifecycle events
warn(msg)Yellow[WARN]Non-fatal unexpected states
error(msg)Red[ERROR]Failures, invalid usage
success(msg)Green[OK]Successful operations

Output Format

console
[HH:mm:ss] [Minegun] [LEVEL] message

Methods

publicstaticvoid info(String message)

Cyan [INFO] message. Used throughout the demo for all startup lifecycle events.

publicstaticvoid warn(String message)

Yellow [WARN] message for non-critical anomalies.

publicstaticvoid error(String message)

Red [ERROR] message. Called in giveCommand when console tries to give itself a weapon.

publicstaticvoid success(String message)

Green [OK] message. Used when a weapon is given to a player or the demo server finishes starting.

publicstaticvoid printBanner()

Prints the purple/pink MineGun ASCII art banner to stdout. Called once at the very start of Main.java.

Usage

java
minegunLogger.printBanner();
minegunLogger.info("Server starting...");
minegunLogger.success(player.getUsername() + " received a Rifle");
minegunLogger.warn("Cooldown map may be growing");
minegunLogger.error("Console cannot use /give");
org.vardinsdev.minegun.Weapons
Rifle
Hitscan rifle. Right-click fires a step-based ray. Deals 25 custom damage via HealthManagement, spawns CRIT particles along the beam, plays sound effects, and broadcasts kill messages to all online players.
Javaorg.vardinsdev.minegun.WeaponsMinestom

Item Properties

PropertyValue
MaterialWOODEN_HOE
Display NameRifle — NamedTextColor.YELLOW
Lore"Custom Made Weapon" / "By: VardinsDev"

Stats

StatValue
Fire cooldown25 ms
Max range100 blocks
Step size0.5 blocks
Custom damage25 (via HealthManagement)
Vanilla damage12f DamageType.ARROW — immediately healed
Trail particleCRIT
Fire soundENTITY_FIREWORK_ROCKET_BLAST (vol 0.25)
Hit confirmENTITY_EXPERIENCE_ORB_PICKUP on shooter (3 tick delay)
Hit soundENTITY_GENERIC_HURT on victim (3 tick delay)

Methods

publicstaticvoid givePlayer(Player player)

Builds and gives a WOODEN_HOE with custom name/lore. Logs a success message.

publicstaticvoid register(InstanceContainer instanceContainer)

Registers PlayerUseItemEvent (via MinecraftServer.getGlobalEventHandler()) filtered to WOODEN_HOE. Calls RaycastWeapons.shoot(player, 25L, instanceContainer, Particle.CRIT, false) and applies HealthManagement.damage(playerHit, 25) on a successful hit.

instanceContainerInstanceContainerUsed for block collision and particle broadcast.

Fire Sequence

flow
Right-click (WOODEN_HOE)
  └─ 25ms cooldown gate
       └─ Raycast (0.5 step, 100 block max)
            ├─ Solid block hit → stop
            ├─ Player hit
            │    ├─ FIREWORK_ROCKET_BLAST on victim
            │    ├─ DamageType.ARROW 12f + instant heal
            │    ├─ HealthManagement.damage(victim, 25)
            │    ├─ health ≤ 0?
            │    │    ├─ setKilledBy, log kill
            │    │    └─ Broadcast kill message (yellow, all players)
            │    └─ +3 ticks: ORB_PICKUP → shooter, GENERIC_HURT → victim
            └─ Miss → CRIT particle at step point
  └─ FIREWORK_ROCKET_BLAST on shooter
org.vardinsdev.minegun.Weapons
RocketLauncher
Explosive launcher. Same raycast pattern as the Rifle, but produces FLAME particles and sends an ExplosionPacket (radius 3.5) when the ray strikes either a solid block or a player. Direct player hits also deal 25 custom damage via HealthManagement.damage().
Javaorg.vardinsdev.minegun.WeaponsMinestom

Item Properties

PropertyValue
MaterialWOODEN_AXE
Display NameRocket Launcher — NamedTextColor.YELLOW
Lore"Custom Made Weapon" / "By: VardinsDev"

Stats

StatValue
Fire cooldown25 ms
Max range100 blocks
Step size0.5 blocks
Block hitExplosionPacket broadcast (radius 3.5)
Direct hit damage25 via HealthManagement.damage() + ExplosionPacket
Trail particleFLAME
Fire soundENTITY_FIREWORK_ROCKET_BLAST (vol 0.25)
Explosion mechanics: The explosion is a client-side ExplosionPacket broadcast (radius 3.5, no block destruction). It fires on both block hits and player hits. Block destruction is not performed — the explosion is visual/audio only.

Methods

publicstaticvoid givePlayer(Player player)

Builds and gives a WOODEN_AXE with custom name/lore. Logs a success message.

publicstaticvoid register(InstanceContainer instanceContainer)

Registers PlayerUseItemEvent (via MinecraftServer.getGlobalEventHandler()) filtered to WOODEN_AXE. Calls RaycastWeapons.shoot(player, 25L, instanceContainer, Particle.FLAME, true). On a player hit, also calls HealthManagement.damage(playerHit, 25).

instanceContainerInstanceContainerUsed for block collision and particle broadcast.

Fire Sequence

flow
Right-click (WOODEN_AXE)
  └─ 25ms cooldown gate
       └─ Raycast (0.5 step, 100 block max)
            ├─ Solid block hit
            │    ├─ ExplosionPacket(radius 3.5) broadcast → stop
            ├─ Player hit
            │    ├─ ExplosionPacket(radius 3.5) broadcast
            │    ├─ FIREWORK_ROCKET_BLAST on victim
            │    ├─ DamageType.ARROW 12f + instant heal
            │    ├─ HealthManagement.damage(victim, 25)
            │    ├─ health ≤ 0?
            │    │    ├─ setKilledBy, log kill
            │    │    └─ Broadcast kill message (yellow, all players)
            │    └─ +3 ticks: ORB_PICKUP → shooter, GENERIC_HURT → victim
            └─ Miss → FLAME particle at step point
  └─ FIREWORK_ROCKET_BLAST on shooter
org.vardinsdev.minegun.demo
Main
Complete demo server entry point. Wires together all MineGun systems in a flat stone arena with a zombie test dummy. Reference only — not for production.
Javaorg.vardinsdev.minegun.demo
Entry point bug: The method signature is static void main() — it's missing public and the String[] args parameter, so the JVM won't find it automatically. Fix to public static void main(String[] args) before running.

Startup Sequence

  1. minegunLogger.printBanner()
  2. Init server with Auth.Online() (real Mojang auth)
  3. Create instance, fill Y 39–40 with Stone, enable LightingChunk
  4. Register Rifle and RocketLauncher
  5. Register /give command
  6. On AsyncPlayerConfigurationEvent: set instance, respawn Pos(0,42,0), permission 4, give Rifle
  7. On PlayerGameModeRequestEvent: allow F3+F4 for perm ≥ 2
  8. Register HealthManagement boss bars + tick update
  9. Start server on 0.0.0.0:25565
  10. Spawn zombie dummy at Pos(1,42,1)
org.vardinsdev.minegun.demo
giveCommand
In-game /give command. Gives the executing player a weapon. Requires permission level ≥ 2. Tab-completes weapon names.
Javaorg.vardinsdev.minegun.demo

Usage

in-game
/give Rifle
/give RocketLauncher

Behaviour

  • Player-only — console triggers minegunLogger.error()
  • Requires permission level ≥ 2
  • Auto-complete via ArgumentType.Word(...).from("RocketLauncher","Rifle")
  • Case-insensitive weapon matching

Registration

java
MinecraftServer.getCommandManager().register(new giveCommand());
org.vardinsdev.minegun.demo
TestDummy
Spawns a stationary zombie for weapon testing. No AI goals — stands still as a target dummy.
Javaorg.vardinsdev.minegun.demo

Method

publicstaticvoid createDummy(InstanceContainer instanceContainer)

Creates an EntityCreature(EntityType.ZOMBIE) and spawns it at Pos(1, 42, 1). The zombie has no AI so it stands still.

Note: The hitscan system only detects players, not entities. The zombie is a visual target — shooting it won't register as a hit via weapons.isPlayerAtPosition.
java
EntityCreature zombie = new EntityCreature(EntityType.ZOMBIE);
zombie.setInstance(instanceContainer, new Pos(1, 42, 1));
zombie.spawn();