成就系统

基本信息

属性 值 来源
注册类 ModAchievements common/achievement/ModAchievements.java
触发类 AchievementMod extends Achievement common/achievement/AchievementMod.java:22
事件类 AchievementTriggerer common/achievement/AchievementTriggerer.java
成就总数 49 49 个 public static Achievement 字段、49 次 new AchievementMod、49 个 LibAchievementNames 常量,三者吻合
隐藏成就 12(.setSpecial()) ModAchievements.init()
成就页 AchievementPage(FML 原版机制) ModAchievements.java:156-158
侧 服务端 ModAchievements.init() 由 CommonProxy.java:117 调用(客户端另见 ClientProxy)

成就页的显示名用 LibMisc.MOD_NAME,pageIndex 记录该页在全局成就页列表中的下标(ModAchievements.java:156)。

注册机制

每个成就走 AchievementMod 的三参重载(AchievementMod.java:26-33):

super("achievement.botania:" + name, "botania:" + name, x, y, icon, parent);
achievements.add(this);   // 加入静态列表
registerStat();           // Statistic.registerStat

因此产生两套本地化键,共 98 条 zh_CN 键(49 × 2):

键 含义 示例
achievement.botania:<name> 成就标题 achievement.botania:flowerPickup=Sky of Beginning
achievement.botania:<name>.desc 成就说明 achievement.botania:flowerPickup.desc=拾取一朵神秘花

传给 Achievement 构造器的第二个参数(未本地化名)少了 achievement. 前缀,为 botania:<name>。achievements 列表在构造时累积,最后统一 new Achievement[achievements.size()] 传给 AchievementPage(ModAchievements.java:157)。

位置坐标 (x, y) 决定成就页上的格子位置,负数为左侧独立的分支(遗物 6 件 + 3 个彩蛋全在 x < 0 区域)。

触发方式

AchievementTriggerer 只监听 2 个原版事件(AchievementTriggerer.java:22-34):

事件 判定接口 行为
ItemPickupEvent 拾取物 instanceof IPickupAchievement 调 getAchievementOnPickup(stack, player, entity),非空则 player.addStat(achievement, 1)
ItemCraftedEvent 合成物 instanceof ICraftAchievement 调 getAchievementOnCraft(crafting, player, matrix),非空则 addStat

也就是说成就不靠监听方块放置 / 实体击杀 / 地块交互,而是靠物品自身实现 IPickupAchievement / ICraftAchievement(通常经 ItemLexicon、各 Item 子类)后借上述两个事件顺带解锁。遗物另有 IRelic.setBindAchievement 绑定(AchievementMod.java:31-32)。

AchievementTriggerer 自身也在 init 末尾注册到 FMLCommonHandler 总线(ModAchievements.java:160)。

全部 49 个成就

「隐藏」列为 是 表示调用了 .setSpecial(),在成就页上以问号显示直到解锁。

