Helios Core icon

Helios Core -----

The shared foundation every Helios plugin depends on — unified storage, permissions, dashboard



HeliosCore — Developer Documentation
HeliosCore is a pure library plugin. Server owners drop it in /plugins and forget about it. This documentation is for plugin developers who want to build on top of it.
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
1. Declaring a Dependency
In your plugin.yml:
Code (YAML):

depend
:
 - HeliosCore
 
Or as a soft dependency if HeliosCore is optional:
Code (YAML):

softdepend
:
 - HeliosCore
 
2. Resolving Services
All services are registered on the Bukkit Services Manager. Use CoreServices.require() to resolve them safely — it throws a clear IllegalStateException if HeliosCore is not loaded, which is far better than a silent null crash.
Code (Java):

import dev.ninez.core.api.CoreServices ;
import dev.ninez.core.api.database.DatabaseService ;
import dev.ninez.core.api.profile.PlayerProfileService ;
public class MyPlugin extends JavaPlugin {
    private DatabaseService db ;
    private PlayerProfileService profiles ;
    @Override
    public void onEnable ( ) {
        this. db = CoreServices. require ( this, DatabaseService. class ) ;
        this. profiles = CoreServices. require ( this, PlayerProfileService. class ) ;
    }
}
 
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
3. Service API Reference
DatabaseService
HikariCP-backed connection pool. Supports SQLite (default) and MySQL.
Code (Java):

// Check if the pool is alive (no query — instant)
boolean alive = db. isConnected ( ) ;
// Run a live SELECT 1 health check
boolean ok = db. testConnection ( ) ;
// Get the last error message
String err = db. lastError ( ) ;
// Borrow a connection for a query
try ( Connection con = db. openConnection ( ) ;
      PreparedStatement ps = con. prepareStatement ( "SELECT * FROM my_table WHERE uuid = ?" ) ) {
    ps. setString ( 1, player. getUniqueId ( ). toString ( ) ) ;
    ResultSet rs = ps. executeQuery ( ) ;
    // ...
}
// Which backend is active?
DatabaseType type = db. type ( ) ; // DatabaseType.SQLITE or DatabaseType.MYSQL
String label = db. describe ( ) ;   // e.g. "SQLite (helioscore.db)"
 
Note: Always use try-with-resources. HeliosCore manages the pool lifecycle; never close the pool yourself.
---
PlayerProfileService
Persistent cache of player statistics updated each login/logout cycle.
Code (Java):

// Get a full snapshot (works for online AND offline players)
PlayerProfileSnapshot snap = profiles. profile (offlinePlayer ) ;
PlayerProfileSnapshot snap = profiles. profile (uuid, "FallbackName" ) ;
// Key fields on PlayerProfileSnapshot:
snap. username ( )                   // last known name
snap. online ( )                     // currently online?
snap. health ( ) / snap. maxHealth ( )   // last recorded HP
snap. gameMode ( )                   // "survival", "creative", etc.
snap. worldName ( )                   // last known world
snap. blockX /Y /Z ( )                 // last known coords
snap. ping ( )                       // last known ping ms
snap. firstSeenAtMillis ( )           // first join timestamp
snap. lastSeenAtMillis ( )           // last quit timestamp
snap. joinCount ( )                   // total logins
snap. totalPlaytimeTicks ( )         // accumulated playtime
snap. effectivePlaytimeTicks ( )     // total + current live session
snap. playerKills ( ) / snap. deaths ( ) / snap. killDeathRatio ( )
// Register / unregister a custom data provider (extend your own profile cards)
profiles. registerProvider (myProvider ) ;
profiles. unregisterProvider (myProvider ) ;
// List registered provider IDs
List <String > ids = profiles. providerIds ( ) ;
// Retrieve all profile cards for a player (one per provider)
List <PlayerProfileCard > cards = profiles. cards (offlinePlayer ) ;
// How many profiles are in memory?
int count = profiles. cachedProfileCount ( ) ;
 
