Skip to content

API Overview

Fand plugins depend only on fand-api. fand-api is the stable compile-time surface for plugin authors, while runtime implementations are provided by Fand Server.

IMPORTANT

Do not infer runtime behavior from Java default method bodies, fallback return values, or placeholder exceptions in the fand-api source. They primarily exist for source/binary compatibility while the API evolves; real behavior is provided by the active Fand Server runtime, plugin-scoped wrapper, or registered provider.

Prefer PluginContext for plugin-owned work. It represents the lifecycle scope of the current plugin, so commands, listeners, tasks, service providers, GUIs, boss bars, tab-list entries, and similar resources can be cleaned up when the plugin is disabled. Use Fand.server() when you need the global server view.

Two Core Entry Points

Entry PointRoleUse For
PluginContextPlugin-scoped servicesCommands, events, tasks, permissions, GUIs, packets, cross-plugin services
Fand.server()Global server viewOnline players, worlds, performance, global registries, broadcasts
java
public final class ExamplePlugin implements Plugin {
    @Override
    public void onEnable(PluginContext context) {
        context.logger().info("{} enabled", context.descriptor().id());
        context.commands();
        context.events();
        context.scheduler();
    }
}
java
Fand.server().players();
Fand.server().worlds();
Fand.server().performance();
Fand.server().itemType(Key.key("minecraft:diamond"));

API Layers

Fand API can be read in layers:

LayerRepresentative APIsDescription
Plugin basicsplugin, lifecycle, config, storageLoading, configuration, data directories, persistence
Interactioncommand, event, scheduler, permissionPlayer input, server behavior hooks, async/main-thread work, access control
Player experiencetext, placeholder, bossbar, tablist, scoreboard, gui, mapText, placeholders, screens, boss bars, player lists, scoreboards, map rendering
World and entitiesworld, block, entity, inventory, player, tagWorlds, blocks, entities, players, inventories, vanilla tag lookup
Content extensioncustomitem, customblock, recipe, loot, advancement, enchantment, datapack, structureCustom content, data-pack content, structures, generation-facing features
Ecosystem integrationservice, integration, messaging, regionCross-plugin providers, external resources, plugin messaging, region protection
Low-level presentationpacket, component, registry, performance, gamerule, nbsPackets, components, registries, performance snapshots, game rules, NBS parsing

PluginContext Service Matrix

ServiceEntry PointTypical Use
Loggingcontext.logger()SLF4J logger named after the plugin id
Descriptorcontext.descriptor()Read id, version, mainClass, dependencies, permission declarations
Eventscontext.events()Register player, entity, world, plugin, and server listeners
Commandscontext.commands()Annotated commands, descriptor commands, completions, visible command lookup
Schedulercontext.scheduler()Main-thread, async, delayed, repeating, tick-based tasks
Permissionscontext.permissions()Nodes, trees, attachments, groups, prefix/suffix/meta, context lookup
Configurationcontext.config()Default plugin config.yml, reload, save
Config Loadercontext.configurations()YAML, JSON, TOML, properties, and other config files
Storagecontext.storage()Plugin-scoped JSON/KV persistence
Servicescontext.services()Economy, chat, permission bridge, region protection, and other Java providers
Regionscontext.regions()Region definitions, flag registration, priority ordering, resolution traces
Packetscontext.packets()Interception, construction, sending, custom payloads, fake blocks/entities
Placeholderscontext.placeholders()Register and resolve %namespace_value% style placeholders
MiniMessagecontext.miniMessages()Adventure MiniMessage with Fand placeholder replacement
GUIscontext.guis()Inventory screens, slot handlers, close handlers
Scoreboardscontext.scoreboard()Objectives, display slots, teams, nameplates
Boss Barscontext.bossBars()Create and update boss bars with lifecycle cleanup
Tab Listscontext.tabLists()Per-viewer player-list visibility, sorting, and entries
Mapscontext.maps()Map renderers, cursors, per-player rendering
Plugin Messagingcontext.pluginMessaging()Standard plugin message channels
Custom Itemscontext.customItems()Register custom item types and base-item bindings
Custom Blockscontext.customBlocks()Register custom block types, listeners, item bindings
Recipescontext.recipes()Register and remove recipes
Loot Tablescontext.lootTables()Loot tables in the plugin namespace
Advancementscontext.advancements()Advancements in the plugin namespace
Enchantmentscontext.enchantments()Enchantments in the plugin namespace
Data Packscontext.dataPacks()Plugin-scoped data-pack file trees
Structurescontext.structures()Template save, import, export, placement, locate
Game Rulescontext.gameRules()Plugin-namespaced custom game rules
Simulated Playerscontext.simulatedPlayers()Server-side simulated players
Integrationscontext.integrations()External resource strategies for SQL, Redis, MQ, and similar systems

Global Server View

Server is an Adventure ForwardingAudience that forwards messages to current online players. It is useful for global lookup and broadcast, but plugin-owned registrations should still prefer PluginContext.

CapabilityEntry Point
Server infobrand()version()minecraftVersion()phase()
Playersplayers()player(UUID)player(String)playerAccess()
Worldsworlds()world(Key)defaultWorld()createWorld(...)unloadWorld(...)
Registry lookupblockType(...)itemType(...)entityType(...)blockTags()itemTags()
Global servicesevents()commands()permissions()scheduler()scoreboard()packets()
Performanceperformance()currentTick()
BroadcastsendMessage(...)broadcast(...)

Usage Guidelines

  • Register lifecycle-owned resources in onEnable; release external resources in onDisable.
  • Prefer context.xxx() unless you explicitly need global lookup or broadcast.
  • Event listeners run on the thread that fired the event. Hop to the main thread before mutating world, entity, or inventory state.
  • Async tasks should not touch main-thread state directly. Use context.scheduler().runMain(...) to return to the server thread.
  • ServiceRegistry is for ecosystem interop, not a replacement for ordinary Java dependency injection.
  • Permission nodes, commands, and configuration keys should use the plugin id as a prefix.

Maven Coordinates

kotlin
repositories {
    maven("https://repo.fandmc.cn/repository/maven-public/")
}

dependencies {
    compileOnly("io.fand:fand-api:latest.release")
}

Real plugin projects should prefer the official Gradle plugin because it wires the API dependency and processes fand-plugin.json.