字段 名称 图标 坐标 父成就 隐藏 说明
flowerPickup Sky of Beginning ModBlocks.flower meta 6 0, 4 无 拾取一朵神秘花
lexiconUse 现実的论理主义者 ModItems.lexicon 1, 5 flowerPickup 打开一本植物魔法辞典并浏览目录
daybloomPickup 拂晓抵达 subtile_daybloom 3, 5 lexiconUse 在花药台制作一朵太阳花
cacophoniumCraft Noisy Lover Soul ModItems.cacophonium -1, 2 flowerPickup 制作一个不和谐之音来激怒你的敌人
manaPoolPickup Vivid Wave ModBlocks.pool 3, 2 daybloomPickup 将稀释魔力池升级为普通的魔力池
endoflamePickup 炉心融解 subtile_endoflame 2, 0 manaPoolPickup 做出一朵火红莲来加速魔力生产
tinyPotatoPet Just Be Friends ModBlocks.tinyPotato 2, -2 manaPoolPickup 做出一个小土豆再爱抚它
sparkCraft Live Drive ModItems.spark 4, -2 manaPoolPickup 制作火花协助传输魔力
baubleWear Inner Arts ModItems.manaRing 4, 0 manaPoolPickup 做出一件饰品并佩戴
manaCookieEat 腐れ外道とチョコレゐト ModItems.manaCookie 2, -4 manaPoolPickup 注魔一块魔力曲奇并吃掉
manaweaveArmorCraft Imagination Forest ModItems.manaweaveChest 4, -4 manaPoolPickup 制作一套魔力布匹制作的装甲来提高你的魔力效率
craftingHaloCraft Segments Blue ModItems.craftingHalo 3, -6 manaPoolPickup 制作一个合成环以方便合成
manaCartCraft World Domination How-To ModItems.poolMinecart 5, 3 manaPoolPickup 制作一个用魔力矿车进行的长距离魔力运输系统
enchanterMake Odds and Ends ModBlocks.enchanter 1, 2 manaPoolPickup 制作一个魔力附魔台来更好的控制附魔
runePickup Lilium Doll ModBlocks.runeAltar 6, 2 manaPoolPickup 用符文祭坛制作符文
dirtRodCraft Rockbell ModItems.dirtRod 8, 3 runePickup 制作一根泥棍子…哦不,是大地法杖
terraformRodCraft World is Mine ModItems.terraformRod 10, 3 dirtRodCraft 制作一把泰拉高并用他改变世界地形
manaBlasterShoot M‘AIDER遭難ガール ModItems.manaGun 8, 1 runePickup 合成魔力脉冲枪再发射脉冲
pollidisiacPickup Romeo and Cinderella subtile_pollidisiac 8, 5 runePickup 做一个畜牧花,在空气中制造爱情力场
brewPickup Childhood Blues ModBlocks.brewery 6, 0 runePickup 制作一个植物酿造台并用他酿造所有种类的药水
terrasteelPickup Dancer in the Dark ModItems.manaResource meta 4 6, 9 runePickup 是 用泰拉凝聚板制作一块泰拉锭
terrasteelWeaponCraft Remote Paranoia ModItems.terraSword 8, 10 terrasteelPickup 用泰拉锭制作的武器武装你自己
elfPortalOpen World Calling ModBlocks.alfPortal 4, 9 terrasteelPickup 是 打开通往精灵王国的传送门
kekimurusPickup 放課後ストライド subtile_kekimurus 3, 11 elfPortalOpen 制作一朵贪食花来提供大量魔力
heiseiDreamPickup Heisei Cataclysm subtile_heisei_dream 5, 11 elfPortalOpen 制作一朵平成之梦让怪物们窝里斗
bubbellPickup 深海少女 subtile_bubbell 6, 12 elfPortalOpen 制作一株气泡铃来方便水下建筑
enderAirMake Imitation Air ModItems.manaResource meta 15 4, 14 elfPortalOpen 收集一瓶末地空气
corporeaCraft Drop Pop Candy ModBlocks.corporeaFunnel 2, 14 enderAirMake 合成一个使用多媒体网络的方块
luminizerRide World’s End Dancehall ModBlocks.lightRelay 6, 14 enderAirMake 制作一些微光并用它来进行传输
gaiaGuardianKill Dead and Seek ModItems.manaResource meta 5 2, 9 elfPortalOpen 是 在盖亚仪式中召唤并击杀一只盖亚守护者
spawnerMoverUse I can take off my (redacted) ModItems.spawnerMover -1, 10 gaiaGuardianKill 用一个生命聚合器来转移刷怪笼
tiaraWings Heart Shooter ModItems.flightTiara -1, 8 gaiaGuardianKill 制作天翼族之冠并用翅膀装饰它
manaBombIgnite Under of Fragments ModBlocks.manaBomb 0, 11 gaiaGuardianKill 制作一个魔力风暴,并在宽阔的地方点燃它
dandelifeonPickup Donut Hole subtile_dandelifeon 0, 7 gaiaGuardianKill 制作一朵启命英来挑战你的心智
signalFlareStun See the Lights ModItems.signalFlare -3, 1 无 是 用一发信号弹让至少 100 只怪物眩晕
l20ShardUse Out of Step ModItems.laputaShard -5, 3 无 是 用能量为 XX 的拉普达碎片将地面升至天空
gaiaGuardianNoArmor Mythologia’s End Items.skull meta 3 -5, 1 无 是 战斗从头至尾不穿任何护甲击杀一只盖亚守护者
rankSSPick 六兆年零一夜物语 ModItems.terraPick -3, 3 无 是 用 SS 级的泰拉粉碎者挖穿世界
superCorporeaRequest Invader Girl ModBlocks.corporeaIndex -3, -1 无 是 成功从多媒体索引处请求单种物品至少 50,000 个
pinkinator Decorator ModItems.pinkinator -5, -1 无 是 使用粉色手炮
relicInfiniteFruit Innocentia ModItems.infiniteFruit -9, 8 无 获得战利品:禁忌果实
relicKingKey A Fake, Fake Psychotropic ModItems.kingKey -7, 11 无 获得战利品:王之宝钥
relicFlugelEye Angel of Death ModItems.flugelEye -5, 8 无 获得战利品:天翼族之眼
relicThorRing One Step Layered ModItems.thorRing -7, 7 无 获得战利品:托尔之戒
relicOdinRing 回忆补时 ModItems.odinRing -9, 10 无 获得战利品:奥丁之戒
relicLokiRing Arithmetic ModItems.lokiRing -5, 10 无 获得战利品:洛基之戒
relicAesirRing 神のまにまに ModItems.aesirRing -7, 9 无 是 通过合成做出诸神之戒
nullFlower Take it Easy ModBlocks.specialFlower -8, 0 无 是 发现一个 bug 导致你有了一朵未定义的植物魔法花。别忘了提交!
desuGun 裏表ラバーズ ModItems.manaGun(显示名被改为 “desu gun”) -8, 2 无 是 ASADA-SAN × 9

