:api: the plugin's public API. It holds the two types generated mob behaviours share with the plugin, the service
other plugins ask BloodNight through, and the events they can listen to.
The module is small on purpose. It contains no logic, only the contract between three parties:
- Generated behaviour code. Every custom mob's node graph is compiled at runtime into a class implementing
CompiledBehaviour. Its constructor receives aMobContext. These two interfaces are the only types the plugin and generated code share. - The node platform in bukkit-nodes, which builds one entry node per
CompiledBehaviourmethod and reads the mob and its items throughMobContext. - Other plugins, which ask BloodNight through
BloodNightServiceand react to it through the events inapi.event.
CompiledBehaviour has one method per trigger, and every method is a no-op by default, so a generated class overrides
only the triggers its graph uses. Each living mob gets its own instance, which is why state such as cooldowns is per
mob.
All packages are @NullMarked (JSpecify): everything is non-null unless annotated @Nullable.
de.eldoria.bloodnight.api.internal.CompiledBehaviour(for generated code): behaviour of a custom mob. Lifecycle methods (onSpawn,onNightEnd,onTick,onDebug) and event methods that receive the Bukkit event (onDamage,onDamageByEntity,onDamageByPlayer,onHit,onKill,onDeath,onTeleport,onTargetChange,onProjectileShoot,onProjectileHit,onExplosionPrime,onExplode,onExtensionDamage,onExtensionDeath).de.eldoria.bloodnight.api.internal.MobContext(for generated code): what a behaviour knows about its mob: the entity, its extension (the entity riding or carrying it, if any) anditem(id), a copy of an item from the plugin's item registry.de.eldoria.bloodnight.api.BloodNightService: whether and which blood nights run (RunningNight), the next one (NightForecast), the chance of a coming night, force and cancel; whether an entity is a BloodNight mob, its id, and spawning a mob; a mob's details (MobInfo: names by language, entity type, store, weight) and its weight in a world; whether and how a world has blood nights (WorldInfo). Registered with Paper's services manager;BloodNightProvider.get()finds it from anywhere.de.eldoria.bloodnight.api.event.night.BloodNightBeginEvent: a blood night is about to begin in a world. Cancellable; cancelling it keeps the night an ordinary one.de.eldoria.bloodnight.api.event.night.BloodNightEndEvent: a blood night has ended in a world;reason()tells why (TIME,CANCELLED,DISABLED,RELEASEDafter a dragon fight,SHUTDOWN).de.eldoria.bloodnight.api.event.mob.CustomMobSpawnEvent: a spawning entity is about to become a BloodNight mob. Cancellable; cancelling it keeps the entity as it is.de.eldoria.bloodnight.api.event.mob.CustomMobDeathEvent: a BloodNight mob died; its drops can still be changed.de.eldoria.bloodnight.api.event.mob.CustomMobNightEndEvent: a BloodNight mob's night is over and it is about to go or turn ordinary. Cancellable;action(...)changes what happens (REMOVE,REVERT,KEEP).de.eldoria.bloodnight.api.event.DeathActionEvent: a death is about to cause lightning, thunder or a shockwave. Cancellable, per action.de.eldoria.bloodnight.api.event.BloodNightSettingsChangeEvent: the settings changed and are in use;cause()tells why (RELOAD,EDITOR,COMMAND,STORE,CONVERT).de.eldoria.bloodnight.api.internal.MovementPreset(for generated code): how a mob moves on top of its vanilla AI.
Nights carry their number, night(): the day the night begins on, or the period for worlds without a day cycle (the
Nether and the End have timed blood nights). The night events are world events, so getWorld() names the world.
BloodNightService bloodNight = BloodNightProvider.get();
if (bloodNight.isRunning(world)) { ... }
bloodNight.next(world, 30).ifPresent(next -> ...);
bloodNight.customMobId(entity).ifPresent(id -> ...);On Folia, force and cancel belong on the global region and spawn on the region owning the location; the queries
can be called from anywhere.
The module is published to EldoNexus with every release:
repositories { maven("https://eldonexus.de/repository/maven-public/") }
dependencies { compileOnly("de.eldoria.bloodnight:api:<version>") }Depend on BloodNight in your paper-plugin.yml so it loads first.
@EventHandler
public void onBegin(BloodNightBeginEvent event) {
if (event.getWorld().getName().equals("lobby")) event.setCancelled(true);
}The plugin fires BloodNightBeginEvent from its regular night check (and when an admin forces a night that has
already begun). BloodNightEndEvent fires when the world's time leaves the night, when an admin cancels a running
blood night, when the world is disabled while one runs, and for every running blood night when the plugin disables.
Depends on: the Paper API (compileOnly, through the bloodnight.paper convention plugin) and JSpecify.
Used by: bukkit-nodes and core (both as api dependencies, so it
reaches catalog through bukkit-nodes).
The module has no tests of its own; it is built with everything else:
./toolchain.sh be-build # formatting check, tests, SpotBugs, jars
./toolchain.sh be-format # apply formatting and license headers