稷然如此

  • 首页
  • 文章分类
    • AI
    • Android
    • Java
    • Shell
    • Vue
    • C#
    • Python
    • 数据库
    • 组件
    • 其他
    • Game
  • 常用命令
    • Docker
    • Git
    • Linux
  • 操作系统
    • CentOS
    • Ubuntu
    • Windows
    • Kylin
  • 工具
    • IntelliJ IDEA
    • Visual Studio Code
稷然如此
不积跬步,无以至千里
  1. 首页
  2. 文章分类
  3. Game
  4. 正文

魔兽世界开源 Azeroth Core 服务端 Lua

2024年9月27日 1248点热度 0人点赞

1、自定义模块简介

除了开源代码集成了优秀的自定义幻化、嵌入式Lua引擎模块之外,用户也可以根据自身需求自定义功能模块。

 

二、嵌入式 Lua 脚本引擎简介

项目源码git地址:https://github.com/azerothcore/mod-eluna,Eluna支持MaNGOS,CMaNGOS,TrinityCore和AzerothCore,开源社区还提供了入门指南、API接口、Lua参考手册、示例脚本等等各种文档,极大的方便用户进行开发。

 

三、开发工作准备

首先,我们需要克隆一份Lua功能模块源码。
1、克隆Lua引擎模块源码
进入克隆下来的AzerothCore源码目录下modules文件夹,空白处右键选择Git Bash Here。
在弹出的git命令行中输入:git clone https://github.com/azerothcore/mod-eluna.git mod-eluna,等待下载完成。
2、使用CMake重新编译
请参考兄弟篇文章《魔兽世界开源 Azeroth Core 服务端编译手册》第九、十章。在编译前,先把build目录下所有文件删掉,注意备份源码编译输出目录下的bin\Debug\data文件夹内容、那3个拷贝过来的动态链接库dll以及修改过的configs目录下的两个配置文件,后续使用VS编译源码完成后,可以直接覆盖过去。
生成的新工程会多出lua_scripts文件夹以及configs目录下的modules文件夹,我们需要进入configs\modules文件夹,复制mod_LuaEngine.conf.dist并重命名为mod_LuaEngine.conf,不做修改,让它默认配置就行了。后续编写完成的lua脚本,直接放到lua_scripts根目录下。
3、开发工具的选择
开发工具可选以下其中一个,但我还是墙裂推荐使用Visual Studio Code,宇宙最强开发工具(代码编辑器)没有之一,和我们编译服务端的Visual Studio 2022开发工具都是同一家公司出品,那就是盖茨公司。虽然没有VS功能强大和全面,但它免费啊,插件生态圈那么优秀、突出不是吗?2022年了都,相信大多写前端的工程师码农们,用的都是VS Code吧?
记事本,伤不起
NotePad++,其实用这个也就够了
LuaEdit,没用过
Visual Studio Code,墙裂推荐

 

四、编写 Lua 脚本前准备工作

1、根据个人癖好,在指定的目录下新建一个文件夹,我这里指定的是和AzerothCore源码目录平级的文件夹,也就是D:\games\wow\azeroth-core\lua-scripts。
2、使用VS Code打开这个文件夹
3、打开后,咱先装一个南山必胜客开源的Lua插件LuaHelper,让代码看起来舒服点不是吗?当然,打开前也可以安装,怎么高兴怎么来。
4、新建一个名为teleport-stone.lua文件,看名字就知道,传送石,不错!今天我们将编写一个具有传送功能的对话菜单lua脚本,并将它绑定到物品【炉石】上。
5、我们看下社区针对lua引擎模块的其他介绍。
6、先看API接口文档,看都有些什么接口。
7、再看看示例脚本,其中example_gossip.lua就是我们要做的对话菜单Demo,盘它。
8、进去看看Demo怎么写的,我们今天要做的是绑定对话菜单到物品【炉石】上,所以只用关心其中的RegisterItemGossipEvent函数,其他暂时用不到。比如RegisterCreatureGossipEvent函数针对非玩家控制的目标(也就是NPC)事件,RegisterPlayerEvent函数是监听玩家事件。
9、AzerothCore代码太多,一开始也不可能一行行去读,上来直接放大招,在源码工程里ctrl + shift + F全局搜索,就搜RegisterItemGossipEvent这个函数。
10、可以看到,函数RegisterItemGossipEvent需要三个参数(实际上是4个,只不过最后个参数默认为0,咱暂时用不到),调用方式是这样婶的:
RegisterItemGossipEvent(itemId, eventType, callback, [cout]),其中参数itemId为绑定的物品id;eventType为注册的事件类型(1为绑定物品对象事件,2为对话菜单选中事件);callback为事件回调函数,[count]为调用次数,可选参数,默认为0,因暂时用不到,我们在调用时,只需要传前三个参数就行了。
11、第一个参数就是物品的唯一标识,也就是物品id,接下来我们需要找到【炉石】在数据库里的唯一标识,需要使用到以下几个工具:
 a.巫妖王之怒中文数据库站点:https://80.wowfan.net/
