村庄声誉与防御系统(reputation-handler)
基本信息
| 属性 | 值 |
|---|---|
| 主类 | toast.specialAI.village.ReputationHandler |
| 防御 AI | toast.specialAI.village.EntityAIVillagerDefendVillage |
| 实例化 | _SpecialAI.init() 中 new ReputationHandler() |
| 监听 | FMLCommonHandler.bus() + MinecraftForge.EVENT_BUS |
功能总览
ReputationHandler 通过 4 个事件钩子把村庄声誉系统接入:
- ServerTick(每 40 tick):扫描所有世界所有村庄
house_rep=true时:记录 doorCountCache,对比当前门数与上次差异,对半径+32 内所有玩家setReputationForPlayer(diff)refresh_houses=true时:每 400 tick(40×10)把每扇门的lastActivityTimestamp设为村庄 tick,确保村庄不会因玩家远离而"丢失"门(修复原版离开太远声誉重置的 bug)
- LivingDeath:
help_rep_chance概率(默认 0.2)在 32 格内村庄给玩家 +1 声誉(仅当死者为IMob) - HarvestDropsEvent:玩家打碎方块时根据黑/白名单与
block_*_limit阈值扣声誉/标记攻击者 - 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 | 村民主动防御 |