奖杯系统(25 种生物奖杯)

基本信息

奖杯方块 OpenBlocks:trophy 是一个单个方块 + 25 个 meta 的组合:meta 决定奖杯的生物种类,每种生物有独立的缩放、垂直偏移与可选行为。

属性 值 位置
注册名 OpenBlocks:trophy OpenBlocks.java:295
方块类 openblocks.common.block.BlockTrophy —
TileEntity openblocks.common.tileentity.TileEntityTrophy OpenBlocks.java:295
ItemBlock openblocks.common.item.ItemTrophyBlock OpenBlocks.java:295
枚举 openblocks.common.TrophyHandler.Trophy TrophyHandler.java:95-235
行为接口 openblocks.trophy.ITrophyBehavior trophy/ITrophyBehavior.java:7
行为实现 10 个 trophy/ 目录(11 个文件 = 10 实现 + 1 接口)

「25 种」经两种方式核对:Trophy 枚举体(TrophyHandler.java:97-146)中形如 ^ [A-Z]\w*\s*[({,] 的常量声明行计数 = 25;同一区间的另一种宽松正则计数 = 25。一致。

功能

25 种奖杯

Trophy 枚举(TrophyHandler.java:97-146),括注为构造参数(scale、verticalOffset、behavior):

# 常量 行 参数 特殊行为
0 Wolf :97 无 —
1 Chicken :98 ItemDropBehavior(10000, egg, "mob.chicken.plop") 激活时掉鸡蛋并播 mob.chicken.plop
2 Cow :99 ItemDropBehavior(20000, leather) 激活时掉皮革
3 Creeper :100 CreeperBehavior 苦力怕行为
4 Skeleton :101 SkeletonBehavior 骷髅行为
5 PigZombie :102 ItemDropBehavior(20000, gold_nugget) 激活时掉金粒
6 Bat :103 1.0, -0.3 缩放 1.0,垂直偏移 −0.3
7 Zombie :104 无 —
8 Witch :105 0.35, WitchBehavior 女巫行为
9 Villager :106 无 —
10 Ozelot :107-120 无 + 覆写 驯服(setTamed(true));类型不符时 Log.warn("Invalid cat entity class: %s")(:114-117)
11 Sheep :121 ItemDropBehavior(20000, wool) 激活时掉羊毛
12 Blaze :122 BlazeBehavior 烈焰人行为
13 Silverfish :123 无 —
14 Spider :124 无 —
15 CaveSpider :125 CaveSpiderBehavior 洞穴蜘蛛行为
16 Slime :126-132 0.6 + 覆写 setSlimeSize(entity, 1) 反射调用(:130)
17 Ghast :133 0.1, 0.3 缩放 0.1,垂直偏移 0.3
18 Enderman :134 0.3, EndermanBehavior 末影人行为
19 LavaSlime :135-141 0.6 + 覆写 同 Slime,setSlimeSize(entity, 1)(:139)
20 Squid :142 0.3, 0.5, SquidBehavior 鱿鱼行为
21 MushroomCow :143 MooshroomBehavior 哞菇行为
22 VillagerGolem :144 0.3 缩放 0.3
23 SnowMan :145 SnowmanBehavior 雪傀儡行为
24 Pig :146 ItemDropBehavior(20000, porkchop) 激活时掉猪排

行为接口

ITrophyBehavior 只有 2 个方法(trophy/ITrophyBehavior.java:12、:14):

方法 触发时机
executeActivateBehavior(TileEntityTrophy, EntityPlayer) 玩家右键奖杯方块;返回值是某种内部计数(TrophyHandler.java:210-213)
executeTickBehavior(TileEntityTrophy) 每刻(TrophyHandler.java:215-217)

behavior 为 null 时两个方法都直接返回(:211-212、:216)——25 种里只有 14 种带行为(TrophyHandler.java:97-146 中含 Behavior( 的行数)。Ozelot、Slime、LavaSlime 三个带 {} 覆写的是 createEntity() 而非行为。

10 个行为实现

BlazeBehavior、CaveSpiderBehavior、CreeperBehavior、EndermanBehavior、ItemDropBehavior、MooshroomBehavior、SkeletonBehavior、SnowmanBehavior、SquidBehavior、WitchBehavior(trophy/ 目录)。

其中 ItemDropBehavior 被 4 种奖杯复用(Chicken / Cow / PigZombie / Sheep / Pig 中的 5 种),构造参数是 (probability, ItemStack) 或 (probability, ItemStack, sound)。

实体缓存

每种奖杯只创建一个「假实体」并缓存(ENTITY_CACHE,TrophyHandler.java:50、:70-83):

try {
    entity = trophy.createEntity();
} catch (Throwable t) {
    Log.severe(t, "Failed to create dummy entity for trophy %s", trophy);
}

createEntity() 用 EntityList.createEntityByName(toString(), null)(:219-221)——按枚举名查实体 ID,所以 PigZombie / VillagerGolem 这类与原版实体 ID 名不完全一致的枚举名会返回 null。这是不吞异常的 catch(记 Log.severe),但缓存仍会把 null 存进去,后续 getEntityFromCache 会走 entity == null 分支重试(:71-79)——即每次访问都会重试创建。

setSlimeSize 也用反射(ReflectionHelper.call 试 func_70799_a 与 setSlimeSize 两名),失败时 Log.warn(e, "Can't update slime size")(:85-93)。

掉落概率:可配置公式

TrophyHandler 有一个可热改的表达式求值器(dropChangeCalculator,:54-55),表达式来自 Config.trophyDropChanceFormula,在 ConfigurationChange.Post 时重读(:61-68)。

公式的三个全局符号(:244-247):

符号 值
looting event.lootingLevel
specialDrop event.specialDropValue
chance Config.trophyDropChance

默认公式(Config.trophyDropChanceFormula,Config.java:145):

let([bias=rand()/4, selection=rand()], (looting + bias) * chance - selection)

trophyDropChance 的默认值是 0.001,且它的配置注释自陈为遗留值:"Legacy value. For actual configuration, see 'trophyDropChanceFormula'"(Config.java:137)。

Supplier.get() 的回退实现(:252-256):

final double bias = fallbackDropChance.nextDouble() / 4;
final double selection = fallbackDropChance.nextDouble();
return (event.lootingLevel + bias) * Config.trophyDropChance - selection;

即结果 > 0 时掉落(:259)。掉落物是 new EntityItem(...),delayBeforeCanPickup = 10(10 刻拾取延迟,:264-270)。

触发条件:event.recentlyHit && canDrop(entity)(:240)。

辅助映射

静态初始化块(:223-230)用 t.name() 建 ImmutableMap<String, Trophy> TYPES(:232),并导出 Trophy[] VALUES = values()(:234)。getItemStack() 把枚举值写进方块 meta(ItemTrophyBlock.putMetadata,:189-191)。

playSound(:193-208)把缓存实体瞬移到目标点,synchronized (e) 内播放 playLivingSound() 后把 worldObj 置回 null。

数值

数值名 来源 值
奖杯种类 Trophy 枚举 25(TrophyHandler.java:97-146)
带行为的奖杯数 枚举体中含 Behavior( 的行 14(见上表)
行为实现类数 trophy/ 目录 10(11 文件 − 1 接口)
默认缩放 scale 字段初值 0.4(TrophyHandler.java:148)
默认垂直偏移 verticalOffset 初值 0.0(TrophyHandler.java:149)
掉落公式回退偏置 fallbackDropChance.nextDouble() / 4 0 ~ 0.25(:253)
掉落物拾取延迟 delayBeforeCanPickup 10 刻(:270)
缩放取值范围 逐项统计 0.1(Ghast,:133)~ 1.0(Bat,:103)
垂直偏移取值 逐项统计 −0.3(Bat,:103)~ 0.5(Squid,:142)

交互

触发 行为
玩家右键奖杯方块 调 executeActivateBehavior(TrophyHandler.java:210-213)
奖杯每刻 调 executeTickBehavior(:215-217)
玩家击杀生物 LivingDropsEvent 触发概率公式,命中则掉对应奖杯(:237-270)
放置方块 / 首次访问 创建并缓存假实体用于渲染(:70-83)
声音播放 移动缓存实体到目标点后 playLivingSound()(:193-208)

合成配方

奖杯方块没有合成配方,也不在任何 Config.registerCraftingRecipes 的 recipeList.add 中。唯一来源是 TrophyHandler.onLivingDrops(TrophyHandler.java:238)的击杀掉落,或创造模式/指令。

相关条目