Technical reference for plugin developers and advanced users. Includes the public API for external plugin integration.
id: string; // Unique identifier (snake_case)
category: Category; // Category classification
trigger: Trigger; // Unlock condition
iconItem?: string; // Item ID for icon (default: "Ore_Gold")
hidden?: boolean; // Hide until unlocked (default: false)
difficulty?: Difficulty; // Difficulty tier (default: "normal")
requires?: string | string[]; // Prerequisite achievement ID(s)
showRequires?: boolean; // Show requirements when locked (default: true)
title?: Title; // Unlockable title reward
rewards?: Reward[]; // Item/command rewards
additionalInfo?: AdditionalInfo; // Custom info text
custom?: boolean; // Mark as custom achievement
type Category = "combat" | "progression" | "exploration" | "social" | "husbandry" | "secret";
type Difficulty = "easy" | "normal" | "hard" | "epic";
type: "blocks_mined" | "blocks_placed";
target: string; // Block ID, "any", or prefix (e.g., "Ore_")
count: number; // Required count
Target Matching:
"any" - Matches all blocks
"Stone" - Exact match
"Ore_" - Prefix match (matches Ore_Iron, Ore_Gold, etc.)
target: string; // Entity ID, "any", "any_mob", "any_player"
Target Options:
| Value | Matches |
|---|
"any" | All entities |
"any_mob" | All non-player entities |
"any_player" | All players |
"Spider" | Exact entity type |
target: string; // Item ID or "any"
type: "zones_discovered";
target: string; // Zone ID or "any"
interface PlaytimeTrigger {
type: "playtime_minutes";
count: number; // Minutes
interface DistanceTrigger {
| "iron" | "copper" | "bronze" | "steel"
| "cobalt" | "mithril" | "thorium"
| "adamantite" | "onyxium" | "prisma";
target: string; // Item ID
interface ManualTrigger {
type: "auto_on_prerequisites";
interface WeekendLoginTrigger {
count: number; // Number of weekend logins required
Triggers when a player logs in on Saturday or Sunday. Useful for attendance-based achievements.
interface SkillLevelTrigger {
target: string; // Skill name (e.g., "mining", "fishing")
count: number; // Required skill level
interface TotalSkillLevelTrigger {
type: "total_skill_level";
count: number; // Combined level of all skills
interface RpgLevelTrigger {
target: string; // Level number as string
count: number; // Usually 1
count: number; // Total XP required
itemId: string; // Hytale item ID
amount: number; // Quantity (1-64)
interface CommandReward {
command: string; // Command to execute (use {player} placeholder)
executor: Executor; // Who runs the command
type Executor = "console" | "player";
interface LootbagReward {
lootbagId: string; // ID from lootbags.json
id: string; // Title identifier (for localization)
color?: string; // Hex color code (default: "#FFFFFF" white)
interface AdditionalInfo {
text: string; // Display text
color?: string; // Hex color code (default: "#AAAAAA" gray)
language: "en-US" | "de-DE";
loadDefaultAchievements: boolean;
displayMode: "nametag" | "chat" | "both";
titlePosition: "prefix" | "above" | "below";
rpgLevelPosition: "before_name" | "after_name" | "after_title";
displayMode: "chat" | "banner" | "both";
displayDurationMs: number;
showRewardsInBanner: boolean;
broadcastToChat: boolean;
saveIntervalSeconds: number;
enableExploration: boolean;
enableProgression: boolean;
cascadeRevokeWarning: boolean;
bypassPrerequisites: boolean;
exportGlobalStats: boolean;
exportLeaderboards: boolean;
exportRecentUnlocks: boolean;
recentUnlocksSize: number;
includePlayerTotals: boolean;
achievements.name.<id> - Achievement display name
achievements.desc.<id> - Achievement description
achievements.title.<id> - Title display name
achievements.ui.gallery - Gallery window title
achievements.ui.search - Search placeholder
achievements.ui.all - "All" filter
achievements.ui.combat - "Combat" filter
achievements.ui.progression - "Progression" filter
achievements.ui.exploration - "Exploration" filter
achievements.ui.social - "Social" filter
achievements.ui.completed - "Completed" filter
achievements.ui.locked - "Locked" status
achievements.ui.unlocked - "Unlocked" status
achievements.ui.progress - "Progress" label
achievements.ui.requires - "Requires" label
achievements.ui.reward - "Reward" label
achievements.ui.title - "Title" label
achievements.ui.prev - "Previous" button
achievements.ui.next - "Next" button
achievements.ui.page - "Page" label
achievements.cmd.grant.success - Grant success message
achievements.cmd.grant.already - Already unlocked message
achievements.cmd.revoke.success - Revoke success message
achievements.cmd.revoke.not_unlocked - Not unlocked message
achievements.cmd.list.header - List header format
achievements.cmd.list.empty - Empty list message
achievements.trigger.blocks_mined - "Mine {0} blocks"
achievements.trigger.blocks_placed - "Place {0} blocks"
achievements.trigger.kills - "Kill {0} {1}"
achievements.trigger.items_crafted - "Craft {0} {1}"
achievements.trigger.playtime_minutes - "Play for {0} minutes"
achievements.trigger.distance_walked - "Walk {0} blocks"
achievements.trigger.chat_messages - "Send {0} chat messages"
achievements.trigger.zones_discovered - "Discover {0} zones"
plugins/KyuubiAchievements/
├── config.json - Main configuration
├── configs/ - Standard configs
│ ├── mmo_achievements.json
│ └── rpg_leveling_achievements.json
├── custom/ - Custom configs (safe from updates)
│ └── custom_achievements.json
├── localization/ - Language files
├── playerdata/ - Player achievement data
└── export/ - Statistics export
Common/UI/Custom/Pages/Achievements/
├── AchievementGallery.ui
├── AchievementPlugin.java - Main plugin class
│ └── AchievementAPI.java - Public API for external plugins
│ ├── AchievementCommand.java - /achievements command
│ ├── TitleCommand.java - /titles command
│ └── AchievementAdminCommand.java
│ ├── AchievementConfig.java - Config model
│ ├── AchievementDefinition.java
│ └── AdditionalInfo.java
│ └── PlayerAchievementData.java
│ ├── TitleDisplayManager.java
│ ├── AchievementToastHud.java
│ ├── LuckPermsIntegration.java
│ └── MHUDIntegration.java
│ └── AchievementService.java
│ ├── BlockBreakTrackerSystem.java
│ ├── BlockPlaceTrackerSystem.java
│ ├── ExplorationTracker.java
│ ├── MovementTracker.java
│ ├── AchievementGalleryPage.java
│ └── TitleSelectionPage.java
└── AdventureConverter.java
The plugin tracks these Hytale events:
| Event | Trigger Type |
|---|
BlockBreakEvent | blocks_mined |
BlockPlaceEvent | blocks_placed |
EntityDeathEvent | kills |
PlayerCraftEvent | items_crafted |
PlayerMoveEvent | distance_walked |
PlayerChatEvent | chat_messages |
ZoneEnterEvent | zones_discovered |
PlayerEquipEvent | equip_item, full_armor_set |
PlayerJoinEvent | weekend_login (checks day of week) |
External plugins can interact with the Achievement System through a stable public API.
import com.hytale.achievements.api.AchievementAPI;
AchievementAPI api = AchievementAPI.getInstance();
// Achievement plugin not loaded
// Or with availability check
if (AchievementAPI.isAvailable()) {
AchievementAPI api = AchievementAPI.getInstance();
| Method | Description |
|---|
hasAchievement(Player, String) | Check if player has achievement |
hasAchievement(UUID, String) | Check by UUID |
getProgress(Player, String) | Current progress |
getRequiredProgress(String) | Required progress to unlock |
getUnlockedAchievements(Player) | Set of all unlocked IDs |
getUnlockedCount(Player) | Number of unlocked achievements |
getTotalAchievementCount() | Total number of achievements |
getUnlockTimestamp(Player, String) | Unix timestamp of unlock |
getAllAchievementIds() | List of all achievement IDs |
getAchievementsByCategory(String) | Achievements in a category |
achievementExists(String) | Check if achievement exists |
| Method | Description |
|---|
getActiveTitle(Player) | Active title ID (or null) |
getUnlockedTitles(Player) | Set of all unlocked titles |
| Method | Description |
|---|
grantAchievement(Player, String) | Grant achievement (with rewards) |
revokeAchievement(Player, String) | Revoke achievement |
setProgress(Player, String, int) | Set progress directly |
incrementProgress(Player, String, int) | Increment progress (checks unlock) |
| Method | Description |
|---|
onAchievementUnlock(BiConsumer<Player, String>) | Listener for unlock events |
removeUnlockListener(BiConsumer) | Remove unlock listener |
onProgressUpdate(BiConsumer<Player, String>) | Listener for progress updates |
removeProgressListener(BiConsumer) | Remove progress listener |
| Method | Description |
|---|
getTotalBlocksMined(Player) | Total blocks mined |
getTotalBlocksPlaced(Player) | Total blocks placed |
getTotalMobKills(Player) | Total mob kills |
getPlaytimeMinutes(Player) | Playtime in minutes |
AchievementAPI api = AchievementAPI.getInstance();
// Does the player have "monster_hunter_1"?
if (api.hasAchievement(player, "monster_hunter_1")) {
player.sendMessage("You are a monster hunter!");
int progress = api.getProgress(player, "blocks_mined_1000");
int required = api.getRequiredProgress("blocks_mined_1000");
player.sendMessage("Progress: " + progress + "/" + required);
AchievementAPI api = AchievementAPI.getInstance();
api.onAchievementUnlock((player, achievementId) -> {
// Firework effect or similar
spawnFirework(player.getLocation());
LOGGER.info(player.getDisplayName() + " unlocked " + achievementId + "!");
AchievementAPI api = AchievementAPI.getInstance();
// Grant achievement on special event
if (specialEventTriggered) {
boolean granted = api.grantAchievement(player, "special_event_2026");
// Player already had it or achievement doesn't exist
AchievementAPI api = AchievementAPI.getInstance();
int blocksMinedTotal = api.getTotalBlocksMined(player);
int achievementCount = api.getUnlockedCount(player);
long playtimeMinutes = api.getPlaytimeMinutes(player);
// Use for leaderboard...
- The API is thread-safe using
CopyOnWriteArrayList for listeners
- All query methods can be called from any thread
- Modification methods should ideally be called from the main thread