b.Keira3,详情请看:https://www.azerothcore.org/catalogue.html#/
c.Navicat数据库管理工具
12、咱先到巫妖王之怒中文数据库站点:https://80.wowfan.net/去搜一下【炉石】这个物品,找下这个物品的id。
13、我们在中文数据库站点找到【炉石】的id为6948,觉得不靠谱?那就使用工具Keira3再查一遍,这个工具链接的就是本地数据库acore_world。
14、不过从Keira3工具查询出来的结果,那也不能够确定啊,谁知道【炉石】的专业术语对应的英文是啥对不对?还是不太靠谱,Ok,直接放大招,用Navicat打开acore_world库,找到物品表item_template,在此之前让我们大胆猜测,数据库里肯定有国际化的表,这张表记录就是对应这些物品的各种语言的描述。
15、现在我们已经找到【炉石】这件物品的id了,下一步就是分析下示例脚本example_gossip.lua的RegisterItemGossipEvent注册绑定物品对话菜单事件和事件回调函数OnGossipHello。
看下源码的GossipClearMenu、GossipMenuAddItem函数说明。
从上图中可以看出,调用的GossipMenuAddItem函数所需传递的各项参数,故调用方式应为:player:GossipMenuAddItem(icon,sender,intid,code,popup,money),其中参数icon为菜单图标;sender为菜单绑定的句柄,暂理解为附加数据;intid为菜单项唯一标识,也就是菜单id;code为是否弹出输入框,默认为false;popup为弹出确认对话框的内容,字符串类型,为空则不弹出;money为扣除玩家身上的游戏币金额。
16、接着看选中对话菜单项回调函数OnGossipSelect。
综上所述,选中菜单项回调函数会传递7个参数,分别是event(事件)、player(当前玩家)、object(绑定对象)、sender(绑定句柄)、intid(菜单id)、code(弹出的输入框输入内容)、menu_id(菜单id),现在我们就可以来看看回调函数OnGossipSelect的函数体具体信息了。

 

五、编写对话菜单 Lua

该了解的大致都了解了,接下来开始动手写脚本代码咯!咱也照葫芦画瓢,一步一步来,让一颗普通的【炉石】变成一颗【超级炉石】。
1、注册对话菜单绑定到指定物品【炉石】。
--[[
    制作炉石对话功能
]] --
-- 已知【炉石】id为6948,声明它为绑定对象
local BIND_ITEM = 6948

--[[
    添加菜单项
        player:当前玩家
        object:绑定对象
        menuId:菜单id
]] --
local function AddMenuItem(player, object, menuId)
    player:GossipClearMenu() -- 清除当前玩家对话菜单列表
    --[[
        发送菜单到绑定物品
        GossipSendMenu(npc_text, sender)
            npc_text:world数据库表npc_text对应的id,默认使用id为100的数据记录
            sender:绑定对象
    ]] --
    player:GossipSendMenu(1, object, menuId)
end

--[[
    指定物品绑定对话菜单回调函数,这里我们先让它显示主菜单界面
        参数:
            参阅源码RegisterItemGossipEvent函数注释
]] --
local function OnShowMenu(event, player, object)
    --[[
        添加菜单项
        AddMenuItem(player, object, menuId)
            player:当前玩家
            object:绑定对象
            menuId:菜单id
    ]] --
    AddMenuItem(player, object, 1)
end

--[[
    注册物品对话菜单绑定事件
        BIND_ITEM:绑定的物品
        1:注册绑定事件类型,对指定物品绑定对话菜单
        ShowMenu:当使用绑定的物品时回调的函数
]] --
RegisterItemGossipEvent(BIND_ITEM, 1, OnShowMenu)
编写好的脚本保存后复制到lua_scripts根目录下,需要重启authserver和worldserver。
相信细心的同学已经发现了,在使用炉石弹出对话菜单的时候,居然还在读条,那么我们怎么取消这个动作呢?其实在前面的第四章第9节有说过,RegisterItemGossipEvent这个事件回调的lua脚本方法,方法返回false(return false)的话就会停止施法,我们只需要让lua脚本的OnShowMenu方法返回false就可以了,稍加改动下脚本。

local function OnShowMenu(event, player, object)
    --[[
        添加菜单项
        AddMenuItem(player, object, menuId)
            player:当前玩家
            object:绑定对象
            menuId:菜单id
    ]] --
    AddMenuItem(player, object, 1)
    return false --停止施法
end
2、为弹出的对话菜单添加菜单项。
我们只需要修改AddMenuItem方法,在调用GossipClearMenu函数和调用GossipSendMenu函数之间处理添加菜单项逻辑就行了。
local function AddMenuItem(player, object, menuId)
    player:GossipClearMenu() -- 清除当前玩家对话菜单列表
    --[[
        添加菜单项
        GossipMenuAddItem(icon, text, sender, intid, code = false, popup, money)
            icon:图标类型可以搜源码查看枚举GossipOptionIcon,下图中的函数。
            text:菜单名称
            sender:绑定句柄
            intid:唯一标识,菜单id
            code:是否弹出输入框
            popup:字符串类型,有值的话就弹出对话确认
            money:扣除玩家费用
    ]] --
    player:GossipMenuAddItem(0, "菜单一", 0, 2)
    --[[
        发送菜单到绑定物品
        GossipSendMenu(npc_text, sender)
            npc_text:world数据库表npc_text对应的id,默认使用id为100的数据记录
            sender:绑定对象
    ]] --
    player:GossipSendMenu(1, object, menuId)
