村庄声誉与防御系统(reputation-handler)

基本信息

属性 值
主类 toast.specialAI.village.ReputationHandler
防御 AI toast.specialAI.village.EntityAIVillagerDefendVillage
实例化 _SpecialAI.init() 中 new ReputationHandler()
监听 FMLCommonHandler.bus() + MinecraftForge.EVENT_BUS

功能总览

ReputationHandler 通过 4 个事件钩子把村庄声誉系统接入:

  1. ServerTick(每 40 tick):扫描所有世界所有村庄
    • house_rep=true 时:记录 doorCountCache,对比当前门数与上次差异,对半径+32 内所有玩家 setReputationForPlayer(diff)
    • refresh_houses=true 时:每 400 tick(40×10)把每扇门的 lastActivityTimestamp 设为村庄 tick,确保村庄不会因玩家远离而"丢失"门(修复原版离开太远声誉重置的 bug)
  2. LivingDeath:help_rep_chance 概率(默认 0.2)在 32 格内村庄给玩家 +1 声誉(仅当死者为 IMob)
  3. HarvestDropsEvent:玩家打碎方块时根据黑/白名单与 block_*_limit 阈值扣声誉/标记攻击者
  4. DefendVillageAI:村民主动攻击村庄攻击者 + 声誉 ≤ -15 的玩家

EntityAIVillagerDefendVillage

每 70~120 tick 重新查找最近村庄(半径 32);从村庄中查找 findNearestVillageAggressor;如果是玩家则记录 aggressorName;播放 mob.villager.no 音效。开始执行时 setAttackTarget(aggressor)。

continueExecuting(中断判定)

if (super.continueExecuting()) {
    if (aggressorName != null) {
        int reputation = village.getReputationForPlayer(aggressorName);
        // 声誉 > defend_limit:停止攻击
        if (reputation > ReputationHandler.getDefendLimit()
            || reputation > -15 && rand.nextFloat() < (reputation - limit + 10) / 150)
            return false;
    }
    return true;
}
return false;

这意味着:村民对声誉只是略差(>-15)的玩家会按概率性"忘记"仇恨;对声誉 ≤ -15 的玩家持续追击。

ReputationHandler.onBlockBreak(HarvestDropsEvent)

if (harvester == null) return;
if (BLOCK_WHITELIST 非空 && 不在白名单) return;
if (在 BLOCK_BLACKLIST) return;
Village village = 距离 8 格内最近村庄;
if (village == null) return;
boolean special = SPECIAL_LIST.contains(方块);
int playerRep = village.getReputationForPlayer(player);

// 1. 扣声誉
if (playerRep <= BLOCK_REP_LIMIT) {
    chance = special ? SPECIAL_REP_CHANCE : BLOCK_REP_CHANCE;
    if (world.rand.nextDouble() < chance) {
        village.setReputationForPlayer(player, -1);
        world.playAuxSFX(2004, x, y, z, 0);  // 蓝色粒子
    }
}

// 2. 标记为攻击者(村民与铁傀儡开始攻击)
if (playerRep <= BLOCK_DEFEND_LIMIT) {
    chance = special ? SPECIAL_DEFEND_CHANCE : BLOCK_DEFEND_CHANCE;
    if (world.rand.nextDouble() < chance) {
        village.addOrRenewAgressor(player);
    }
}

addOrRenewAgressor 写入村庄 aggressors 列表,是 EntityAIVillagerDefendVillage 的目标来源。

默认黑名单

block_blacklist 默认包含(不引发敌意):

  • 所有 wooden_door(含变种 spruce/birch/jungle/acacia/dark_oak)
  • stone, grass, dirt, sand, leaves, leaves2
  • 农作物(wheat, potatoes, carrots, pumpkin_stem, melon_stem, reeds, nether_wart, pumpkin, melon_block, cocoa, cactus)
  • 装饰植物(tallgrass, brown_mushroom, red_mushroom, yellow_flower, double_plant, deadbush, snow_layer, ice)

这些方块被破坏时不会扣声誉也不会被村民攻击。

默认特殊列表(block_special_list)

默认 emerald_block:绿宝石方块在村庄被打碎时使用独立的 100% 扣声誉 + 100% 标记攻击者几率(默认配置),相当于"绿宝石方块必招村民报复"。

默认白名单(block_whitelist)

默认空。若填入非空列表,则仅列表内的方块会扣声誉/标记攻击者(其他方块即使不在 blacklist 也不影响村庄)。

村庄门同步(refresh_houses)

修复了原版 1.7.10 的一个 bug:玩家走远后回到村庄时声誉会被重置。Special AI 通过 lastActivityTimestamp = villageTicks 强制每扇门保持"活跃"。

当村庄内 getNumVillagers() <= 0 且有玩家在附近(半径+32)时不刷新(避免空村庄的错误保留)。

数值总结

配置 默认 触发
block_rep_loss_chance 0.1 非特殊方块被破时扣 1 声誉
block_rep_loss_limit 8 仅当声誉 ≤ 8 时扣
block_aggression_chance 0.1 标记为攻击者
block_aggression_limit -5 仅当声誉 ≤ -5 时标记
block_special_rep_loss_chance 1.0 特殊方块被破扣声誉
block_special_aggression_chance 1.0 特殊方块被破标记攻击者
help_rep_chance 0.2 在村庄附近击杀怪物加声誉
house_rep true 房屋增减影响附近玩家声誉
refresh_houses true 房屋加入后永久保留
villagers_defend true 村民主动防御

相关条目