发现
为 Kraftland 唱片更新音乐的时候, 我注意到 Minecraft 内唱片资源包无论怎样替换都会有截断音乐的问题. 查找一些资料之后发现这似乎是 1.19.4 引入的新 特性
.
经过 [MC-260346]
在 1.19.4 中, Mojang 为 Java Edition 引入了一个新功能: 和基岩版一样, 唱片机将可以与漏斗集成:
- 在唱片播放完毕之后, 漏斗将会吸走唱片机中的唱片
- 漏斗能将唱片导入唱片机 (来源请求)
为了实现第一条功能, Mojang 并没有选择判断歌曲长度再适时弹出唱片, 而是选择 Hardcode 一个固定的唱片时常并不允许修改. 这个 Bug 第一次出现于 23w06a
快照中.
表现
使用资源包替换 11 号唱片 (时长大于 1:11), 在播放到原版唱片的长度时立刻停止, 即使唱片机下方没有漏斗.
可能的解决方案
Dirty Trick
使用资源包添加自定义音效 (e.g. kraftland.intro
)
编写数据包, 在玩家插入唱片的一刻播放自定义音效
Right Fix (Credit Apollo)
原版反编译 Code (net.minecraft.world.level.block.entity.JukeboxBlockEntity.java // Original):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| public class JukeboxBlockEntity extends BlockEntity implements Clearable, ContainerSingleItem { ... @VisibleForTesting public void startPlaying() { this.recordStartedTick = this.tickCount; this.isPlaying = true; this.level.updateNeighborsAt(this.getBlockPos(), this.getBlockState().getBlock()); this.level.levelEvent((Player) null, 1010, this.getBlockPos(), Item.getId(this.getFirstItem().getItem())); this.setChanged(); } ... public void setItem(int p_273461_, ItemStack p_273584_) { if (p_273584_.is(ItemTags.MUSIC_DISCS) && this.level != null) { this.items.set(p_273461_, p_273584_); this.setHasRecordBlockState((Entity) null, true); this.startPlaying(); } } private boolean shouldRecordStopPlaying(RecordItem p_273267_) { return this.tickCount >= this.recordStartedTick + (long) p_273267_.getLengthInTicks() + 20 L; } ... }
|
Fix:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| public class JukeboxBlockEntity extends BlockEntity implements Clearable, ContainerSingleItem { private long customDuration; ... @VisibleForTesting public void startPlaying(ItemStack itemStack) { this.customDuration = itemStack.getTag() != null ? itemStack.getTag().getLong("CustomDuration") : -1; this.recordStartedTick = this.tickCount; this.isPlaying = true; this.level.updateNeighborsAt(this.getBlockPos(), this.getBlockState().getBlock()); this.level.levelEvent((Player) null, 1010, this.getBlockPos(), Item.getId(this.getFirstItem().getItem())); this.setChanged(); } ... public void setItem(int p_273461_, ItemStack p_273584_) { if (p_273584_.is(ItemTags.MUSIC_DISCS) && this.level != null) { this.items.set(p_273461_, p_273584_); this.setHasRecordBlockState((Entity) null, true); this.startPlaying(p_273584_); } } private boolean shouldRecordStopPlaying(RecordItem p_273267_) { return this.tickCount >= this.recordStartedTick + ((this.customDuration == -1 ? (long) p_273267_.getLengthInTicks() + 20L : customDuration * 20L)); } ... }
|
在 Fix Code 中, 如果唱片存在 NBT 标签 CustomDuration
, 就以此为唱片时长. 玩家使用
1
| /give @s minecraft:music_disc_cat{CustomDuration:114514}
|
来获得特定时长唱片