---
CooldownService
Per-subject, per-scope in-memory cooldowns. A "scope" is just a string key for your feature (e.g. "myplugin.daily_reward").
Code (Java):

CooldownService cooldowns = CoreServices. require ( this, CooldownService. class ) ;
// Try to start a cooldown — returns false if already active
boolean started = cooldowns. tryStart ( "myplugin.warp", player. getUniqueId ( ), Duration. ofSeconds ( 30 ) ) ;
// Check if a cooldown is active
boolean active = cooldowns. isActive ( "myplugin.warp", player. getUniqueId ( ) ) ;
// Get remaining duration
Duration remaining = cooldowns. remaining ( "myplugin.warp", player. getUniqueId ( ) ) ;
// Human-readable remaining time ("14s", "2m 5s")
String text = cooldowns. remainingText ( "myplugin.warp", player. getUniqueId ( ) ) ;
// Clear a specific entry
cooldowns. clear ( "myplugin.warp", player. getUniqueId ( ) ) ;
// Unconditionally set (or overwrite) a cooldown
cooldowns. set ( "myplugin.warp", player. getUniqueId ( ), Duration. ofMinutes ( 5 ) ) ;
// Clear everything under a scope (e.g. on plugin reload)
cooldowns. clearScope ( "myplugin.warp" ) ;
// Inspect active scopes and entry counts
Collection <String > scopes = cooldowns. activeScopes ( ) ;
int count = cooldowns. activeEntryCount ( "myplugin.warp" ) ;
// Format any Duration to a human-readable string
String fmt = cooldowns. format (Duration. ofSeconds ( 90 ) ) ; // "1m 30s"
 
---
ConfigService
Managed YAML and JSON config files. All files are tracked and reloaded together on /hcore reload.
Code (Java):

ConfigService configs = CoreServices. require ( this, ConfigService. class ) ;
// Load (or create from default) a YAML file relative to your plugin's data folder
YamlConfigFile yaml = configs. loadYaml ( "settings.yml", true ) ;
FileConfiguration fc = yaml. configuration ( ) ;
// Load a JSON file
JsonConfigFile json = configs. loadJson ( "data/players.json", false ) ;
// Reload all tracked files
configs. reloadAll ( ) ;
// Look up an already-loaded file without re-loading it
Optional <YamlConfigFile > existing = configs. findYaml ( "settings.yml" ) ;
Optional <JsonConfigFile > existingJson = configs. findJson ( "data/players.json" ) ;
// List all tracked file paths
Collection <String > loaded = configs. loadedFiles ( ) ;
// Resolve a path relative to your plugin's data folder
Path absolute = configs. resolve ( "data/export.csv" ) ;
 
---
GuiService
Shared inventory click/close event routing. Extend Menu and open via the service so clicks are routed correctly without each plugin registering its own listener.
Code (Java):

GuiService guis = CoreServices. require ( this, GuiService. class ) ;
// Open a menu for a player
guis. open ( new MyShopMenu (player ), player ) ;
// Check what a player is viewing
Optional <Menu > current = guis. currentMenu (player ) ;
boolean viewing = guis. isViewing (player, MyShopMenu. class ) ;
 
---
PermissionService
Registers Bukkit Permission objects at startup. Compatible with LuckPerms and any Bukkit-aware permissions manager.
Code (Java):

PermissionService perms = CoreServices. require ( this, PermissionService. class ) ;
// Register a single node
perms. registerPermission (
    "myplugin.command.fly",
    "Allows use of /fly",
    PermissionDefault. OP,
    Map. of ( )
) ;
// Register from a PermissionNode record (preferred for bulk registration)
perms. registerPermissions (MyPermissionNodes. defaults ( ) ) ;
// Check permission (same as sender.hasPermission but works with the registry)
boolean allowed = perms. has (sender, "myplugin.command.fly" ) ;
 
---
PlayerService
Fast player lookup with fuzzy name matching.
Code (Java):

