Bukkit 如何自定义实体/怪物的行为

在Bukkit里,如何自定义实体、怪物的行为呢?

本文用魔改牛牛君为例,介绍了两种如何怪物、生物的行为AI的方法。


一、设想效果


在我设想的效果中,自定义的怪物是多种多样的。同一个怪物模型,不同的怪物等级,拥有不同的AI。举个简单的例子。

普通僵尸:见到玩家会追击和攻击
懒惰的僵尸:见到玩家不会主动追击,除非玩家攻击他。
胆小的僵尸:见到玩家就会逃跑。
变异的僵尸:不惧怕太阳照射。

以上的这几个僵尸例子,就是使用同一个怪物模型(僵尸),不同的AI实现。
而要达成这个想法,使用我翻译的那篇文章显然是不可能的。

在我们自定义怪物的时候,只能自定义已有怪物的AI,而不能修改他们的材质或模型,因为那样的话客户端无法正常显示。

二、研究Minecraft底层中Entity的工作


为此,我专门翻阅了Entity在底层中是如何工作的。
简单来说,Entity包含很多种,而我们的怪物或者是动物的父类是LivingEntity(活性实体)
而LivingEntity之中包含了该实体的AI部分处理。

Entity Living AI Task

在上图中,tasks和targetTasks都是实体的AI表,而每个AI表都存在多个AI处理器。

Zombie AI

如图是实体僵尸的所有AI,定义了僵尸会游泳, 攻击,监视附近的玩家,以及主动攻击玩家,村民和铁傀儡。首先攻击伤害自己的单位。
而我们的工作就是把这些AI全部修改掉,然后修改成我们自定义的AI。

大约就是 entity.tasks.clear() 和 entity.targetTasks.clear() 这么简单。

每个具有AI的实体都是由World来进行刷新的(每Tick一次 / Tick = 1/20s)

三、魔改牛牛君


众所周知,牛牛菌属于动物,是不会攻击任何生物/怪物 或玩家的。而我们要做的是一个疯狂的牛牛菌,他攻击鸡鸡菌。

为了简化,我简单写了一个插件,然后注册了一个命令叫做mobs,下面我开始onCommand里魔改牛牛菌:

Cow

只有简单的几行,我们就可以创建出一个独一无二的,拥有独立AI的牛牛菌。(正常的牛不会受到影响)


第一步、获取Server/World的NMS实例

我们通过CommandSender获得Player(当然Console是不可以使用这个指令的)
关键的第一步我们要获得WorldServer,而对于这个WorldServer,我要进行一下解释:
大家可能都知道Bukkit的World,他代表了一个世界。而如果你深究他是如何实现的,你会发现真正实现它的是CraftBukkit的CraftWorld,而CraftWorld封装了WorldServer。

对于这三者的关系是这样的。
WorldServer是原生的,血脉纯正,MOJANG写的。
CraftWorld 是非官方组织开发的,属于CraftBukkit,封装了WorldServer。
而Bukkit的World只是一个接口,他真正的实现类是CraftWorld。
所以我们通过World强转获得CraftWorld,而通过CraftWorld的getHandle()获得WorldServer的实例


第二步、创建一个实体。

创建实体的步骤很简单,实例化一个实体类。将这个实体类添加到世界中。(如果不添加到世界中则不会显示和刷新AI)
实例化需要提供一个WorldServer作为参数。


第三步、删除实体的AI,让他变白痴。

删除实体的AI,重新实例化一个PathfinderGoalSelector,并覆盖掉实体原来的PathfinderGoalSelector。
新的PathfinderGoalSelector是空的,所以相当于置空了实体的AI列表。
这样做,会让疯狂的牛牛菌变成一个白痴。你打他,他没反应。你把他推到水里,他会沉底。你拿着小麦在他面前晃悠,他无视你。
他不会走动,不会转头。攻击他也不会惊慌失措的逃跑。

PathfinderGoalSelector 是AI列表(具体请看最后解释)


第四步、重新制作牛牛菌的脑子。

下一步就是重新制作牛牛菌的脑子了,我们的目标是: 让牛牛菌主动攻击鸡
你可以看到在上图的代码中,我给他添加了一个名为AIAtk的AI处理器,没错,这个AIAtk是我自己写的一个AI处理器。他会让实体攻击其他实体。

