
Allium
A modern, secure Essentials solution
- Загрузки
- 105
- Подписчики
- 1
- Обновлён
- 7 июля 2026 г.
- Лицензия
- GPL-3.0-only
Опубликован 5 апреля 2026 г.
Allium is a modern Essentials-style Paper plugin built for servers that want one cohesive core instead of a pile of loosely connected utility plugins.
It combines everyday player commands, staff tooling, moderation systems, economy utilities, advanced chat handling, creative-mode restrictions, Discord integration, and custom world systems into a single package that is designed to feel practical on a real server.
If you run a survival server, a semi-vanilla community, or a staff-heavy admin environment and keep finding yourself thinking “this should already be built in”, Allium is aimed directly at that problem.
Why Allium
- One plugin for the core systems most servers actually need
- Strong admin and moderation tooling, not just player conveniences
- Modern integrations with Vault, PlaceholderAPI, LuckPerms, DiscordSRV, PacketEvents, Oraxen, and Floodgate
- Built around real server-owner workflows: hiding commands, creative auditing, chat cleanup, ticket/escalation style tooling, timed fly, vouchers, utility items, and more
Feature Highlights
Core player utilities
- Homes, bed homes, warps, spawn,
/back, offline location tracking, and full teleport request flow - Private messages, reply, mail, social spy, notes, and
/whois - Economy support with balances, payments, cheques, and XP vouchers
- Utility commands like
/heal,/feed,/god,/fly,/nv,/speed,/trash,/more,/itemdb,/skull
Advanced item and reward systems
- Flexible
/giveand/ihandling - Dialog-based
/rename,/lore, and nickname editing - Voucher items with redeem commands and weighted permission grants
- Cheques and XP bottles as redeemable item-backed value
- Spawner core items and spawner-crafting support
Staff and admin tooling
- Freeze, handcuffs, vanish, creative controls, invsee, ender chest access, and detailed player inspection
/delmsgchat moderation with resend support and Discord mirror cleanup- Command/plugin hiding via
hide.yml - Group-based hidden command inheritance with LuckPerms-aware parent support
- Escalation-ready admin workflows and offline state tracking
Chat system
- Configurable channel system with built-in global and staff chat
- Discord-linked channel routing
- Word/phrase filter with token, phrase, substring, and regex modes
- Spam blocker with repeated-message detection and normalization
- Hover/click formatting, placeholder support, and moderation overlays
Server protection and creative controls
- Creative Manager with per-action permissions for place, break, use, interact, drop, pickup, spawn, and inventory behavior
- Creative blacklists for blocks and entities
- Command hiding and tab completion filtering
- Anti-alt / security-oriented listener support
World and custom content systems
- Integrated custom ore generation for Oraxen ores
- Pregeneration command with ore placement support
- Oraxen custom smelting hooks
- Note block / custom block protection helpers
- Creeper explosion regeneration and related world safety logic
Integrations
Allium is designed to work well with common modern server stacks.
- Vault
- LuckPerms
- PlaceholderAPI
- DiscordSRV
- PacketEvents
- Oraxen
- Floodgate
- mcMMO
Most integrations are soft dependencies, so you can run a smaller setup and still use the rest of the plugin.
Good Fit For
- Survival and SMP servers that want a stronger core plugin
- Servers replacing a pile of Essentials-style utilities with one system
- Staff teams that need moderation, visibility control, and audit-friendly tools
- Servers using DiscordSRV, PlaceholderAPI, LuckPerms, and custom content plugins
Quick Examples
- Give staff their own live in-game + Discord-linked staff chat
- Hide
/plugins,/version, and sensitive tab-completes from normal players - Let players use temporary fly time without permanent fly permission
- Turn XP, money, or perks into redeemable items
- Run
/delmsgand clean up moderated chat quickly - Generate custom silver/galena ores directly in world generation
Installation Overview
- Install Allium on a Paper server.
- Add Vault and LuckPerms if you want economy/chat/group integration.
- Add PlaceholderAPI if you want placeholder-driven formatting.
- Add DiscordSRV if you want Discord-linked channels and staff relay.
- Add PacketEvents if you want the best chat resend/deletion behavior.
- Review
config.yml,lang.yml,hide.yml, and thechat/module files.
Documentation
For usage instructions, see the official Allium documentation.
Current Direction
Allium is actively growing beyond a traditional Essentials replacement. The current focus is on:
- better chat moderation and channel systems
- stronger admin workflows
- smoother Discord integration
- deeper custom content/world integration
- keeping one coherent core instead of fragmenting into many separate plugins
Ченджлог
0.2.6aРелиз26.1.1, 26.1.2, 26.2 · 7 июля 2026 г.
Allium v0.2.6a
Wiki: https://github.com/castledking/Allium/wiki
Highlights
- Paper Brigadier compatibility —
CommandManagernow correctly handles commands registered via Paper'sLifecycleEvents.COMMANDS(e.g., AbyssalLib'sCommandBus, custom Brigadier dispatcher commands). These commands appear asVanillaCommandWrapperin the command map, whosetestPermissionSilent()can false-negative. Allium now allows these commands through and defers permission evaluation to the server's native Brigadier dispatch. - Derived permission scoped to Allium-owning plugins only — The legacy heuristic that produced synthetic permissions like
<pluginName>.<commandName>is now only applied to commands owned by Allium itself. For all other plugins — whetherPluginCommand,VanillaCommandWrapper, or custom wrappers — Allium trusts the command's native permission system.
Technical Details
Problem
Commands registered through Paper's modern LifecycleEvents.COMMANDS API (used by AbyssalLib's CommandBus, among others) do not go through Bukkit's plugin.yml command registration. Instead, they register LiteralArgumentBuilder<CommandSourceStack> nodes directly into Mojang's Brigadier CommandDispatcher.
Paper wraps these dispatcher-only nodes in VanillaCommandWrapper (org.bukkit.craftbukkit.command.VanillaCommandWrapper) so they appear in SimpleCommandMap.knownCommands for Bukkit API compatibility. However, VanillaCommandWrapper.testPermissionSilent() does not reliably evaluate the underlying Brigadier node's requires() predicates, often returning false even when the player holds the correct permission.
This caused Allium's CommandManager to block all such commands and display the Allium "no-permission" message, even when the command's native permission system would have allowed execution.
Attempted Fixes (Rejected)
- Class name matching (
className.contains("Brigadier") || className.contains("Wrapper")) — fragile, case-sensitive, and missesVanillaCommandWrapperin the general case since the wrapper extendsCommand/PluginCommandvia different paths depending on the Paper version. PluginIdentifiableCommandinstanceof check — Paper'sMinecraftCommandMap$CommandWrappermay implementPluginIdentifiableCommandwith anullplugin, making the check useless.PluginCommandinstanceof check — some Paper wrapper variants extendPluginCommanddirectly, so negatingPluginCommanddoesn't reliably capture dispatcher-only commands.
Actual Fix
The fix uses a class-name-exact check for VanillaCommandWrapper as the first gate in hasPermissionForCommand():
if (className.contains("VanillaCommandWrapper")) {
return true;
}
This immediately allows all Brigadier-dispatcher-registered commands and defers permission evaluation to the server's native dispatch (which correctly evaluates the CommandNode.canUse() predicates at execution time).
For PluginCommand instances, the revised logic is:
- Explicit permission set —
command.getPermission()is non-null →testPermissionSilentalready checked it, allow. - Derived permission — only computed for commands whose
PluginIdentifiableCommand.getPlugin()returns"Allium". The derived string isallium.<baseCommand>. - All other commands (
PluginCommandfrom other plugins, vanilla commands with matching Bukkit wrappers) — trusttestPermissionSilent.
getPluginForCommand Fallback Fix
The fallback in getPluginForCommand previously returned commandName.toLowerCase() when no plugin could be identified, causing the derived permission to be <commandName>.<commandName> (e.g., relique.relique). This is now null, which propagates through getDerivedPluginCommandPermission as null — treated as "no permission required".
Support and Feedback
Issues: https://github.com/castledking/Allium/issues Wiki: https://github.com/castledking/Allium/wiki Discord: https://discord.com/invite/pCKdCX6nYr Website: https://castled.codes/
0.2.5aРелиз26.1.1, 26.1.2, 26.2 · 6 июля 2026 г.
Allium v0.2.5a
Wiki: https://github.com/castledking/Allium/wiki
Highlights
- Translation probe config corruption fixed —
applyBundledDefaultsno longer callsconfig.save(), preventing the old JAR's defaults from being written to disk on every restart. A newseedMissingProbeConfig()method writes thetranslation-probesection to disk only when the file actually lacks it (usingcontains(path, true)to ignore in-memory defaults). - Hardcoded probe check fallback —
loadChecks()now cascades: disk config → bundled resource →createDefaultChecks()with 16 hardcoded checks (meteor + 14 IPN + 2 libIPN). This ensures the probe always has checks even when both the disk config and old JAR resource lack the section. - Probe enabled fallback —
isEnabled()now falls back to rootenabled, so the probe registers even when thetranslation-probesection is entirely absent from the config file. - Stealthier probe —
CloseWindowis sent immediately (no 2-tick delay, sign GUI never renders), and the sign position isY - 30below the player (out of view). Zero visual flicker. /allium modguard reload— New command unregisters the probe, reloads the config from disk, and re-registers. Requiresallium.admin.
Bug Fixes
| Bug | Root Cause | Fix |
|---|---|---|
| Config file overwritten on every restart | applyBundledDefaults called config.save() with copyDefaults(true), writing old JAR defaults back to disk |
Removed config.save() and copyDefaults(true) from applyBundledDefaults |
translation-probe section never persisted to disk |
seedMissingProbeConfig used config.contains("translation-probe") which returned true from defaults set by applyBundledDefaults — even though the file lacked the section |
Changed to config.contains("translation-probe", true) to ignore defaults and check only the file |
| Probe has no checks after config corruption | loadChecks() had no fallback when both disk config and bundled resource lacked the checks section |
Added createDefaultChecks() with 16 hardcoded checks as final fallback |
Probe doesn't fire when translation-probe section is missing |
registerTranslationProbe() and isEnabled() returned false for config.getBoolean("translation-probe.enabled", false) when the section was absent |
Changed fallback to config.getBoolean("translation-probe.enabled", config.getBoolean("enabled", false)) |
| Probe delay too slow (3s) and timeout too long (4s) | Config defaults for delay-ticks (60) and timeout-ticks (80) were unnecessarily conservative |
Changed to 10 ticks (0.5s) and 30 ticks (1.5s) |
| Sign GUI visible to player on join | CloseWindow was sent after a 2-tick delay, giving the client time to render the sign |
CloseWindow sent immediately in the same packet batch; sign placed 30 blocks below player |
| No reload command — required full restart for config changes | No implementation | Added /allium modguard reload which calls ModGuardManager.reload() |
Files Changed (4)
| File | Change |
|---|---|
managers/security/ModGuardManager.java |
applyBundledDefaults no longer saves to disk; added seedMissingProbeConfig() with contains(path, true) guard; added reload() static method; added /allium modguard reload dispatcher |
managers/security/ModGuardTranslationProbe.java |
Added createDefaultChecks() (16 hardcoded checks); loadChecks() now cascades config → bundled → hardcoded; isEnabled() falls back to root enabled; CloseWindow immediate; sign Y -30; delay-ticks 10, timeout-ticks 30 |
modguard/config.yml |
Cleaned up: removed debug, regex-matching, case-sensitive, banned-mods, allowed-mods; added translation-probe section with all 16 checks with require-corroboration-for-kick: false |
commands/Core.java |
Added handleModGuardCommand() for /allium modguard reload |
Technical Details
Config Persistence Chain
The old code had two bugs forming a corruption loop:
applyBundledDefaultscalledconfig.save()with the old JAR's bundled config (notranslation-probesection), overwriting user changes on every restart- Even after removing
config.save(),seedMissingProbeConfigcheckedconfig.contains("translation-probe")— butapplyBundledDefaultshad already set the NEW bundled resource as defaults, which DO contain the section. Socontains()returnedtruefrom defaults andseedMissingProbeConfigreturned early without persisting
Fix: seedMissingProbeConfig now uses config.contains("translation-probe", true) to skip default-only matches. It also writes the full 16-check section to disk when absent, so subsequent restarts load it directly from the file.
Probe Check Fallback Chain
loadChecks() now follows this order:
config().getConfigurationSection("translation-probe.checks")— reads from the in-memory config (loaded from disk or defaults)loadBundledChecks()— reads from the JAR resource (modguard/config.yml) and copies checks into the in-memory configcreateDefaultChecks()— 16 hardcoded checks: meteor + 14 IPN (key.inventoryprofiles.*) + 2 libIPN
This ensures the probe always has checks regardless of which JAR version is deployed or whether the config file contains the section.
Support and Feedback
Issues: https://github.com/castledking/Allium/issues Wiki: https://github.com/castledking/Allium/wiki Discord: https://discord.com/invite/pCKdCX6nYr Website: https://castled.codes/
0.2.4aРелиз26.1.1, 26.1.2, 26.2 · 30 июня 2026 г.
Allium v0.2.4a
Wiki: https://github.com/castledking/Allium/wiki
Highlights
- Vault softdepend crash fixed — Allium no longer crashes at startup when Vault is absent. All Vault-typed fields and method signatures were changed to
Object, with casts at call sites.VaultEconomyProvideris only created when Vault'sEconomyclass is actually loadable. TheFormatChatListeneris skipped entirely when Vault Chat isn't available. - PacketEvents softdepend crash fixed — Allium no longer crashes at startup when PacketEvents is absent. The
Glowcommand andGlowListenerare guarded behindisPacketEventsAvailable(), and theglowCommandfield was relaxed fromGlowtoObjectto prevent class loading. - CrowBar 128-block radius limit removed — Added
shouldBeVisibleIgnoreDistancetoPartyManagerso players beyond 128 blocks remain visible on the locator bar, with only same-world and forced-visibility checks applied. - NPC locator bar flash fixed —
PartyManager.updatePlayerVisibilitynow checksviewer.canSee(target)before callingshowPlayer, preventing NPC info packets from being resent every 5 ticks when the NPC is already visible.
Bug Fixes
| Bug | Root Cause | Fix |
|---|---|---|
| Plugin fails to enable without Vault | Vault types in field/method signatures cause NoClassDefFoundError during class loading; new VaultEconomyProvider runs before Vault availability check |
Changed Vault-typed fields/methods to Object; guarded VaultEconomyProvider creation; skipped FormatChatListener when vaultChat == null |
| Plugin fails to enable without PacketEvents | Glow class references PacketEvents types in method signatures; new Glow(this) at unconditional line 1524 forces class loading |
Guarded Glow/GlowListener creation behind isPacketEventsAvailable(); changed glowCommand field to Object |
| Players beyond 128 blocks hidden on CrowBar | shouldBeVisible applies distance filtering which limits range to 128 blocks |
Added shouldBeVisibleIgnoreDistance that skips distance check while keeping same-world and visibility overrides |
| NPCs flash on locator bar every 5 ticks | updatePlayerVisibility calls showPlayer unconditionally every interval |
Guarded showPlayer behind viewer.canSee(target) |
Files Changed (8)
| File | Change |
|---|---|
PluginStart.java |
Changed Vault fields/methods to Object; guarded VaultEconomyProvider and FormatChatListener creation; guarded Glow/GlowListener behind isPacketEventsAvailable() |
commands/Glow.java |
No structural change (guarded at call site) |
DB/PermissionCache.java |
getVaultPermission returns Object |
listeners/security/CommandManager.java |
vaultPermission field / setupVaultPermission now Object |
listeners/security/MaintenanceManager.java |
perms field / constructor param now Object |
managers/core/PartyManager.java |
Added shouldBeVisibleIgnoreDistance; canSee guard in updatePlayerVisibility |
packetevents/CrowBarDataSender.java |
Uses shouldBeVisibleIgnoreDistance instead of shouldBeVisible |
listeners/security/ConnectionManager.java |
vaultChat null guard in reloadChatFormatter |
Technical Details
Vault Class Loading Fix
Paper 1.21+'s PluginClassLoader eagerly resolves type references during class definition. Having Vault types in field declarations or method return types causes NoClassDefFoundError even when the code path never executes. Fix: all Vault-typed fields and return types are now Object, with casts at every call site.
PacketEvents Class Loading Fix
Same mechanism as Vault — PacketEvents types in Glow's method signatures crash class loading. Glow is now only instantiated when isPacketEventsAvailable() returns true, so the class is never loaded on servers without PacketEvents.
Support and Feedback
Issues: https://github.com/castledking/Allium/issues Wiki: https://github.com/castledking/Allium/wiki Discord: https://discord.com/invite/pCKdCX6nYr Website: https://castled.codes/
0.2.3aРелиз26.1.1, 26.1.2, 26.2 · 29 июня 2026 г.
Wiki: https://github.com/castledking/Allium/wiki
Highlights
- CanvasMC 26.2 support — Migrated from Paper API to Canvas API (
io.canvasmc.canvas:canvas-api). Canvas is a Folia fork targeting Minecraft 26.2 (build 835). All scheduling now goes through the newSchedulerAdapterin thecodes.castled.allium.schedulerpackage, which properly handles Canvas's regionized threading model. - New SchedulerAdapter — Complete rewrite of the scheduling layer. The old
util/SchedulerAdapter.java(587 lines of reflection-heavy Folia detection) is replaced by a clean 426-linescheduler/SchedulerAdapter.javawith a dedicatedTaskHandleabstraction. The old class is kept as a deprecated thin wrapper delegating to the new one, ensuring backward compatibility. - Tab completion API — New
AlliumTabCompletionsEvent+AlliumTabCompletionsListenerthat populate tab completions with all online non-vanished players when PartyManager is enabled. Other plugins can fire this event to get Allium-aware player name suggestions. - Vault initialization guard — Fixed a race condition where
registerVaultDependentListeners()could be called multiple times if Vault initialized successfully and then the retry timer fired again. Added aregisteredboolean flag to ensure one-time registration. - FAWE removed — FastAsyncWorldEdit dependency and repositories dropped from
pom.xml. No longer a soft dependency.
Minecraft Version Support
| Version | Status |
|---|---|
| 26.2 (Canvas build 835) | Primary target |
| 26.2 (Folia) | Supported |
| 1.21.x (Paper/Spigot) | Supported via fallback |
API / Dependency Changes
pom.xml:io.papermc.paper:paper-apireplaced withio.canvasmc.canvas:canvas-apipom.xml:<paper.version>bumped from26.2.build.37-alphato26.2.build.835-alphapom.xml: Addedcanvasmc-releasesandcanvasmc-snapshotsrepositoriespom.xml: RemovedFastAsyncWorldEdit-Coredependencypom.xml: Removed IntellectualSites repositoriesplugin.yml: RemovedFastAsyncWorldEditandWorldEditfromsoftdepend
New Files
| File | Description |
|---|---|
scheduler/SchedulerAdapter.java |
Full Folia/Canvas scheduling adapter with global, async, entity, and location scheduling |
scheduler/TaskHandle.java |
Lightweight abstraction over BukkitTask and Folia ScheduledTask |
events/AlliumTabCompletionsEvent.java |
Custom event for populating player name tab completions |
listeners/AlliumTabCompletionsListener.java |
Handles the event — returns all online non-vanished players when PartyManager is enabled |
SchedulerAdapter API
The new codes.castled.allium.scheduler.SchedulerAdapter provides:
// Global (main thread equivalent)
SchedulerAdapter.runGlobal(plugin, runnable)
SchedulerAdapter.runLaterGlobal(plugin, runnable, delayTicks)
SchedulerAdapter.runRepeatingGlobal(plugin, runnable, delayTicks, periodTicks)
// Async
SchedulerAdapter.runAsyncNow(plugin, runnable)
SchedulerAdapter.runAsyncLater(plugin, runnable, delayTicks)
SchedulerAdapter.runAsyncRepeating(plugin, runnable, delayTicks, periodTicks)
// Entity (Folia entity scheduler, Bukkit fallback)
SchedulerAdapter.runEntity(plugin, entity, runnable, retired)
SchedulerAdapter.runLaterEntity(plugin, entity, runnable, delayTicks)
SchedulerAdapter.runEntityRepeating(plugin, entity, runnable, retired, delayTicks, periodTicks)
// Location (Folia region scheduler, Bukkit fallback)
SchedulerAdapter.runAtLocation(plugin, location, runnable)
SchedulerAdapter.runAtLocationLater(plugin, location, runnable, delayTicks)
SchedulerAdapter.runAtLocationRepeating(plugin, location, runnable, delayTicks, periodTicks)
// Utility
SchedulerAdapter.cancelTasks(plugin)
SchedulerAdapter.isFolia()
All methods return codes.castled.allium.scheduler.TaskHandle which wraps both BukkitTask and Folia's ScheduledTask.
Deprecated API
codes.castled.allium.util.SchedulerAdapter is now a deprecated wrapper. All methods delegate to the new codes.castled.allium.scheduler.SchedulerAdapter. Existing code continues to work but should be migrated:
| Old (util) | New (scheduler) |
|---|---|
run(task) |
runGlobal(plugin, task) |
runLater(task, delay) |
runLaterGlobal(plugin, task, delay) |
runTimer(task, delay, period) |
runRepeatingGlobal(plugin, task, delay, period) |
runAsync(task) |
runAsyncNow(plugin, task) |
runLaterAsync(task, delay) |
runAsyncLater(plugin, task, delay) |
runAtEntity(entity, task) |
runEntity(plugin, entity, task, null) |
runAtEntityLater(entity, task, delay) |
runLaterEntity(plugin, entity, task, delay) |
Files Changed (31)
| File | Change |
|---|---|
pom.xml |
Canvas API, build 835, removed FAWE, added Canvas repos |
plugin.yml |
Removed FAWE/WorldEdit softdepend |
scheduler/SchedulerAdapter.java |
New — full scheduling adapter |
scheduler/TaskHandle.java |
New — task handle abstraction |
events/AlliumTabCompletionsEvent.java |
New — tab completion event |
listeners/AlliumTabCompletionsListener.java |
New — tab completion handler |
util/SchedulerAdapter.java |
Rewritten as deprecated wrapper (~500 lines removed) |
PluginStart.java |
Vault init guard, SchedulerAdapter migration for channel/Discord retry |
Core.java |
Bukkit.getScheduler() calls replaced with SchedulerAdapter |
PregenCommand.java |
SchedulerAdapter for async completion callback |
StaffChatCommand.java |
SchedulerAdapter for channel switch |
InventoryManager.java |
SchedulerAdapter for autosave |
FormatChatListener.java |
SchedulerAdapter for phase renderer |
StaffChatListener.java |
SchedulerAdapter for message redirect |
WolfBehaviorListener.java |
SchedulerAdapter for delayed task |
CommandManager.java |
SchedulerAdapter migration |
ConnectionManager.java |
SchedulerAdapter migration, significant refactor |
FreecamDetector.java |
SchedulerAdapter migration |
HandcuffsListener.java |
SchedulerAdapter migration |
IPNDetector.java |
SchedulerAdapter migration |
ModDetectionListener.java |
SchedulerAdapter migration |
VanishListener.java |
SchedulerAdapter migration |
FaweActivityListener.java |
SchedulerAdapter migration, FAWE removal |
OreGenerationListener.java |
SchedulerAdapter migration |
AlliumChannelManager.java |
SchedulerAdapter migration |
DiscordSrvMessageBridge.java |
SchedulerAdapter migration |
GradientNameManager.java |
SchedulerAdapter migration |
ModGuardManager.java |
SchedulerAdapter migration |
ModGuardTranslationProbe.java |
SchedulerAdapter migration |
OreGenerationManager.java |
SchedulerAdapter migration |
CrowBarDataSender.java |
SchedulerAdapter migration |
Technical Details
Scheduler Detection
Folia/Canvas detection uses Bukkit.getServer().getClass().getMethods() to find getGlobalRegionScheduler — more reliable than string-matching server name/version. The detection result is cached in a static final boolean at class load time.
TaskHandle
Wraps either a BukkitTask (Paper/Spigot path) or a raw Folia ScheduledTask object (accessed via reflection for cancel). Thread-safe cancellation via AtomicBoolean. The isScheduled() method returns best-effort status.
Vault Initialization Fix
Previously, if initializeVault() succeeded on attempt N but the timer tick was already queued, registerVaultDependentListeners() could fire twice. The fix adds a registered[] boolean flag checked before each registration call, ensuring idempotency.
Support and Feedback
Issues: https://github.com/castledking/Allium/issues Wiki: https://github.com/castledking/Allium/wiki Discord: https://discord.com/invite/pCKdCX6nYr Website: https://castled.codes/
0.2.2aРелиз26.1, 26.1.1, 26.1.2 · 21 июня 2026 г.
Wiki: https://github.com/castledking/Allium/wiki
Highlights
- Glow command — New
/glowcommand for per-player colored glow outlines using PacketEvents virtual team packets. Supports all 16 vanilla colors, rainbow cycling, and per-color permissions. No scoreboard pollution — teams are sent directly to viewers and never registered on any Bukkit scoreboard. - Join/Quit message permissions — Permission-based join/quit message formats via
allium.join_message.<id>andallium.quit_message.<id>. Set custom formats with LuckPerms metadata. - Chat system rewrite —
ChatMessageManager,FormatChatListener, andPacketChatTrackerImplsignificantly reworked for better PacketEvents integration and staff moderation features. - Flight restoration refactor —
FlightRestorationrewritten for improved Folia compatibility and reliability. - Command management —
CommandManagernow caches the server's known commands map with a 2-second TTL, eliminating repeated reflection calls.Helpcommand caches available commands per-player with a 3-second TTL. - TP companion teleportation — Pet/entity teleport-on-TP moved from
TPlistener to dedicatedTeleportBackListenerfor cleaner separation. - Inventory snapshot optimization —
InventoryManager.saveSnapshot()simplified to run directly on the calling thread instead of throughSchedulerAdapter.run().
New Commands
| Command | Description | Permission |
|---|---|---|
/glow <color> [player] |
Set glow color (e.g. /glow red, /glow dark_aqua) |
allium.glow + allium.glow.<color> |
/glow rainbow [player] |
Enable rainbow cycling glow | allium.glow.rainbow |
/glow off [player] |
Remove glow effect | allium.glow / allium.glow.others |
New Permissions
| Permission | Description | Default |
|---|---|---|
allium.glow |
Base glow permission (grants all 16 color sub-permissions) | op |
allium.glow.<color> |
Per-color (e.g. allium.glow.red, allium.glow.blue) |
via parent |
allium.glow.rainbow |
Rainbow glow mode | op |
allium.glow.others |
Target other players | op |
allium.join_message.<id> |
Custom join message format (value from LP metadata) | — |
allium.quit_message.<id> |
Custom quit message format (value from LP metadata) | — |
allium.join_message.* |
Wildcard — grants all join message formats | staff |
allium.quit_message.* |
Wildcard — grants all quit message formats | staff |
New Config
join-and-quit-messages:
join:
enabled: true
format: "&e%name% &7has joined the server"
quit:
enabled: true
format: "&e%name% &7has left the server"
broadcast-scope: server # server, world, or global
Setting Custom Join/Quit Messages with LuckPerms
Set a permission with a metadata value on a player:
/lp user <player> meta set allium.join_message.vip.a "rift in the universe has spawned %player%"
/lp user <player> meta set allium.quit_message.vip.a "%player% has left through a rift"
Supported placeholders: %name% (display name, respects /nick), %player% (real name), %prefix% (Vault prefix), %suffix% (Vault suffix).
The first matching permission (alphabetical by suffix) is used. If no permission metadata is found, the default config format is used.
Technical Details
Glow
- Uses PacketEvents
WrapperPlayServerTeamswithTeamMode.CREATE(includes both team info and player entries in one packet) TeamMode.UPDATEfor rainbow color changes,TeamMode.REMOVEfor cleanup- Packets sent to all online players including the target (the client needs to receive the team packet to render the colored outline)
- No
Bukkit.getScoreboardManager()usage — completely virtual - Folia-safe: no region-scheduled tasks needed
Join/Quit Messages
- Handled via standard
PlayerJoinEvent/PlayerQuitEvent(main thread on both Bukkit and Folia) - Permission metadata read through Vault Chat's
getPlayerInfoString() - Falls back to default config format if no permission match found
- Vanish check: vanished players don't show join/quit messages
Chat System
ChatMessageManagerrewritten with improved message storage and retrievalPacketChatTrackerImplupdated for better PacketEvents 2.11.1 compatibilityFormatChatListenersignificantly expanded with new formatting options
SchedulerAdapter
- All scheduled tasks route through
SchedulerAdapterwhich auto-detects Folia - Folia path: uses
EntitySchedulerfor entity-specific tasks,GlobalRegionSchedulerfor global tasks - Bukkit path: uses standard
BukkitScheduler - No raw
Bukkit.getScheduler()calls in new code
Files Changed (22)
| File | Change |
|---|---|
PluginStart.java |
Glow command + listener registration, glow field |
Glow.java |
New — /glow command with PacketEvents team packets |
GlowListener.java |
New — cleanup on player quit |
JoinQuitMessages.java |
New — permission-based join/quit messages |
ChatMessageManager.java |
Rewritten — message storage, tracking, moderation |
FormatChatListener.java |
Major rewrite — chat formatting, hover, click events |
PacketChatTrackerImpl.java |
Major rewrite — PacketEvents 2.11.1 integration |
FlightRestoration.java |
Major rewrite — Folia-safe flight state management |
CommandManager.java |
Known commands caching, getCachedKnownCommands() API |
Help.java |
Available commands caching, uses CommandManager cache |
| `TeleportBackListener.java** | Extracted from TP — pet/entity companion teleport |
TP.java |
Removed inline teleport listener, now delegates |
InventoryManager.java |
Simplified snapshot saving, removed SchedulerAdapter wrapper |
AlliumPlaceholder.java |
Import cleanup |
GeneralPlaceholder.java |
Import cleanup |
TFlyManager.java |
Import cleanup, formatting |
SpawnerChangerManager.java |
Minor cleanup |
config.yml |
New join-and-quit-messages section |
lang.yml |
New glow.* message keys |
plugin.yml |
New glow command, permission definitions |
pom.xml |
Paper version 1.21.8 |
Support and Feedback
Issues: https://github.com/castledking/Allium/issues Wiki: https://github.com/castledking/Allium/wiki Discord: https://discord.com/invite/pCKdCX6nYr Website: https://castled.codes/
0.2.1aРелиз26.1, 26.1.1, 26.1.2 · 1 июня 2026 г.
Wiki: https://github.com/castledking/Allium/wiki
Highlights
- CrowBar same-world payloads — CrowBar player data is now built per recipient and only includes players in the recipient's current world.
- CrowBar quit refresh — Sends an immediate snapshot when a player quits so CrowBar clients can remove stale dots and name tags without waiting for expiry.
- CrowBar join/world snapshots — Sends delayed targeted snapshots after joins and world changes so reconnecting CrowBar clients get nearby player positions before movement updates.
- NPC filtering — Citizens NPCs are excluded from CrowBar player-data payloads.
Support and Feedback
Issues: https://github.com/castledking/Allium/issues Wiki: https://github.com/castledking/Allium/wiki Discord: https://discord.com/invite/pCKdCX6nYr Website: https://castled.codes/
0.2.0aРелиз26.1, 26.1.1, 26.1.2 · 1 июня 2026 г.
Allium v0.2.0a
Wiki: https://github.com/castledking/Allium/wiki
Highlights
- CrowBarDataSender NPC Filter — Prevents NPCs from Citizens from having their data sent to CrowBar
Support and Feedback
Issues: https://github.com/castledking/Allium/issues Wiki: https://github.com/castledking/Allium/wiki Discord: https://discord.com/invite/pCKdCX6nYr Website: https://castled.codes/
0.1.9aРелиз26.1, 26.1.1, 26.1.2 · 31 мая 2026 г.
Wiki: https://github.com/castledking/Allium/wiki
Highlights
- Citizens NPC body visibility fixed — Allium no longer strips unlisted
PLAYER_INFO_UPDATEentries for unknown player UUIDs. Citizens uses those packets to send player-NPC profile/skin data while keeping NPCs out of the tab list; removing them made the client fail to render NPC bodies. NPCs are also exempted from PartyManager body visibility hiding. - CrowBarDataSender UUID fix — Fixed a bug where the loop variable
uuid(a String) was being used instead ofplayer.getUniqueId(), causing all CrowBar clients to receive the same UUID for every player entry.
What's Fixed
- Citizens NPC bodies no longer invisible — The confirmed fix is in the PacketEvents tab-list interceptor: unknown/unlisted player-info entries now pass through unchanged instead of being removed. This preserves Citizens' spawn/profile handshake for player-type NPCs. Allium also detects Citizens NPC metadata live and skips
hidePlayer()visibility management for those NPC entities. - CrowBarDataSender player UUID — Each player object now correctly calls
player.getUniqueId().toString(). Previously, a strayuuidvariable from an unrelated context was serialized for every entry, meaning all players appeared as the same entity on the CrowBar locator bar.
Internal
.release/discord-updater-webhook.yml—message_idupdated for the current Discord release post..release/src/spigot-release.js— Modrinth download link corrected.
Requirements
- Minecraft 1.21.11
- Fabric Loader 0.18.4 or newer
- Fabric API 0.141.4 or newer
- Java 21
Комментарии
Загружаем…
