版本信息
你使用的系统:Windows 10 1909 64位版
你是用的JDK: Java HotSpot™ 64-Bit (build 1.8.0_251-b08)
你使用的IDE:IntelliJ IDEA
你使用的IDE版本: 2020.2
Forge版本: 31.2.0
Minecraft版本: 1.15.2
Mapping 文件版本: snapshot-20200514-1.15.1
情况简述
我想要添加一个物品,手持时可以吸引所有继承了 AnimalEntity 的动物实体,但是发现所有可以吸引动物实体的物品都是直接写死在实体类中的。所以我想问 Forge 有没有提供什么方法可以为一个动物实体添加可吸引的物品,或者是我应该怎么做才能大致实现我想要的功能。
查到的资料
ChickenEntity.java
public class ChickenEntity extends AnimalEntity {
private static final Ingredient TEMPTATION_ITEMS = Ingredient.fromItems(Items.WHEAT_SEEDS, Items.MELON_SEEDS, Items.PUMPKIN_SEEDS, Items.BEETROOT_SEEDS);
...
protected void registerGoals() {
...
this.goalSelector.addGoal(3, new TemptGoal(this, 1.0D, false, TEMPTATION_ITEMS));
...
}
几个思路。
- 反射获取
TEMPTATION_ITEMS
获取这个类,然后加物品
- AT 修改private改成public,加物品
- 用Coremod加方法添加物品。
推荐等级从高到低,最后一个方法如果不是迫不得已不要用。
可是在某些动物实体类里没有TEMPTATION_ITEMS
字段。
CowEntity.java
public class CowEntity extends AnimalEntity {
protected void registerGoals() {
...
this.goalSelector.addGoal(3, new TemptGoal(this, 1.25D, Ingredient.fromItems(Items.WHEAT), false));
...
}
那就分别对待,继续看调用链,反正想法就是看这些东西存在哪里,然后直接改存的地方的值。
最终的解决方案是订阅 EntityJoinWorldEvent
事件,为所有的 AnimalEntity
添加了一个新的 TemptGoal
,新的 TemptGoal 不会影响旧的 TemptGoal。但是因为 EntityJoinWorldEvent
事件在实体加载时也会触发,所以需要做一些判断。
大致的代码如下:
public void onAnimalAppear(EntityJoinWorldEvent event) {
if (event.getEntity() instanceof AnimalEntity) {
AnimalEntity animalEntity = (AnimalEntity) event.getEntity();
boolean alreadySetUp = false;
for (Goal goal : animalEntity.goalSelector.goals) {
if (goal instanceof TemptGoal) {
TemptGoal temptGoal = (TemptGoal) goal;
if (temptGoal.isTempting(new ItemStack(ItemRegistry.item.get()))) {
alreadySetUp = true;
break;
}
}
}
if (!alreadySetUp) {
animalEntity.goalSelector.addGoal(3, new TemptGoal(animalEntity, 0.8D, false, Ingredient.fromItems(ItemRegistry.item.get())));
}
}
}
其中,GoalSelector
中的 goals
字段是 private 的,TemptGoal
中的 isTempting
方法是 protected 的,因此需要使用 AT 进行修改。
这个思路来自于 Quark 的代码,并根据实际情况做了些调整。
但是我还是想问问有什么办法能够不用 AT,毕竟 AT 可能会触发兼容性问题。
我觉得这里用AT没什么太大的问题,遇见问题再说吧。
该主题在最后一个回复创建后7天后自动关闭。不再允许新的回复。