Thaumcraft4 傀儡「收割」核心-魔力豆跨区种植异常问题
魔力豆农场跨区异常修复思路
我搭建了按魔力豆类型分区的农场,配备带Harvest核心与Ordo升级的傀儡负责收割,傀儡无法跨区域作业,但相邻区域却长出属性错误的魔力豆(如Vitium、Spiritus)。排查harvest()方法代码后,确认问题与ID为4的Ordo升级逻辑相关,但因不熟悉Java,无法定位具体问题点,也不知如何覆盖该逻辑,求修复思路。
void harvest() { this.count = 200; final int md = this.blockMd; final FakePlayer fp = FakePlayerFactory.get((WorldServer)this.theWorld, new GameProfile((UUID)null, "FakeThaumcraftGolem")); fp.func_70107_b(this.theGolem.field_70165_t, this.theGolem.field_70163_u, this.theGolem.field_70161_v); if (CropUtils.clickableCrops.contains(this.block.func_149739_a() + md)) { this.block.func_149727_a(this.theWorld, this.xx, this.yy, this.zz, (EntityPlayer)fp, 0, 0.0f, 0.0f, 0.0f); } else { this.theWorld.func_147480_a(this.xx, this.yy, this.zz, true); if (this.theGolem.getUpgradeAmount(4) > 0) { final ArrayList<ItemStack> items = new ArrayList<ItemStack>(); final ArrayList<Entity> drops = (ArrayList<Entity>)EntityUtils.getEntitiesInRange(this.theWorld, this.theGolem.field_70165_t, this.theGolem.field_70163_u, this.theGolem.field_70161_v, (Entity)this.theGolem, (Class)EntityItem.class, 6.0); if (drops.size() > 0) { for (final Entity e : drops) { if (e instanceof EntityItem) { if (e.field_70173_aa < 2) { Vec3 v = Vec3.func_72443_a(e.field_70165_t - this.theGolem.field_70165_t, e.field_70163_u - this.theGolem.field_70163_u, e.field_70161_v - this.theGolem.field_70161_v); v = v.func_72432_b(); e.field_70159_w = -v.field_72450_a / 4.0; e.field_70181_x = 0.075; e.field_70179_y = -v.field_72449_c / 4.0; } boolean done = false; final EntityItem item = (EntityItem)e; final ItemStack st = item.func_92059_d(); if (st.func_77973_b() != null && st.func_77973_b() == Items.field_151100_aR && st.func_77960_j() == 3) { final int var5 = BlockDirectional.func_149895_l(this.blockMd); final int par2 = this.xx + Direction.field_71583_a[var5]; final int par3 = this.zz + Direction.field_71581_b[var5]; final Block var6 = this.theWorld.func_147439_a(par2, this.yy, par3); if (var6 == Blocks.field_150364_r && BlockLog.func_150165_c(this.theWorld.func_72805_g(par2, this.yy, par3)) == 3) { final ItemStack itemStack = st; --itemStack.field_77994_a; this.theWorld.func_147465_d(this.xx, this.yy, this.zz, Blocks.field_150375_by, BlockDirectional.func_149895_l(this.blockMd), 3); } done = true; } else if (st.func_77973_b() != null && st.func_77973_b() == ConfigItems.itemManaBean) { if (this.block.func_149707_d(this.theWorld, this.xx, this.yy, this.zz, 0)) { final ItemStack itemStack2 = st; --itemStack2.field_77994_a; if (!st.func_77973_b().func_77648_a(st.func_77946_l(), (EntityPlayer)fp, this.theWorld, this.xx, this.yy + 1, this.zz, 0, 0.5f, 0.5f, 0.5f)) { this.theWorld.func_147465_d(this.xx, this.yy, this.zz, ConfigBlocks.blockManaPod, 0, 3); } } done = true; } else { final int[] xm = { 0, 0, 1, 1, -1, 0, -1, -1, 1 }; final int[] zm = { 0, 1, 0, 1, 0, -1, -1, 1, -1 }; for (int count = 0; st != null && st.field_77994_a > 0 && count < 9; ++count) { if (st.func_77973_b() != null && (st.func_77973_b() instanceof IPlantable || st.func_77973_b() instanceof ItemSeedFood) && st.func_77973_b().func_77648_a(st.func_77946_l(), (EntityPlayer)fp, this.theWorld, this.xx + xm[count], this.yy - 1, this.zz + zm[count], ForgeDirection.UP.ordinal(), 0.5f, 0.5f, 0.5f)) { final ItemStack itemStack3 = st; --itemStack3.field_77994_a; } } } if (st.field_77994_a <= 0) { item.func_70106_y(); } else { item.func_92058_a(st); } if (done) { break; } continue; } } } } } fp.func_70106_y(); this.theGolem.startActionTimer(); }
问题定位
Ordo升级的核心逻辑是:当傀儡拥有该升级时,会收集自身周围6格范围内的所有掉落物,并自动种植其中的种子/作物。导致跨区异常的两个关键点:
- 无属性过滤:收集掉落物时,没有区分魔力豆种子的属性(Vitium、Spiritus等),会把其他区域掉落的异属性种子也纳入处理。
- 强制原地种植:处理魔力豆种子时,直接在当前傀儡收割的地块(
this.xx, this.yy + 1, this.zz)重新种植,不管该地块属于哪个分区,导致异属性种子被种到错误区域。
修复方案
方案1:修改原逻辑,添加属性过滤与区域校验
修改Ordo升级中处理魔力豆的分支,同时过滤掉落物:
// 1. 先添加一个获取当前区域目标魔力豆属性的方法(需自行实现,比如读取地块标记方块的NBT数据) private int getTargetAspectForArea(int x, int z) { // 示例:读取当前地块下方的标记方块属性,返回对应Aspect的ID Block marker = this.theWorld.func_147439_a(x, this.yy - 2, z); if (marker == ConfigBlocks.blockAspectMarker) { return this.theWorld.func_72805_g(x, this.yy - 2, z); } return 0; // 默认值,根据实际情况调整 } // 2. 修改掉落物收集后的过滤逻辑 final ArrayList<Entity> drops = (ArrayList<Entity>)EntityUtils.getEntitiesInRange(this.theWorld, this.theGolem.field_70165_t, this.theGolem.field_70163_u, this.theGolem.field_70161_v, (Entity)this.theGolem, (Class)EntityItem.class, 6.0); ArrayList<Entity> filteredDrops = new ArrayList<>(); int targetAspect = getTargetAspectForArea(this.xx, this.zz); for (Entity e : drops) { if (e instanceof EntityItem) { ItemStack st = ((EntityItem)e).func_92059_d(); // 只保留与当前区域匹配的魔力豆,以及非魔力豆的其他掉落物 if (st.func_77973_b() != ConfigItems.itemManaBean || st.func_77960_j() == targetAspect) { filteredDrops.add(e); } } } // 3. 修改魔力豆种植逻辑,确保种植正确属性的豆荚 else if (st.func_77973_b() != null && st.func_77973_b() == ConfigItems.itemManaBean) { int targetAspect = getTargetAspectForArea(this.xx, this.zz); // 仅种植与区域匹配的种子 if (st.func_77960_j() == targetAspect) { if (this.block.func_149707_d(this.theWorld, this.xx, this.yy, this.zz, 0)) { final ItemStack itemStack2 = st; --itemStack2.field_77994_a; boolean planted = st.func_77973_b().func_77648_a(st.func_77946_l(), (EntityPlayer)fp, this.theWorld, this.xx, this.yy + 1, this.zz, 0, 0.5f, 0.5f, 0.5f); if (!planted) { // 种植失败时生成对应属性的豆荚 this.theWorld.func_147465_d(this.xx, this.yy, this.zz, ConfigBlocks.blockManaPod, targetAspect, 3); } } done = true; } }
方案2:用Mixin覆盖Ordo升级逻辑(模组开发场景)
若不想修改原代码,可通过Mixin注入替换Ordo升级的处理流程:
import net.minecraft.entity.item.EntityItem; import net.minecraft.item.ItemStack; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @Mixin(GolemHarvestCore.class) // 替换为原Harvest核心的类名 public abstract class MixinGolemHarvestCore { @Inject(method = "harvest", at = @At(value = "INVOKE", target = "Ljava/util/ArrayList;size()I", ordinal = 0), cancellable = true) private void overrideOrdoUpgrade(CallbackInfo ci) { GolemHarvestCore core = (GolemHarvestCore) (Object) this; // 这里实现自定义的Ordo升级逻辑,参考方案1的过滤与种植校验逻辑 // 完成自定义逻辑后取消原逻辑执行 ci.cancel(); } }
内容的提问来源于stack exchange,提问作者Greenlight Shadow
相关产品推荐
相关产品推荐

