资讯动态

Mangos自定义内容编辑:world库、SmartAI与四类实体落地

发布时间:2026/10/29 15:40:27 来源:尧图企业网站定制
简介Mangos物品、任务、BOSS、NPC等编辑软件面向Mangos服务端搭建、私服内容维护与数据表调试人员用于集中查看和修改游戏内物品、任务、怪物、NPC及相关静态配置减少手工改库带来的字段错漏。压缩包共66个文件约1.63MB包含55个csv数据表、2个sql脚本、5个lng语言文件以及exe主程序、dll运行库、txt说明和bmp设置图示覆盖数据编辑、多语言切换与初始化配置等环节。已有927人学习下载适合需要快速调整服务端内容、核对字段含义与批量维护数据的开发者参考也可作为理解Mangos数据结构、配置流程和常见字段取值的实用工具包便于在搭建与维护过程中提高效率。1. 从“加个自定 BOSS”说起这套编辑器到底省了什么上周有人问我不改核心代码、不重新编译能不能给自己的服加一个会喊话、会掉三件装备、还能发任务的守关 BOSS。能但要动四张表creature_template定它的血量模型阵营smart_scripts让它有行为creature_loot_template决定它掉什么creature_questrelation让它头顶冒出感叹号。手写 SQL 当然做得成问题是一个字段填错客户端就是一片空白甚至 worldserver 直接起不来。Mangos 这套物品、任务、BOSS、NPC 编辑软件解决的正是这一段把散在七八张表里的字段收进同一套表单改完直接写回库或导出 SQL。它适合自己搭服做自定义内容的人也适合接手别人服、需要快速摸清现有数据的人。2. 先看清工具改的是哪一层world 库、核心缓存与客户端 DBC很多人第一次用这类编辑器会犯同一个错以为改完库里那一行游戏里立刻就能看见。真实情况是一行数据要穿过三层才显示到玩家屏幕上编辑软件只管其中一层。把这三层的边界搞清楚后面所有“我改了怎么没反应”的问题都能自己回答。2.1 一条自定义内容要穿过哪三层第一层是 MySQL 里的 world 库物品模板、任务模板、生物模板、刷新点、掉落、AI 脚本全在这里编辑软件直接读写这一层。第二层是服务端核心worldserver 启动时把模板表整批读进内存缓存运行时不再查库所以改完必须重载对应模板或者重启。第三层是客户端模型、图标、技能效果这些东西由客户端自带的 DBC 文件决定服务端只能引用已有的编号不能凭空创造。层具体是什么编辑软件能否直接改改错的典型后果数据层world 库各张*_template、*_loot_template、smart_scripts能这是它的主战场数据脏、引用悬空、服务端启动报错核心层worldserver 内存缓存、硬编码的 ID 段与逻辑不能只能靠重载或重启生效改了库但游戏里没变化客户端层模型、图标、声音、地图等 DBC 资源不能只能引用已有编号物品显示成问号、生物变隐形方块所以这个工具的正确定位是“库编辑 引用校验”。它能帮你把displayid填对、把掉落物品的entry关联对但它变不出一个客户端里不存在的模型。提示判断某个字段是不是客户端决定的看它后缀就能猜个八九不离十——displayid、modelid、sound、spellid这类基本都是引用客户端已有资源填之前先确认这个编号在现有数据里被用过。2.2 四类实体的表骨架与字段权重工具界面上摆了几百个输入框实际决定“能不能用”的只有一小撮。下面这张表是我自己接手陌生服时的第一张速查表按它过一遍基本能判断一份数据是活的还是死的。实体主表决定“能不能用”的关键字段必须一起看的关联表物品item_templateclass/subclass、Quality、ItemLevel、RequiredLevel、displayid、stackablecreature_loot_template、reference_loot_template任务quest_templateMinLevel、QuestLevel、RequiredRaces、RequiredClasses、PrevQuestId、NextQuestIdcreature_questrelation、creature_involvedrelation、quest_template目标计数BOSS/生物creature_templateminlevel/maxlevel、faction、rank、npcflag、AIName、modelid1creature刷新点、creature_loot_template、smart_scriptsNPCcreature_templatenpc_text、gossip_menunpcflag位掩码、gossip_menu_idnpc_text、gossip_menu_option、conditions一个容易混淆的点creature_template是模板creature才是刷新点。模板里写“这是一只 80 级精英”刷新点里写“它站在哪张地图的哪个坐标、多久重生一次”。工具如果只让你改模板不让你加刷新点那只改模板等于没改怪根本不会出现在世界上。2.3 什么时候该用 GUI什么时候老老实实写 SQLitem_template一张表上百列quest_template六十多列靠记忆写 INSERT 是不现实的这是 GUI 最大的价值字段有标签、有下拉、有默认值还能顺手检查外键。但 GUI 也有明确的边界下面这几种情况我一般直接切回命令行批量操作比如把某个 ID 段内所有物品的BuyPrice统一乘 0.8跨表一致性检查GUI 不会告诉你“这条掉落引用的物品根本不存在”版本迁移把自定义内容从旧库搬到新库导出 SQL 再导入最快复杂条件conditions表里的条件组用表单点起来比写 SQL 还慢。换句话说GUI 负责“造单条内容”SQL 负责“批量、校验、搬运”。这两件事分工清楚效率差好几倍。3. 把库连通账号权限、字符集与表结构核对在打开编辑器之前有三件事必须先确认库连得上、字符集是对的、表结构与工具版本对得上。这三件事任何一件没做后面都会以“莫名其妙”的形式翻车。3.1 建一个只动 world 库的专用账号不要用 root 连编辑器。这类工具的表单里有删除按钮也有“批量替换”这种一键改一片的功能权限收窄是最便宜的一道保险。常见做法是单独建一个只对 world 库有增删改查权限的账号# 先在命令行确认能连上再填进编辑器 mysql -h 127.0.0.1 -P 3306 -u root -p-- 专用编辑账号只碰 world 库不给 DDL 权限 CREATE USER wedit127.0.0.1 IDENTIFIED BY ChangeMe_Local_01; GRANT SELECT, INSERT, UPDATE, DELETE ON world.* TO wedit127.0.0.1; FLUSH PRIVILEGES;这里刻意没有给DROP、ALTER、CREATE。工具出错最多写脏几条数据不会把整张表删掉而脏数据是可以靠备份和 SQL 找回来的。参数上wedit127.0.0.1里的主机位限定为本机编辑器和服务端跑在同一台机器上时这样最省事如果分机部署把这个地址换成编辑机 IP不要图方便写成%。如果这套服还有characters、realmd两个库编辑账号不需要碰它们。物品、任务、生物、NPC 的内容全在 world 库里把三个库搞混是新手最常见的错误之一。3.2 字符集中文名变问号的根因自定义内容只要写了中文名字符集问题迟早会撞上。表现是编辑器里显示正常游戏里或者重连之后变成一串问号。根因通常有两个一是库或表的默认字符集是三字节的utf8存不下某些字符二是客户端连接没有声明字符集写入时就已经被截断了。-- 揪出所有不是 utf8mb4 的表 SELECT table_name, table_collation FROM information_schema.tables WHERE table_schema world AND table_collation NOT LIKE utf8mb4%;-- 库级默认字符集确认 SELECT schema_name, default_character_set_name, default_collation_name FROM information_schema.schemata WHERE schema_name world;第一条查询返回空说明表级字符集统一返回一堆表名就说明这个库是历史遗留的混合字符集中文内容写进去迟早出事。改法上稳妥的顺序是先全库备份再把库默认字符集和涉及的几张表统一到utf8mb4最后在编辑器的连接参数里显式声明字符集不要依赖驱动的默认值。注意字符集转换必须在有备份的前提下做。已经存成问号的数据是救不回来的只能重新录入所以第一次导入自定义内容之前就把字符集定好比事后补救省太多事。3.3 用一条 entry 打通闭环环境确认完先不要急着做 BOSS。拿一条物品做最小闭环验证“编辑 → 写库 → 重载 → 游戏内可见”这条链路是通的。在编辑器里新建一条物品entry填90000名称随便写一个测试名class选消耗品或杂项Quality选 1displayid抄一个现有物品的值不要自己编保存写库。然后用 SQL 回查-- 回查刚写入的物品确认字段真的落库了 SELECT entry, name, class, subclass, Quality, ItemLevel, RequiredLevel, displayid, stackable, BuyPrice, SellPrice FROM item_template WHERE entry 90000;字段说明class和subclass一起决定物品归类与默认图标槽位Quality决定名字颜色0 灰到 5 橙displayid是客户端模型引用填错就是问号stackable决定堆叠上限写 1 表示不可堆叠。这条查询能返回一行且displayid不为 0说明写库这一步没问题。接下来重载模板。不同核心的命令名不完全一致.reload后面接的参数要以你手上核心的帮助输出为准拿不准就重启 worldserver虽然慢但一定生效。进游戏用 GM 命令给自己刷一件能看到正确名字和图标这条链路就算打通了。后面做任务、做 BOSS 都是在这条链路上加表不会再遇到新类型的问题。4. 四类实体逐个落地物品、任务、BOSS、NPC这一章是真正动手的部分。四类实体之间有依赖关系合理的顺序是“物品 → 任务 → 生物 → NPC 与对话”因为任务奖励要引用物品掉落要引用物品NPC 又要引用任务。4.1 物品先定 ID 段再谈属性第一步不是填属性是定 ID 段。官方内容占掉了大量编号自定义内容如果随手填一个entry很可能撞上核心预留段或者已有数据表现是“物品刷出来是别的东西”或者“服务端启动时报重复 entry”。我一般给自己划一个高位段比如物品用90000–90999任务用91000–91999生物用90000–90999里另划一块段与段之间留空方便以后插内容。属性上武器类要重点看dmg_min/dmg_max/dmg_type/delay四个字段的组合delay是攻击间隔毫秒数伤害数值要和它匹配否则会出现“秒伤高得离谱”的武器。带技能的物品看spellid_1到spellid_5以及对应的spelltrigger、spellcharges、spellcooldownspelltrigger决定是装备时生效、使用后生效还是击中时触发。-- 一条自定义武器的最小写入未列出的列走默认值 INSERT INTO item_template (entry, class, subclass, name, displayid, Quality, ItemLevel, RequiredLevel, inventory_type, dmg_min1, dmg_max1, dmg_type1, delay, bonding, stackable, BuyPrice, SellPrice) VALUES (90000, 2, 7, 测试短刃, 12345, 3, 60, 55, 13, 40, 72, 0, 1800, 1, 1, 120000, 24000);参数逐个说class2是武器subclass7是单手剑一类的分支具体对照关系以你的库版本为准inventory_type13表示主手dmg_type10是物理伤害delay1800即 1.8 秒一击bonding1是拾取绑定想做成装备后绑定就换成对应值BuyPrice/SellPrice单位是铜币120000就是 12 金。这套值不是标准答案但组合是自洽的改的时候四项伤害相关字段要一起调。物品做完掉落才有东西可挂。掉落表里两个参数最容易翻车ChanceOrQuestChance的符号和groupid的分组语义。-- 给 90001 这只怪挂一件 25% 掉落的物品 INSERT INTO creature_loot_template (entry, item, ChanceOrQuestChance, groupid, mincount, maxcount, condition_id) VALUES (90001, 90000, 25.0, 0, 1, 1, 0);ChanceOrQuestChance填正数是普通掉率填负数是“只有接了对应任务的人才会掉”绝对值仍是概率groupid相同的一组条目互斥一组里只会出一个填 0 表示不分组mincount不能大于maxcount否则这条掉落永远算不出来condition_id关联conditions表填 0 表示无条件。这五个参数里只要错一个表现就是“掉率写了 100 却不掉”或者“一次掉一堆”。4.2 任务链式关系比文案更容易出错任务表的字段分三块准入条件等级、种族、职业、前置任务、目标杀几只、交什么物品、去哪个区域、奖励经验、金钱、物品、可选物品。文案类的Details、Objectives、OfferRewardText写错只是难看准入条件写错是直接接不到任务。链式任务是新手最容易绕晕的地方。PrevQuestId表示“必须先完成哪个任务”NextQuestId表示“完成后自动接到哪个”ExclusiveGroup用来做多选一的分支。这三个字段填反了任务链要么断要么出现“同时能接两个互斥任务”的怪现象。-- 任务 9100055 级可接杀 8 只 90001奖励一件 90000 INSERT INTO quest_template (entry, Method, ZoneOrSort, MinLevel, QuestLevel, Type, RequiredRaces, RequiredClasses, Title, Objectives, Details, RequiredNpcOrGo1, RequiredNpcOrGoCount1, RewardXp, RewardMoney, RewardItemId1, RewardAmount1) VALUES (91000, 2, 0, 55, 60, 0, 0, 0, 测试任务, 击杀 8 只测试守卫。, 这是一个用于验证链路的测试任务。, 90001, 8, 8000, 50000, 90000, 1);参数说明Method2一般表示“杀怪类”任务Type0是普通组队任务RequiredRaces和RequiredClasses填 0 表示不限制填掩码则按位限制RewardXp是经验值RewardMoney单位铜币RewardItemId1是必给奖励如果要“多选一”则用RewardChoiceItemId系列字段。不是每一列都必须填但填了就要保证引用对象存在。让 NPC 能发任务、能交任务靠的是两张关系表这两张表的作用完全不同-- 让 90001 发放 91000头顶感叹号 INSERT INTO creature_questrelation (id, quest) VALUES (90001, 91000); -- 让 90001 接收 91000 的交付头顶问号 INSERT INTO creature_involvedrelation (id, quest) VALUES (90001, 91000);只写第一张任务能接不能交只写第二张NPC 头顶有问号但给不了任务。两张都写才是完整闭环。另外别忘了creature_template里的npcflag要包含任务位否则关系表写对了右键点上去也没有任何反应——这是最高频的翻车点之一。4.3 BOSS 与 NPC模板、刷新点、行为脚本三件套生物这条线要动三张表creature_template定它是什么creature定它在哪smart_scripts定它怎么动。少任何一张表现分别是“没有这个怪”、“怪不在那”、“怪站着不动”。-- 生物模板80 级精英可对话 可发任务 UPDATE creature_template SET name 测试守卫, subname 自定义内容, minlevel 80, maxlevel 80, faction 35, npcflag 3, rank 3, AIName SmartAI, MovementType 0, modelid1 12345 WHERE entry 90001;rank3是精英0 普通、1 精英、2 稀有精英、3 首领、4 稀有它会影响血量与经验系数faction建议直接抄一个同地图同阵营的现有 NPC 的值自己瞎填会导致“怪不打你”或“全城追杀你”npcflag3是位掩码1 是对话、2 是任务合起来就是 3。常用的几个位值如下位值含义典型用途1对话gossip有自定义菜单的 NPC2任务给予与交付头顶感叹号或问号16职业训练师学技能32商人卖东西64飞行管理员开航线256旅店老板绑炉石512银行职员开仓库8192拍卖师开拍卖行npcflag是按位相加的要“既能对话又能发任务”就是 123“商人 修理”就是 32 加修理对应的位。填的时候一定要按位加不要直接填一个看起来顺眼的数字。加刷新点这一步-- 在 map 0 的指定坐标刷出这只怪300 秒重生 INSERT INTO creature (guid, id, map, position_x, position_y, position_z, orientation, spawntimesecs, MovementType) VALUES (900001, 90001, 0, -8900.0, 600.0, 95.0, 3.14, 300, 0);guid是刷新点的唯一编号和id模板编号不是一个东西这是初学者最容易混的一对spawntimesecs是重生秒数orientation是朝向弧度。坐标建议先在游戏里用 GM 命令站好位置再查出来贴进去比对着地图估靠谱得多。行为脚本用 SmartAI本质是把“事件 → 动作 → 目标”写成表行-- 进入战斗时喊一句死亡时再喊一句 INSERT INTO smart_scripts (entryorguid, source_type, id, link, event_type, event_phase_mask, event_chance, event_flags, event_param1, event_param2, event_param3, event_param4, action_type, action_param1, action_param2, action_param3, action_param4, action_param5, action_param6, target_type, target_param1, target_param2, target_param3, target_param4, comment) VALUES (90001, 0, 0, 0, 4, 0, 100, 0, 0, 0, 0, 0, 1, 9001, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 进入战斗喊话), (90001, 0, 1, 0, 6, 0, 100, 0, 0, 0, 0, 0, 1, 9002, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 死亡喊话);参数说明entryorguid对应生物模板编号source_type0表示来源是生物event_type4是进入战斗、6是死亡、0是战斗中周期触发event_chance100是触发概率百分比action_type1是说话action_param1填creature_ai_text之类文本表里的分组编号target_type1是自身。这些枚举值在不同核心分支上略有出入写之前对着自己核心的 SmartAI 文档核一遍编号比事后猜“为什么它不说话”快得多。4.4 改完怎么验证三条 SQL 加一次重启图形界面的“保存成功”只代表写进了库不代表游戏里能用。我习惯在重启之前先跑三条检查把悬空引用先筛掉-- 1. 掉落的物品是否真实存在 SELECT l.entry AS creature, l.item FROM creature_loot_template l LEFT JOIN item_template i ON i.entry l.item WHERE i.entry IS NULL AND l.item 0; -- 2. 任务关系指向的任务是否存在 SELECT qr.id AS npc, qr.quest FROM creature_questrelation qr LEFT JOIN quest_template q ON q.entry qr.quest WHERE q.entry IS NULL; -- 3. 刷新点是否指向存在的模板 SELECT c.guid, c.id FROM creature c LEFT JOIN creature_template t ON t.entry c.id WHERE t.entry IS NULL;三条都返回空才值得重启。第一条查出来的通常是“物品 ID 打错一位”第二条是“任务做完删了但关系表没清”第三条是“模板删了刷新点还在”——这三种悬空引用轻则报错刷屏重则 worldserver 直接崩在启动阶段。重启之后按顺序验先.lookup creature 90001看模板在不在再飞去坐标看刷新点有没有怪右键看有没有对话和感叹号接任务打怪看掉落和计数交任务看奖励。每一步都对上了这条内容才算真正做完。5. 避坑实录六条踩过的坑下面六条都是“现象看着玄学、原因其实很土”的典型每条按现象、原因、解决三段写遇到了直接对号入座。5.1 头上有感叹号点开是空的现象NPC 头顶明明有黄色感叹号右键点开任务列表一片空白或者只有一个“再见”。原因三种可能叠在一起。npcflag没开任务位缺 2或者creature_questrelation写了但creature_involvedrelation漏了或者quest_template的准入条件把玩家挡在外面MinLevel高于当前等级、RequiredRaces掩码不匹配、PrevQuestId指向一个没做完的任务。解决先查SELECT npcflag FROM creature_template WHERE entry 90001;确认位掩码包含 2再查两张关系表是否成对存在最后把MinLevel、RequiredRaces、RequiredClasses、PrevQuestId四个字段临时全置 0 试一次能接了再逐个填回去定位。5.2 物品显示成问号或者干脆看不见现象GM 命令能刷出来但图标是问号鼠标悬停没有名字或者背包里是个空白格。原因displayid填了一个客户端不存在的模型编号或者把displayid错填进了entry或者class/subclass组合非法导致客户端无法归类。解决entry用自定义段比如 90000 起displayid一定要从现有物品里抄——SELECT displayid FROM item_template WHERE displayid 0 LIMIT 20;挑一个复制过来最保险。改完重载物品模板再验别在原地反复试。5.3 中文全变问号现象编辑器里中文正常进游戏或者重启之后名字变成一串???。原因库或表的字符集是三字节utf8或者连接没有声明字符集写入那一刻就已经截断了后面怎么改都救不回来。解决先备份把库和涉及的表统一到utf8mb4编辑器连接参数显式声明字符集然后重新录入中文内容。已经变成问号的行没有修复价值只能重写。5.4 掉率写了 100 却一次不掉现象ChanceOrQuestChance明明写了 100打了二十只一只没掉或者反过来一次掉出来五件。原因写成了-100负号在掉落表里表示“只有接了对应任务才掉”没任务的人打一辈子也不掉另一种是groupid相同的几条互斥你以为每条独立判定实际一组只出一个还有mincount大于maxcount这条记录直接被判为无效。解决普通掉落填正数想要“必掉一件”就把groupid设为 0 且概率 100想要“三选一”才用相同的非零groupidmincount ≤ maxcount是硬约束。改完清一次怪重新打掉落表有缓存打同一只不会刷新结果。5.5 改了库游戏里毫无变化现象SQL 回查数据是对的游戏里就是老样子。原因核心把模板整批读进内存改库不影响运行中的进程或者你改的是characters、realmd库而不是world库或者改了模板没重载刷新点模板变了但世界里那只怪的实例还是旧的。解决先确认改的是 world 库再执行对应的重载命令拿不准就重启 worldserver如果只改了creature_template记得刷新点也要重新加载或者让怪重新生成一次击杀后等重生、或者用 GM 命令删除再刷。5.6 BOSS 血量和伤害完全不对现象模板里写的 80 级实际打起来像 60 级或者血量正常但一刀秒人。原因血量不是直接写绝对值而是由等级、rank、HealthModifier一类的系数共同算出来的伤害受DamageModifier、BaseAttackTime、dmgschool影响rank从精英改成首领血量和经验系数一起变。只改等级不改系数出来的数值当然不对。解决改完先打一次记录实际血量和单次伤害再回头调系数一次只动一个参数。另外确认刷新点没有重复生成同一只怪——SELECT id, COUNT(*) FROM creature WHERE id 90001 GROUP BY id;数量超出预期会让战斗场面完全变样。6. 进阶ID 段巡检与上线前的一套自检自定义内容做到十几条之后真正的问题不再是“怎么填”而是“我怎么知道有没有撞号”。手工翻表不现实我一般用一个几十行的小脚本把各表的占用情况扫一遍顺便算出下一个可用编号。# id_audit.py —— 扫描各模板表在自定义段内的占用情况 import pymysql TABLES { item_template: entry, quest_template: entry, creature_template: entry, gameobject_template: entry, } BASE 90000 # 自定义段起点按自己的规划改 conn pymysql.connect( host127.0.0.1, port3306, userwedit, passwordChangeMe_Local_01, databaseworld, charsetutf8mb4, # 字符集必须显式声明 ) cur conn.cursor() for table, col in TABLES.items(): cur.execute(fSELECT {col} FROM {table} WHERE {col} %s ORDER BY {col}, (BASE,)) used [row[0] for row in cur.fetchall()] used_set set(used) nxt BASE while nxt in used_set: # 从起点往后找第一个空位 nxt 1 print(f{table:24s} 已占用 {len(used):4d} 条下一个可用编号 {nxt}) cur.close() conn.close()逻辑很简单把每张模板表里大于等于自定义段起点的编号取出来做成集合再从起点开始逐个试探第一个不在集合里的就是空位。参数上BASE按你自己的分段规划改charsetutf8mb4不能省否则查出来的中文名会是乱码容易误判成数据损坏。跑完把输出记下来四张表的“下一个可用编号”就是下一批内容的起点。这个习惯的价值在于撞号往往不是立刻暴露的可能过两周某个旧任务的奖励突然变成了别的东西那时候再排查就是灾难。搬运自定义内容我也有固定套路按 ID 段导出而不是整库 dump# 只导自定义段的数据不带建表语句方便回滚和迁移 mysqldump -h 127.0.0.1 -u wedit -p world \ --no-create-info --complete-insert --skip-extended-insert \ --whereentry BETWEEN 90000 AND 90999 \ item_template quest_template creature_template custom_90000.sql--no-create-info只导数据不导表结构目标库结构一致时直接source就能用--complete-insert让每行 INSERT 都带列名避免以后表加列导致导入错位--skip-extended-insert一行一条语句出问题时能精确定位到哪一行失败。这三个参数一起用导出的文件可读性和可回滚性都够用。最后是上线前的自检我固定跑四步第一步 SQL 悬空引用三连查前面 4.4 那三条第二步 ID 段巡检脚本第三步重启 worldserver 看启动日志有没有红字第四步进游戏走一遍完整流程——接任务、打怪、看掉落、交任务、看奖励、确认对话文本。这四步走完再对外开比事后回档便宜太多。踩过最贵的一次坑是给一个活动 BOSS 挂了三组掉落groupid全填了同一个值玩家打完只出一件活动开了两小时才发现。从那以后我每次写完掉落表都强制先自己打十次统计出货分布再看一眼groupid和ChanceOrQuestChance的符号——这两个字段加起来只有四个字符翻车成本却是整场活动。希望帮到你。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