Tags
Creators
Details
1.5.0
Compatibility
Required content
Changes
Added
extensions().registerExpSource(Plugin, ExpSourceProvider), so a third-party plugin can grant exp of its own by returningExpSourceGrantat these gameplay triggers:entity_kill,mythic_mob_kill,block_place,block_break,crop_harvest,craft_item,furnace_extract,player_fish,entity_tameandbrew_complete. Providers are keyed by owner and provider id, dropped automatically when the owner is disabled, and the returnedExpSourceRegistrationhandle can be closed more than once.- Cancellable
PlayerPreLevelUpEvent, fired after every check passes and before charging or writing begins. Cancelling prevents the level-up with nothing charged, no level change, no rewards and no actions, and the runtime reportsevent_cancelled. It is the only supported way to veto an upgrade. It fires only for an online, thread-owned player and not when an earlier check already failed, so treat a missing event as "no committed upgrade to veto" and listen toPlayerLevelUpEventto confirm a completed upgrade. - Leaderboard queries
catalog().top(typeId, limit)andcatalog().topCount(typeId), exp adjustment previewcatalog().previewAdjustment(), andoperations().syncPlayer(),operations().openGui()andoperations().openTopGui(). - Config precheck lines are coloured by severity: red for fatal and error, yellow for warning, the original grey for info.
Changed
- Actions use a new syntax, and most of it is rewritten for you. On first startup CoreLib rewrites the config files of every Emaki plugin under
plugins/, once only. Each edited file keeps the original beside it with a.legacy-backupsuffix. A line that cannot be converted leaves your config untouched and goes into a separate.v2-failedfile, with the file and line listed in the console. Common actions such assendmessageintypes/*.ymland@chance=5 sendactionbarinsources/*.ymlare covered. - Level's own eight actions need renaming by hand; automatic rewriting does not cover them, and the rewriter does not even recognise the old names, so they stay in your config untouched and the console reports an unknown line on load:
emakileveladdexp→level_add_expemakilevelsetexp→level_set_expemakilevelremoveexp→level_remove_expemakileveladdlevel→level_add_levelemakilevelsetlevel→level_set_levelemakilevelremovelevel→level_remove_levelemakilevelreset→level_resetemakilevellevelup→level_up
- The
target=playerNameargument on those eight actions is replaced by a source segment in front of the action:emakileveladdexp type=main amount=10 target=Stevebecomesplayer_by_name Steve | level_add_exp type=main amount=10. With no source segment the action applies to the player who triggered it, as leavingtargetempty used to. auto_upgradeandsilentare only accepted bylevel_add_exp. On any other level action they are treated as an unknown argument.- Placeholders reading level data inside action lines need a
var.prefix. This only concerns you if you have edited your level types or exp sources: the bundledtypes/andsources/files already use the new form. If your own config writes%old_level%,%new_level%,%amount%or%failure_reason%underactions.success,actions.failureoractions.gain, change them to%var.old_level%,%var.new_level%,%var.amount%and%var.failure_reason%, or messages will show%new_level%instead of the number. The full list available in action lines istype,type_display_name,level,old_level,new_level,exp,old_exp,new_exp,total_exp,required_exp,progress,progress_percent,amount,reasonandfailure_reason. - Placeholders in formulas are unchanged and must stay bare. Only action lines, the ones under
actions:, take the prefix.%result_amount%and%mythic_level%inexp_formula, and%level%in theattributesformulas, go through a separate arithmetic path; prefixing them stops them evaluating. PlaceholderAPI%emakilevel_...%placeholders are unaffected. - For developers:
EmakiLevelApiProvideris removed; call the static methods onEmakiLevelApidirectly. The static methods that used to sit on the facade (available(),type(),types(),getPlayerData(),getLevel(),getExp(),getTotalExp(),getRequiredExp(),addExp()/removeExp()/setExp(),addLevel()/removeLevel()/setLevel(),levelUp()and the matching*Async()variants) are replaced bystatus(),catalog(),operations()andextensions().available()becomesstatus(), returningApiStatuswithusable(),ready()and the version and plugin-name fields, whereready()means the data is loaded rather than the components exist. Apart fromcatalog().types()andcatalog().type(), these methods returnEmakiResult<T>and report unavailability instead of throwing.EmakiLevelApi.Bridgeis now@ApiStatus.NonExtendable. - For developers: a cancelled
PlayerExpGainEventnow reportsevent_cancelledinstead ofinvalid_amount. The event classes document their threading: all are synchronous, fire only while the runtime owns the player, and listeners must return quickly without blocking on other threads.
Fixed
- The daily exp cap being charged even when another plugin blocked the gain, on servers running a plugin that listens to level events. The gain was counted towards the daily total before other plugins were notified, so a cancelled or reduced gain had already been counted and players saw their allowance shrink without receiving exp. Counting now happens after the other plugins have had their say, using only the amount that lands.
- Compensation records being lost as a batch when a level-up went wrong midway. One corrupt pending record made the plugin abandon the whole batch, leaving every waiting player without a refund. A corrupt record is now moved aside into
data/operation-journal/quarantine/and the rest recover as usual, with the pending operations listed in the console. - Writing that pending record stalling players and breaking the level-up. The write happened on the player's own thread, so a slow disk slowed level-ups and a failed write aborted the level-up. It now happens in the background, and a failed write only logs and leaves the record for the next recovery pass.
- Some players' level data not refreshing after
/emakilevel reload, on Folia servers. The rewrite ran entirely on the command thread, so players not owned by that thread were skipped with an error. They are now handed back to their own thread.
Removed
- JS experience rules and level-up hooks, with no automatic conversion. Scripts adjusting exp through
level.registerExpRuleor hooking level-ups throughlevel.onLevelUpno longer run. Usemultipliersinconfig.ymlfor rates andactions.successon the level type for level-up effects. The bundledscripts/examples/level_exp_rule.jsandscripts/examples/level_status.jssamples are gone as well. - Seven config options that never did anything:
storage.type,storage.save_on_quit,storage.save_on_shutdown,pdc.sync_on_join,pdc.sync_on_exp_change,pdc.sync_on_level_changeandpdc.sync_on_reload. They sat in the config file but were never read, so no value ever had an effect. Delete them from your own config whenever you like.pdc.enabledandpdc.namespaceare unchanged.
Notes
- Update EmakiCoreLib to
4.7.0first. - Back up your whole
plugins/EmakiLevel/folder before upgrading. - Three things need doing by hand: renaming the eight level actions, replacing
targetwith aplayer_by_namesource segment, and droppingauto_upgradeandsilentfrom anything other thanlevel_add_exp. Everything else in the action syntax is rewritten for you. If you have edited your level types or exp sources, also check that the placeholders in your action lines carry thevar.prefix; the ones in formulas stay as they are. - The player level data file structure is unchanged and needs no migration. Commands, aliases and permission keys are unchanged, and
config.ymlonly loses the seven dead keys, so an existing config file keeps working.
Emaki Level v1.4.0
MineBBS 更新日志
破坏性变更:占位符改为仅读缓存
- PlaceholderAPI 占位符解析现在只读缓存。 此前未缓存玩家的占位符会同步加载并返回数值,现在会直接返回空字符串。
- 在线玩家会在加入时进入缓存;但任何依赖离线玩家、或尚未缓存玩家占位符的展示(如排行牌、告示牌、动态标题等)都需要重新确认显示效果。
破坏性变更:移除 Web Console
- 浏览器端 Web Console 层已整体移除,包含
web-console.yml、配置与 CSS 网页扩展,以及含等级曲线预览的前端项目。 - 随之移除内部的等级曲线预览服务。它只服务于该网页预览,没有对应配置键与命令,因此服主侧没有等价功能损失;等级曲线仍由等级类型配置驱动。
修复:升级扣费不再吞资源
- 修复升级扣费可能扣掉资源却没有给等级的问题:此前货币与材料扣除没有检查结果、也没有回滚,玩家可能在材料不足时白扣货币(或反向情况)。
- 升级扣费改为事务式:货币或材料扣除部分失败时,会回滚已扣除的部分,并提供专门的补偿失败原因。
数据安全与可靠性
- 新增玩家数据就绪保护:数据仍在加载或处于只读状态时,写入会被拒绝并返回专门的失败原因与提示,避免写出损坏数据。
- 排行榜重建改为异步执行,玩家加入与退出不再触发主线程全表扫描。
- 玩家数据加载改为带世代标记的异步会话模型。
占位符与 API
- 通过 CoreLib 占位符系统新增占位符:
level、exp、total/totalexp/total_exp、required/requiredexp/required_exp、progress、progresspercent/progress_percent。 - 公开 API 新增经验与等级变更的异步入口,各自返回带操作结果的 future;API 未安装时会明确返回不可用而不是静默失败。
配置预检与命令
- 配置预检新增文件/目录级提示:缺少必需文件、路径不是文件、文件不可读、缺少必需目录、路径不是目录、目录不可读。
- 插件描述文件迁移到
paper-plugin.yml,改用结构化依赖(必需 EmakiCoreLib;可选 MythicMobs / EmakiAttribute / EmakiCooking / EmakiForge / PlaceholderAPI)。权限键与默认值保持不变;/emakilevel(别名elv、elevel)改为代码注册,别名保留。 - 默认 GUI 文件(
gui/level_gui.yml、gui/top_gui.yml)改用嵌套的item.source+item.components写法;槽位布局与全部占位符保持不变,旧写法仍可解析。 - 消息前缀更换为新的品牌渐变样式。
升级说明
- 需要 EmakiCoreLib
4.6.0。 api-version由1.21提升到1.21.8,构建基线由 spigot-api 改为 paper-api;folia-supported: true与 Java 25 目标保持不变。config.yml没有新增或删除配置键,现有配置可直接使用;玩家等级数据文件结构未变化,无需迁移。- 升级后请重点检查依赖占位符的展示位置(尤其是离线玩家场景),并确认原先经由 Web Console 完成的操作已有替代方式。
SpigotMC Update Log
[CENTER][SIZE=6][B]◆ Emaki Level v1.4.0 Release ◆[/B][/SIZE][/CENTER] [CENTER]Transactional level-up charging with rollback, cache-only placeholder resolution, async leaderboard rebuilds, new placeholders, and removal of the Web Console.[/CENTER] [CENTER][B]━━━━━━━━━━━━━━━━━━━━[/B][/CENTER] [LIST] []Breaking: PlaceholderAPI placeholder resolution is now cache-only. An uncached player's placeholder used to be loaded synchronously and return a value; it now returns an empty string. Online players are cached on join, but re-check any display that relies on placeholders for offline or not-yet-cached players. []Breaking: the browser-based Web Console layer is removed, including web-console.yml, the config and CSS web extensions, and the web-console frontend project with its level curve preview. []The internal level curve preview service is removed with it. It only served that browser preview and had no config key or command, so there is no equivalent owner-facing loss; curves are still driven by level type configuration. []Fixed level-up cost charging consuming resources without granting the level: currency and material deductions were applied without checking their results and without rollback, so a player could lose currency when materials were insufficient, or the reverse. []Level-up cost charging is now transactional. If currency or material deduction partially fails, the already-deducted part is rolled back, with a dedicated failure reason for compensation failure. []New player data readiness protection: a new failure reason and message reject writes while data is loading or read-only, instead of writing corrupt data. []Leaderboard rebuilds are now asynchronous, so player join/quit no longer triggers a full main-thread table scan. []Player data loading moved to a generation-aware asynchronous session model. []New placeholders exposed through the CoreLib placeholder system: level, exp, total/totalexp/total_exp, required/requiredexp/required_exp, progress, progresspercent/progress_percent. []Public API gains asynchronous mutation entry points for exp and level changes, each returning a future with an operation result and reporting unavailability cleanly when the API is not installed. []Config precheck adds file and directory level messages: missing required file, path not a file, unreadable file, missing required directory, path not a directory, unreadable directory. []Descriptor migrated to paper-plugin.yml with structured dependencies (EmakiCoreLib required; MythicMobs / EmakiAttribute / EmakiCooking / EmakiForge / PlaceholderAPI optional). Permission keys and defaults are unchanged, and /emakilevel (aliases elv, elevel) registers in code with aliases preserved. []Default GUI files gui/level_gui.yml and gui/top_gui.yml use the nested item.source + item.components form. Slot layout and all placeholders are unchanged and the old form is still parsed. []Message prefix switched to a new brand gradient. []Requires EmakiCoreLib 4.6.0. api-version moves from 1.21 to 1.21.8 and the build base moves from spigot-api to paper-api; folia-supported: true and the Java 25 target are unchanged. []config.yml has no key additions or removals, so existing config works as-is, and the player level data file structure is unchanged, so no migration is required. [/LIST]
Modrinth Changelog
Added
- Asynchronous mutation entry points for exp and level changes in the public API, each returning a future with an operation result and reporting unavailability cleanly when the API is not installed.
- Transactional level-up cost charging: if currency or material deduction partially fails, the already-deducted part is rolled back, with a dedicated failure reason for compensation failure.
- Player data readiness protection: a new failure reason and message reject writes while data is loading or read-only, instead of writing corrupt data.
- New placeholders exposed through the CoreLib placeholder system:
level,exp,total/totalexp/total_exp,required/requiredexp/required_exp,progress,progresspercent/progress_percent. - Config precheck messages at file and directory level: missing required file, path not a file, unreadable file, missing required directory, path not a directory, unreadable directory.
Changed
- Descriptor migrated to
paper-plugin.ymlwith structured dependencies (EmakiCoreLib required; MythicMobs / EmakiAttribute / EmakiCooking / EmakiForge / PlaceholderAPI optional). Permission keys and defaults are unchanged;/emakilevel(aliaseselv,elevel) registers in code with aliases preserved. - Default GUI files (
gui/level_gui.yml,gui/top_gui.yml) use the nesteditem.source+item.componentsform. Slot layout and all placeholders are unchanged and the old form is still parsed. - Leaderboard rebuilds are now asynchronous, so player join/quit no longer triggers a full main-thread table scan.
- Player data loading moved to a generation-aware asynchronous session model.
- Message prefix switched to a new brand gradient.
api-versionraised from1.21to1.21.8and the build base moved from spigot-api to paper-api;folia-supported: trueand the Java 25 target are unchanged.
Fixed
- Level-up cost charging could consume resources without granting the level: currency and material deductions were applied without checking their results and without rollback, so a player could lose currency when materials were insufficient, or the reverse. Charging is now transactional with rollback.
Removed
- PlaceholderAPI placeholder resolution is now cache-only. An uncached player's placeholder previously loaded synchronously and returned a value; it now returns an empty string. Online players are cached on join, but any display that relies on placeholders for offline or not-yet-cached players must be re-checked.
- The browser-based Web Console layer, including
web-console.yml, the config and CSS web extensions, and theweb-console/frontend project with its level curve preview. - The internal level curve preview service is removed with it. It only served that browser preview and had no config key or command, so there is no equivalent owner-facing loss; curves are still driven by level type configuration.
Notes
- Requires EmakiCoreLib 4.6.0.
config.ymlhas no key additions or removals, so existing config works as-is, and the player level data file structure is unchanged, so no migration is required. After upgrading, re-check any placeholder-driven display, especially for offline players, and confirm you have a replacement for anything previously done through the Web Console.
Projects on Modrinth are automatically available through a Maven repository for use with JVM build tools such as Gradle. To learn more about the Modrinth Maven API, click here.
Note: When available, you should use the creator's maven repo instead as it will have transitive dependency information that the Modrinth Maven API does not. You may also end up with duplicate dependencies if you use a mix of Modrinth and non-Modrinth Maven repositories for your dependencies, because the group identifier will be different when served through the Modrinth Maven API.
Maven coordinates:
Version ID:
build.gradle:
repositories {
exclusiveContent {
forRepository {
maven {
name = "Modrinth"
url = "https://api.modrinth.com/maven"
}
}
// forRepositories(fg.repository) // Uncomment when using ForgeGradle
filter {
includeGroup "maven.modrinth"
}
}
}
// Standard Gradle dependency
dependencies {
implementation "maven.modrinth:Iw3zKgdR:EPkWFP3N"
}
// Legacy Loom dependency
dependencies {
modImplementation "maven.modrinth:Iw3zKgdR:EPkWFP3N"
}

