使用 mixin 重定向方法调用不适用于 LivingEntity.drop



我目前正在为Minecraft Fabric编程一个插件/服务器端Mod,它可以改变玩家的死亡。更准确地说:当玩家死亡时,他们应该在特定情况下保留库存。

为了实现这一点,我有一个扩展net.minecraft.entity.player.PlayerEntity并"混合"类net.minecraft.server.network.ServerPlayerEntity的类。现在,如果在if语句之后调用this.drop(),我会将onDeath(DamageSource source)中的方法调用drop()重定向到我的方法中。

@Redirect(method = "onDeath", at = @At(value = "INVOKE",
target = "Lnet/minecraft/server/network/ServerPlayerEntity;drop(Lnet/minecraft/entity/damage/DamageSource;)V"))
public void redirectDrop(ServerPlayerEntity instance, DamageSource damageSource) {
LOGGER.log(Level.INFO, "Drop called");
if (!countDeath) {
LOGGER.log(Level.INFO, "Kept Items");
return;
}
this.drop(damageSource);
LOGGER.log(Level.INFO, "Dropped Items");
}

正如您所看到的,drop()方法在死亡计数时被调用,而当它不计数时,该方法会提前返回。


但问题来了:

当死亡没有被计算在内时,玩家的库存仍然会被清空,但不会掉落物品。但我希望玩家保留他们的库存,而不仅仅是让他们什么都不掉。奇怪的是,在ServerPlayerEntity.onDeath中有这样的代码:

if (!this.isSpectator()) {
this.drop(source);
}

这使得玩家在观众模式中被杀死时保留他的物品。这是有效的,但不是我的代码。。。

有人知道我做错了什么吗?或者可以帮助我吗?

谢谢!

在对Minecraft的代码进行了一些探索之后,我终于找到了解决问题的方法:

首先
我的代码运行得很好:当死亡人数不计算在内时,玩家不会丢弃其物品。玩家库存在重新发布后为空的事实与.drop()方法无关。

其次
当玩家重生时,会创建一个全新的net.minecraft.server.network.ServerPlayerEntity。因此,新创建的ServerPlayer对象的资源清册为空。当在旁观者模式下死亡或KeepInventory设置为true时,旧ServerPlayer对象的库存将复制到新对象。

最后
为了解决我的问题,我将代码注入到ServerPlayerEntityonDeath(DamageSource source)方法中,该方法将其库存保存在Map中(将其UUID作为密钥(。为了恢复Players invenory,我将其注入net.minecraft.server.PlayerManagerrespawnPlayer方法中,以便将旧ServerPlay对象的库存复制到新对象中。为了获得新的ServerPlayer实例,我重定向了setMainArm()方法,并再次调用它,因此行为是相同的。

我的代码如下:

@Redirect(method = "respawnPlayer", at = @At(value = "INVOKE",
target = "Lnet/minecraft/server/network/ServerPlayerEntity;setMainArm(Lnet/minecraft/util/Arm;)V"))
public void respawn(ServerPlayerEntity instance, Arm arm) {
instance.setMainArm(arm);
instance.getInventory().clone(INV_CACHE.get(instance.getUuid()));

}

相关内容

最新更新