AIAtk完全仿照PathfinderGoalMeleeAttack ,PathfinderGoalMeleeAttack貌似不能为动物所用,无效果,我还没研究透彻。不清楚哪里限制了这个AI处理器不能为动物所用,所以我写了一个AIAtk,完全复制PathfinderGoalMeleeAttack的代码,但是在伤害计算部分是直接进行伤害的

随后我给他的目标选择器targetSelector添加了一个主动攻击近处的目标的AI处理器,而目标设定为EntityChicken鸡鸡菌。

你可以用PathfinderGoalMeleeAttack替代AIAtk,结果是牛追击鸡,但是不会造成伤害。


第五步、开服测试

Test1

首先我通过指令mobs生成了一个疯狂的牛牛菌,它现在是半脑残状态,因为我移除了它自由移动的AI,所以它只会站着不动。面对我们的镜头,一点也不紧张。

Test2

一墙之隔,就是一只正常的鸡鸡菌,它是我用刷怪蛋刷出来的。它拥有健全的大脑,它会监视离它太近的单位(玩家)。有玻璃挡着,它们安然相处。

Test3

而当我把玻璃破坏一个口,牛牛菌疯一般的跳过来,然后几脚就把这只可怜的鸡鸡菌踩死了。(如图鸡受到伤害)

很棒,我们实现了牛牛菌的大脑重制。

这对实现多样化的怪物AI有极大的帮助。

设想一下,我们可以让僵尸拥有更高的智慧:
他们可以有仇恨值,可以召唤其他僵尸到来。可以指挥其他僵尸攻击某一个单位。
而动物们,也不再是任人宰杀了,他们可以反击,追击和远远的逃跑。
而BOSS也不只是末影龙和凋零了,有了强大的AI系统,任何一个生物,哪怕是小鸡,也可以成为一个恐怖的,拥有强大技能和AI的终极BOSS。

四、区块卸载重加载时,怪物的自定义行为就会被清空。

原因就是当区块卸载时,怪物的数据就会以NBT的形式保存在Chunk区块文件中,而我们自定义的行为并不在保存的数据之列,也就被理所当然的刷了下去。当区块再加载,怪物从区块文件中读取出来并重新实例化时,我们的自定义行为就消失了。

我不确定这个问题是否和版本有关,我在1.9.4版本下进行的测试。

为了解决这个问题,我们有几种解决方案:
1、修改Entity的NBT序列化过程,把我们的自定义行为写到数据文件中。
2、记录Entity的UUID作为唯一标识,将自定义行为存储在其他地方,当怪物重新被加载时,重新将自定义行为写到怪物身上。

看上去显然第一条比较复杂,修改服务器端需要很大的功夫,也比较麻烦。现在采用第二种方案来修复这个BUG。

通过ChunkLoadEvent来监听区块被加载的事件,然后对这个区块上所有实体进行检测。需要注意的是,ChunkLoadEvent这个事件是异步的,你在监听到事件后马上getEntities()是只会返回空的,所以你需要延迟一段时间再获取,比如:

Bukkit.getScheduler().scheduleSyncDelayedTask(Plugin,Runnable,40L);

我们获取了刚加载的所有怪物的列表,然后依次判断他们的UUID是否在我们的插件数据库中有记录,如果有记录,根据记录对其的AI进行设置。

如果觉得好麻烦,请使用下面这种方法。下面这个就不会遇到这种问题。


五、使用反射更自由化的操控AI

“这个方法因为原理不同,所以不会遇到上面第四节所说的BUG”


其实还有一种更彻底的操控方法,就是替换掉Minecraft原生的AI操作类,替换成我们的AI类。
EntityTypes(EntityList)中定义了所有实体的类型、ID和对应的处理类。我们通过反射来篡改Minecraft注册的类,来替换成我们的类。

这个方法虽然复杂一些,但是更自由。

1

如上图,通过直接获取EntityTypes的Field进行修改来达成目的。

我修改了实体列表中的EntityPig类为我自己的Pig类。

2

我自己写的Pig类继承了EntityPig这个原生的AI类,这样一来我们只需要修改想改变动的部分就可以了。