三个分组

按坐标与依赖关系,成就页自然分成三块:

组 成就 特征
主线 flowerPickup → lexiconUse → daybloomPickup → manaPoolPickup → endoflamePickup / runePickup → 精灵分支 沿 x = 0 → 10 展开,是推荐的游玩顺序
遗物 6 件 relicInfiniteFruit / relicKingKey / relicFlugelEye / relicThorRing / relicOdinRing / relicLokiRing(+ 合成的 relicAesirRing) 全部 parent = null,且全部受 ConfigHandler.relicsEnabled 门控
彩蛋 6 个 signalFlareStun / l20ShardUse / gaiaGuardianNoArmor / rankSSPick / superCorporeaRequest / pinkinator / nullFlower / desuGun 全部 parent = null 且全部 .setSpecial(),散落在 x = −3 ~ −8 的空白区

遗物 6 件 + 诸神之戒 = 7 个,全部包在 if(ConfigHandler.relicsEnabled) 判定内(ModAchievements.java:140-148),所以 relics.enabled 关闭时实际只有 42 个成就注册。

已确认的细节与坑

42 + 7 的条件注册:关掉 relics.enabled 后 relic* 字段保持 null。但 AchievementPage 用的是 achievements 列表而非字段,列表同样不含这 7 个,所以不会出现 null 图标崩溃 —— 这一点由 achievements.add(this) 只在构造时调用保证。

desuGun 的图标被改过显示名:ItemStack desu = new ItemStack(ModItems.manaGun); desu.setStackDisplayName("desu gun");(ModAchievements.java:152-154)。这是 49 个成就里唯一一个自定义显示名的图标。

gaiaGuardianNoArmor 用原版头颅当图标:new ItemStack(Items.skull, 1, 3)(ModAchievements.java:135),meta 3 是玩家头颅,刻意回避了盖亚守护者自身的模型。

说明文本里的占位符:l20ShardUse.desc 写的是「用能量为 XX 的拉普达碎片」,XX 是未替换的占位符(原文本即如此)。

零星未汉化的标题:上表中有 20 余个成就标题回退到 en_US(例如 Noisy Lover Soul、Imagination Forest),但 .desc 全部有中文译文。已确认 zh_CN.lang 中 49 条 .desc 齐全,标题则部分缺失。

相关条目