PlayerService players = CoreServices. require ( this, PlayerService. class ) ;
// Find an online player by name fragment
PlayerLookupResult <Player > result = players. findOnlinePlayer ( "Notc" ) ;
if (result. found ( ) && !result. multiple ( ) ) {
    Player target = result. player ( ) ;
}
if (result. multiple ( ) ) {
    sender. sendMessage ( "Multiple matches: " + result. describeMatches ( 5 ) ) ;
}
// Find any known player (online or offline, from Bukkit's cache)
PlayerLookupResult <OfflinePlayer > offline = players. findKnownPlayer ( "Notch" ) ;
// Get all online player names for tab-complete
List <String > names = players. onlinePlayerNames ( ) ;
// Fuzzy search — returns all matches, not just one
List <Player > matches = players. searchOnlinePlayers ( "notc" ) ;
// Display-name aware label (falls back to supplied string if no display name)
String label = players. displayName (offlinePlayer, "Unknown" ) ;
 
---
TelemetryService
Optional usage telemetry. Register your plugin as a contributor to include your metrics in any telemetry payloads.
Code (Java):

TelemetryService telemetry = CoreServices. require ( this, TelemetryService. class ) ;
// Is telemetry enabled on this server?
if (telemetry. enabled ( ) ) {
    telemetry. registerContributor (myContributor ) ;
}
// Unique install ID for this server
String id = telemetry. installId ( ) ;
// Unregister when your plugin disables
telemetry. unregisterContributor (myContributor ) ;
// List registered contributor IDs
List <String > contributors = telemetry. contributorIds ( ) ;
// Take an immediate snapshot (metrics as of right now)
TelemetrySnapshot snap = telemetry. snapshotNow ( ) ;
// Extra metadata
boolean remote   = telemetry. remotePublishingEnabled ( ) ;
String env       = telemetry. environment ( ) ;         // e.g. "production"
String endpoint = telemetry. remoteEndpoint ( ) ;
String summary   = telemetry. lastPublishSummary ( ) ;
 
---
DashboardService
Register your plugin as a contributor to the HeliosCore live dashboard. Contributors get a tile, a status card, and optional action/SSE endpoints.
Code (Java):

DashboardService dash = CoreServices. require ( this, DashboardService. class ) ;
// Register your plugin (call from onEnable)
dash. register ( new MyDashboardContributor ( this ) ) ;
// Unregister (call from onDisable)
dash. unregister ( "myplugin" ) ;
// Inspect runtime state
boolean running = dash. isRunning ( ) ;
int port         = dash. port ( ) ;
List <DashboardContributor > all = dash. contributors ( ) ;
 
---
LocaleService
Server-side i18n with per-player locale overrides. Messages are stored in YAML locale files ( lang/en_US.yml). Plugins register their own translation bundles so all translations go through one system.
Code (Java):

LocaleService locale = CoreServices. require ( this, LocaleService. class ) ;
// Simple key lookup — uses server default locale
String msg = locale. message ( "chat.no-permission" ) ;
// With MessageFormat-style argument substitution ({0}, {1}, …)
String msg = locale. message ( "punishment.ban", playerName, reason ) ;
// Per-player locale (falls back to server default)
String msg = locale. messageFor (player. getUniqueId ( ), "chat.no-permission" ) ;
String msg = locale. messageFor (player. getUniqueId ( ), "punishment.ban", playerName, reason ) ;
// Override a specific player's locale
locale. setPlayerLocale (player. getUniqueId ( ), "de_DE" ) ;
String playerLocale = locale. playerLocale (player. getUniqueId ( ) ) ; // "de_DE"
// Register your own translation bundle
// Keys are auto-namespaced as <namespace>.<key>
locale. registerBundle ( "myplugin", "en_US", Map. of (
    "warp.teleported", "Teleported to {0}.",
    "warp.not-found",   "Warp ''{0}'' does not exist."
) ) ;
// Server default locale tag
String def = locale. defaultLocale ( ) ; // e.g. "en_US"
 
---
PlaceholderService
Central placeholder registry. If PlaceholderAPI is present, a PAPI expansion is registered automatically so %helios_<pluginId>_<identifier>% works in any PAPI-compatible plugin.
Code (Java):