end
GossipMenuAddItem函数用到的icon图标参数,可以在源码库game\Entities\Creature\GossipDef.h头文件中枚举GossipOptionIcon查看。
3、处理点击(选中)菜单项。
前面说过,RegisterItemGossipEvent的第二个参数,事件类型为2就是选中菜单项响应事件。我们暂时以发送提示消息来实现这个功能,发送提示消息的接口是SendBroadcastMessage("提示消息内容"),在Lua模块下PlayerMethods.h头文件里。
首先,需要注册选中菜单项事件。
--[[
    注册对话菜单选中事件
    BIND_ITEM:绑定的物品
    2:注册绑定事件类型,对话菜单项被选中
    OnSelectMenu:选中对话菜单项时回调的函数
]] --
RegisterItemGossipEvent(BIND_ITEM, 2, OnSelectMenuItem)
然后就是声明回调方法OnSelectMenuItem。
--[[
    选中菜单回调函数
        event:事件
        player:玩家
        object:绑定对象
        sender:绑定句柄
        intid:唯一标识,菜单id
        code:弹出的输入框输入内容
        menuid:菜单id
]] --
local function OnSelectMenuItem(event, player, object, sender, intid, code, menuid)
    player:SendBroadcastMessage("响应菜单点击事件,菜单id:" .. intid)
end
到这里,绑定对话菜单到【炉石】的基本功能就完成了。接下来我们就要开始编写具有功能性的菜单咯!

 

六、编写功能性菜单 Lua

功能性菜单,顾名思义,就是让这个菜单发挥我们想要的功能作用。比如传送、修理装备、召唤玩家/NPC、刷钱/刷装备、玩家状态设置等等很多很多,具体需要看看API文档。
1、获取传送参数。
传送,这应该是最常用的功能了吧?就那地图之大,步行或骑马都要整半天,时间就是金钱我的朋友。要想能进行传送,得先找到传送API接口,看下这个接口需要传递什么参数。
现在我们知道了,传送API接口,需要传递的参数有地图id(mapId)和x、y、z、o这几个空间坐标。Ok,再来找找如何获取这些参数的API接口。
万事俱备,整起,燥起来。我们将获取到的这些传送所需参数打印出来,然后记录下这些参数(空间坐标小数位取后3位即可)。
local function OnSelectMenuItem(event, player, object, sender, intid, code, menuid)
    local mapId = player:GetMapId() --获取当前玩家所在地图id
    local x = player:GetX() --获取当前玩家所在地图X坐标
    local y = player:GetY() --获取当前玩家所在地图Y坐标
    local z = player:GetZ() --获取当前玩家所在地图Z坐标
    local o = player:GetO() --获取当前玩家所在地图O坐标
    player:SendBroadcastMessage("响应菜单点击事件,菜单id:" .. intid .. ",当前地图id:" .. mapId ..
                                    ",X坐标:" .. x .. ",Y坐标:" .. y .. ",Z坐标:" .. z .. ",O坐标:" .. o)
end
2、穿梭艾泽拉斯
现在,传送的几个参数我们都获取到了,可以开始传送咯!等会儿我稍微跑远点,然后点击菜单再给人物传送回来,嘿嘿嘿......
local function OnSelectMenuItem(event, player, object, sender, intid, code, menuid)
    --[[
        Teleport(mapId, x, y, z, o)
            mapId:地图id
            x:X坐标
            y:Y坐标
            z:Z坐标
            o:O坐标
        刚才获取到的各项传递参数,小数位精确到后3位就够了
            mapId:1
            x:-2920.7922363281
            y:-269.55258178711
            z:53.859161376953
            o:6.1865758895874

    ]]--
    player:Teleport(1, -2920.792, -269.552, 53.859, 6.186)
end
是不是很简单?哈哈,到这也就完成我们编写的第一个Lua脚本了,更多的功能接口功能,需要自己去慢慢摸索哦!下篇章,我们来说说修改源码那些事儿,比如:调整宠物血量、宠物物理攻击、玩家拉怪漏背眩晕(坦克天赋下,拉怪不应该被眩晕)等等。
标签: azeroth core lua 巫妖王之怒 魔兽世界
最后更新:2024年9月28日

Akim

犇 骉 Java、C#、Python、Go、Android、MiniProgram、Bootstrap、Vue2

点赞
< 上一篇
文章目录
  • 1、自定义模块简介
  • 二、嵌入式 Lua 脚本引擎简介
  • 三、开发工作准备
  • 四、编写 Lua 脚本前准备工作
  • 五、编写对话菜单 Lua
  • 六、编写功能性菜单 Lua

Copyright © 2025 aianran.com All Rights Reserved.

免责申明 | 隐私政策 | 服务条款 | 关于我们

黔ICP备2023008200号-1

贵公网安备 52010202003594号