在我创建的Pig类中,在其生成的时候输出一句话来证明实体猪的创建,最终实例化的是这一个类。
(这里忘记运行截图了)

注解

EntityTypes = EntityList
它们是同一个类,但是MCP和CraftBukkit反混淆时给他们起了不同的名字
由于对Minecraft源码的研究我是通过MCP来完成的,CraftBukkit的反混淆不彻底无法进行研究。故在本文中出现了MCP反混淆时命名的类名
他们和CraftBukkit的命名有明显的插件,故作此解释:
本文中的实体列表类,在MCP的反混淆中叫做EntityAITasks,在CraftBukkit的反混淆中叫做PathfinderGoalSelector。实体AI处理器在MCP中被命名为EntityAIXXXX,而在CraftBukkit中则被命名为 PathfinderGoalXXXX。他们的意思都是一样的。同样的,EntityList(MCP)和EntityTypes(CraftBukkit)也是这样的。

  • 3
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
这个是下载就可以使用的,我正在开的服务端 bukkit版本为493 内含插件 AnjoSecurity 注册登录插件 BackupPlugin 自动备份插件 BorderGuardLite 地图限制范围插件 EssentialsSpawn 出生点设置插件 GroupManager 权限管理插件 LWC 箱子加密插件 -------------------------------- server.properties 基本配置文件 level-name=world 地图名称 hellworld=false 是否开启地狱 false/true spawn-monsters=true 是否开启怪物 false/true online-mode=false spawn-animals=true 是否开启动物 false/true max-players=30 服务器最大同时在线人数 30人 server-ip= 服务器ip(我没有填写) pvp=false 是否开启pk false/true server-port= 服务器端口(我没有填写) white-list=true 是否开启白名单(白名单添加方法下面介绍) spawn-protection=16 出生保护时间 秒 白名单添加方法 在控制台输入 whitelist add xxxx 将xxxx添加到白名单 添加自己到admin组 manselect world 选定world地图 ,这里替换成你的地图名字 manuadd ropng admin 将ropng添加到admin组 将ropng替换成你的名字 ----------------------------------- anjosecurity注册插件 /register 密码 注册密码 /login 密码 登录 /reset 密码 重新设定密码 --------------------------- borderguardlite /setborder 数字 例如 /setborder 20 则设定以自身为原点,直径为40的圆限定范围 ,任何人无法再范围外移动 /disableborder 取消范围 注意! 此插件的权限为 第一个使用此命令的玩家可以永久使用 其他人无法使用 ,所以尽早设置 如无需此插件 进入plugin文件夹 删除borderguardlite.jar ---------------- EssentialsSpawn 重生点设置 游戏内admin组玩家输入 /setspawn 设置玩家当前点为重生点 --------------------------- lwc锁箱子插件 游戏内输入/lwc有详细介绍 --------------------------
vscode是一种功能强大的集成开发环境,可用于开发各种编程语言的应用程序和插件。对于开发bukkit插件,vscode提供了许多有用的功能和插件,使开发过程更加高效和方便。 首先,vscode具有丰富的代码编辑功能,包括语法高亮、自动补全、代码片段和代码导航。这些功能有助于开发者更容易地编写和调试bukkit插件的代码,并提高代码的可读性和质量。 其次,vscode支持许多流行的插件,可以轻松扩展开发环境的功能。例如,通过安装Java插件,可以为bukkit插件项目提供实时错误检查、智能建议和自动重构等功能。同时,还可以通过安装Git插件,轻松管理版本控制和团队合作。 此外,vscode还内置了强大的调试工具,可帮助开发者在开发过程中快速定位和解决问题。借助这些调试工具,开发者可以轻松设置断点、监视变量和查看调用栈,从而更好地理解和调试bukkit插件的运行时行为。 最后,vscode还具有丰富的扩展生态系统,可以满足开发者的个性化需求。开发者可以通过安装各种插件和主题,定制自己的开发环境,使其更符合自己的喜好和习惯。 综上所述,vscode是一款适用于开发bukkit插件的理想工具。其强大的编辑功能、丰富的插件支持、强大的调试工具和个性化定制能力,都使得开发者能够更高效、更舒适地进行bukkit插件开发工作。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值