PlaceholderService placeholders = CoreServices. require ( this, PlaceholderService. class ) ;
// Register a provider (replaces existing one with same pluginId)
placeholders. register ( new MyPlaceholderProvider ( ) ) ;
// Unregister on disable
placeholders. unregister ( "myplugin" ) ;
// Resolve manually (e.g. for internal usage without PAPI)
String val = placeholders. resolve (offlinePlayer, "myplugin_rank" ) ;
// List all registered providers
List <String > providers = placeholders. registeredProviders ( ) ;
// Is PAPI integration active?
boolean papi = placeholders. papiActive ( ) ;
 
---
PermissionMetaService
LuckPerms meta bridge. Resolves prefix/suffix/meta values from LuckPerms (or any other provider registered at runtime).
Code (Java):

PermissionMetaService meta = CoreServices. require ( this, PermissionMetaService. class ) ;
// Resolve all meta for a player
PermissionMetaSnapshot snap = meta. resolve (offlinePlayer ) ;
// snap provides prefix, suffix, and arbitrary meta keys
// Check if a real external provider (e.g. LuckPerms) is hooked
boolean hasProvider = meta. hasExternalProvider ( ) ;
String provider     = meta. providerName ( ) ; // e.g. "LuckPerms"
 
---
LogService
Universal structured logging for block, command, and audit events. Stored with a configurable retention policy and queryable by type, actor, or time range.
Code (Java):

LogService logs = CoreServices. require ( this, LogService. class ) ;
// Log a structured entry (async — non-blocking)
logs. log (LogEntry. builder ( )
    . type (LogEntry. LogType. COMMAND )
    . actor (sender. getName ( ) )
    . action ( "WARP" )
    . target (warpName )
    . details ( "Teleported to " + warpName )
    . build ( ) ) ;
// Log and await confirmation
CompletableFuture <Boolean > result = logs. logAsync (entry ) ;
// Query with a LogQuery filter (type, actor, time range, limit, …)
List <LogEntry > entries = logs. query (LogQuery. builder ( ). actor ( "Steve" ). limit ( 25 ). build ( ) ) ;
// Convenience queries
List <LogEntry > byType   = logs. getEntriesByType (LogEntry. LogType. COMMAND, 50 ) ;
List <LogEntry > byActor = logs. getEntriesByActor ( "Steve", 25 ) ;
List <LogEntry > inRange = logs. getEntriesByTime (Instant. now ( ). minusSeconds ( 3600 ), Instant. now ( ), 100 ) ;
// Stats and maintenance
long total = logs. getTotalEntries ( ) ;
logs. pruneOldEntries ( 30 ) ;                   // delete entries older than 30 days
String json = logs. exportAsJson (entries ) ;
LogStorageInfo info = logs. getStorageInfo ( ) ;
logs. reload ( ) ;
 
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
4. Command Framework
HeliosCore ships RoutedCommand + BaseSubcommand. Extend them to get free tab-completion, permission gating, and the interactive /yourcommand help output.
Code (Java):

public final class MySubcommand extends BaseSubcommand {
    public MySubcommand (JavaPlugin plugin ) {
        super (
            plugin,
            "warp",                         // subcommand name
            List. of ( "go", "tp" ),           // aliases
            "myplugin.command.warp",       // permission node
            "Teleport to a warp point.",   // description shown in help
            "warp <name>"                   // usage shown in help
        ) ;
    }
    @Override
    public boolean execute (CommandSender sender, String label, String [ ] args ) {
        // your logic
        return true ;
    }
    @Override
    public List <String > suggest (CommandSender sender, String [ ] args ) {
        return List. of ( "spawn", "home", "market" ) ;
    }
}
 
Wire it up:
Code (Java):

RoutedCommand router = new RoutedCommand ( this, "myplugin", List. of (
    new MySubcommand ( this ),
    new AnotherSubcommand ( this )
) ) ;
PluginCommand cmd = getCommand ( "myplugin" ) ;
cmd. setExecutor (router ) ;
cmd. setTabCompleter (router ) ;
 
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
5. Rich Chat Utilities — Fmt
dev.ninez.core.api.text.Fmt is a public component factory for building premium interactive chat output using Paper's Adventure API.
Code (Java):

