变形(Resizing)缩放的同步与相机修复
基本信息
这是本 mod 最大的一组补丁:5 个 Mixin + 1 个自有数据包 + 2 个事件处理器,
专门修 Witchery 的 PotionResizing 药水(缩小体型)在客户端的表现。
Witchery 的 Resizing 药水由 com.emoniph.witchery.brewing.potions.PotionResizing 实现,
Witchery 不在本 wiki 收录范围(见 分类页),本页只记本 mod 的补丁。
| Mixin 组 | 目标 | 阶段 | 作用 |
|---|---|---|---|
FIX_POSITON_RESIZING_EYE_HEIGHT |
witchery.PotionResizingMixin |
LATE | 缩放时眼高定位 |
WITCHERY_OFFSET_CAPTURE |
witchery.PlayerRenderMixin(仅客户端) |
LATE | 跳过原版视角偏移逻辑 |
FIX_SHAPESHIFT_CAMERA |
minecraft.EntityRendererMixin(仅客户端) |
EARLY | 相机偏移 |
FIX_SHAPESHIFT_SYNC |
minecraft.NetHandlerPlayClientMixin(仅客户端) |
EARLY | 同步位置偏移 |
FIX_SHAPESHIFT_STANCE_VALIDATION |
minecraft.NetHandlerPlayServerMixin |
EARLY | 站姿上限校验 |
FIX_IS_ENTITY_INSIDE_OPAQUE_BLOCK |
minecraft.EntityMixin |
EARLY | 窒息判定 |
组定义见 mixins/Mixins.java:13-30;文件见 mixins/early/minecraft/ 与
mixins/late/witchery/。
Y 偏移的计算(本 mod 自己的公式)
mixins/hooks/EntitySizeManager.java:26-37:
public static float getTargetYOffset(EntityPlayer player) {
EntitySizeInfo size = new EntitySizeInfo(player);
PotionEffect shrunk = Witchery.Potions.RESIZING != null
? player.getActivePotionEffect(Witchery.Potions.RESIZING)
: null;
if (shrunk == null && size.isDefault) {
return 0;
}
float amp = shrunk != null ? PotionResizing.getScaleFactor(shrunk.getAmplifier()) : 1.0F;
float scale = size.defaultHeight / 1.8F * amp;
return 1.8F * (1.0F - scale);
}
| 步骤 | 含义 |
|---|---|
size.isDefault && shrunk == null |
未变形且无缩放药水 → 偏移 0 |
amp |
缩放因子,来自 PotionResizing.getScaleFactor(放大等级);无药水时 1.0F |
scale |
目标身高 / 1.8F(标准玩家身高)× amp |
| 返回值 | 1.8F × (1 − scale) |
未在源码中调用 setter 的数值一律不要写进 wiki——defaultHeight 来自
Witchery 的 EntitySizeInfo,本 mod 读而不设。
扩展属性与存档
OffsetContents implements IExtendedEntityProperties
(EntitySizeManager.java:39-74):
- 属性键:
OFFSET_PROPERTY = "ShapeShiftOffset"(EntitySizeManager.java:39) - 字段:
currentOffset/targetOffset,均以float存 NBT (键名同为currentOffset/targetOffset,EntitySizeManager.java:47-56) init(Entity, World)是空实现(EntitySizeManager.java:59)
3 个事件处理器
全部在 EntitySizeManager 内(EntitySizeManager.java:76-101):
| 事件 | 行 | 行为 |
|---|---|---|
EntityEvent.EntityConstructing |
76-81 |
玩家实体构造时 registerExtendedProperties("ShapeShiftOffset", new OffsetContents()) |
EntityJoinWorldEvent |
83-90 |
服务端且为 EntityPlayerMP 时:发本 mod 的 EntitySizeSyncPacket(offset, true),并连发两次 Witchery.packetPipeline.sendToAll(new PacketSyncEntitySize(player)) |
PlayerEvent.Clone |
92-101 |
event.wasDeath 为 true 时直接返回(死亡不继承);否则把 currentOffset / targetOffset 从原实体复制过来 |
外加 handlers/ServerSizeHandler.java(TickEvent.PlayerTickEvent,PHASE 非 END 时 return)
与 handlers/ClientSizeHandler.java:在 contents.targetOffset != getTargetYOffset(player)
时更新并 NETWORK.sendTo(new EntitySizeSyncPacket(tmp), player)。
ClientSizeHandler 在 proxy/ClientProxy.java 的 init 中注册。
网络
- 通道:
NetworkRegistry.INSTANCE.newSimpleChannel(MODID),MODID = "WitcheryExtras"(core/WitcheryExtras.java:43) - 自有包:1 个 ——
network/EntitySizeSyncPacket.java(构造重载:(float)与(float, boolean))
📌
onEntityJoinWorld里PacketSyncEntitySize被sendToAll连续发送两次 (EntitySizeManager.java:87-88,两行完全相同,仅第二行多传了player)。 这是源码原样,未做合并。
EARLY 阶段 4 个补丁的注入点
| Mixin | 注入 | 改动的常量 / 目标 |
|---|---|---|
EntityMixin.java:14 |
@ModifyExpressionValue on isEntityInsideOpaqueBlock |
CONSTANT floatValue=0.1F |
EntityRendererMixin.java:20 |
@ModifyVariable on orientCamera,@At("STORE", ordinal = 0),ordinal = 1 |
第 2 个被存入的局部变量 |
NetHandlerPlayClientMixin.java:16-20 |
@ModifyExpressionValue on handlePlayerPosLook |
INVOKE S08PacketPlayerPosLook.func_148928_d()D |
NetHandlerPlayServerMixin.java:20 |
@ModifyExpressionValue on processPlayer |
CONSTANT doubleValue=1.65D |
PotionResizingMixin.java:15 走 MixinExtras 专有注入点:
@ModifyExpressionValue(method = "onLivingUpdate", at = @At("MIXINEXTRAS:EXPRESSION"))
——不指定目标,靠 MixinExtras 的表达式匹配生效,比常规 @At 锚点更脆弱。
这也是为什么 mixins.WitcheryExtras.late.json 声明了
"mixinextras": {"minVersion": "0.5.0"}。
PlayerRenderMixin.java:13-15 在 onRenderTick 里对
@At(value = "NEW", target = "com/emoniph/witchery/util/EntitySizeInfo") 注入。
关联
- 全部 Mixin 的注册与门控见 Mixin 补丁总表
- 另一组实体相关补丁(人偶架区块加载)见 机器容器与 TileEntity 补丁