import dev.ninez.core.api.text.Fmt ;
// Key/value row:  "  Label: value"
sender. sendMessage (Fmt. kv ( "Version", "1.0.0" ) ) ;
sender. sendMessage (Fmt. kv ( "Status", "online", NamedTextColor. GREEN ) ) ;
// Clickable command link with hover tooltip
sender. sendMessage (Fmt. clickCommand ( "Run Test", "/hcore database test", "Click to test the DB" ) ) ;
sender. sendMessage (Fmt. suggestCommand ( "Configure", "/hcore reload", "Click to fill command" ) ) ;
// Status indicators
sender. sendMessage (Fmt. ok ( "Connection passed" ) ) ;   // ✔ green
sender. sendMessage (Fmt. fail ( "Connection failed" ) ) ; // ✘ red
sender. sendMessage (Fmt. warn ( "Pool is idle" ) ) ;       // ⚠ yellow
// Toggle pills
sender. sendMessage (Fmt. pill (enabled ) ) ;           // [ON] / [OFF]
sender. sendMessage (Fmt. pillEnabled (enabled ) ) ;   // [ENABLED] / [DISABLED]
// Pagination footer with clickable prev/next
sender. sendMessage (Fmt. paginationFooter ( "/myplugin list", page, totalPages ) ) ;
// Section header and divider
sender. sendMessage (Fmt. sectionHeader ( "My Feature" ) ) ;
sender. sendMessage (Fmt. divider ( ) ) ;
// Format playtime ticks → "2h 15m", "3d 5h", "< 1m"
String time = Fmt. formatPlaytime (player. getStatistic (Statistic. PLAY_ONE_MINUTE ) ) ;
 
Colour constants: Fmt.BRAND (gold), Fmt.ACCENT (aqua), Fmt.LABEL (gray), Fmt.VALUE (white), Fmt.MUTED (dark gray), Fmt.POSITIVE (green), Fmt.NEGATIVE (red), Fmt.WARNING (yellow)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
6. Events
NinezAuditRecordEvent
Fired on the main thread whenever any Helios plugin records a staff audit action (e.g. HeliosAdmin logging a kick, freeze, or vanish). Listen to this to forward audit entries to your own logging system, Discord bot, or database.
Code (Java):

@EventHandler
public void onAudit (NinezAuditRecordEvent event ) {
    String plugin   = event. sourcePlugin ( ) ;   // e.g. "HeliosAdmin"
    String actor     = event. actorName ( ) ;     // staff member's name
    String action   = event. action ( ) ;         // "KICK", "FREEZE", "VANISH", etc.
    String target   = event. targetName ( ) ;
    String outcome   = event. outcome ( ) ;       // "SUCCESS" or "FAILED"
    String details   = event. details ( ) ;
    String time     = event. loggedAt ( ) ;       // ISO-8601 timestamp
}
 
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
7. Gradle / Maven Dependency
Publish HeliosCore to your local Maven repository ( ./gradlew publishToMavenLocal) then reference it:
Gradle (build.gradle):
Code (Groovy):

repositories {
    mavenLocal ( )
}
dependencies {
    compileOnly "dev.ninez:HeliosCore:1.0.0"
}
 
Maven (pom.xml):
Code (XML):

<dependency>
    <groupId>dev.ninez </groupId>
    <artifactId>HeliosCore </artifactId>
    <version>1.0.0 </version>
    <scope>provided </scope>
</dependency>
 
Use compileOnly / provided — HeliosCore is on the server classpath at runtime; you must not shade it.

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Made by Helios Labs · Part of the Helios Ecosystem
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Resource Information
Author:
----------
Total Downloads: 4
First Release: May 8, 2026
Last Update: May 8, 2026
Category: ---------------
All-Time Rating:
0 ratings
Version -----
Released: --------------------
Downloads: ------
Version Rating:
----------------------
-- ratings