# DP-S Game Server Plugin Development Skill ## 🎯 框架架构概述 ### 整体架构层次 ``` MyProject/ (用户自定义脚本层) - GM命令、自定义功能、逻辑重写 _DPS_/_BuiltProject/ (内置功能层) - 团本系统、装备系统、交易系统等 _DPS_/_Core/ (核心框架层) - BaseClass类库、回调系统、钩子系统 Native C++ 服务器 (游戏原生代码) - 原生游戏逻辑 ``` ### 核心类体系 - User: 玩家对象核心类 - GameManager: 游戏管理器 - Packet Dungeon: 副本对象类 - Mysql/MysqlPool: 数据库连接池 - Timer: 定时器类 - NativePointer: 内存操作类 --- ## 📐 官方模块开发规范 ### OfficialProject/ 目录规范 **OfficialProject** 是官方功能模块目录,包含标准化的服务器功能模块。 #### 已有官方模块列表 | 模块名称 | 功能描述 | 配置文件 | |----------|----------|----------| | 二狗宝珠继承 | 装备宝珠属性继承系统 | 无 | | 交易邮件播报 | 交易和邮件系统播报 | 交易邮件播报.json | | 任务清除卷 | 任务相关功能 | 任务相关配置_南瓜.json | | 副本播报 | 副本通关/放弃播报 | 副本播报配置_Nangua.json | | 史诗掉落奖励 | 史诗/神器/稀有掉落奖励 | 史诗掉落奖励配置_南瓜.json | | 心悦播报 | 心悦会员登录播报 | 心悦播报配置_Nangua.json | | 战力榜 | 战力排行榜功能 | 战力榜配置_南瓜.json | | 杂项功能 | 多种游戏功能开关 | 杂项功能开关_Nangua.json | | 根据任务进入不同副本 | 任务控制副本进入 | 根据任务进入不同副本_Lenheart.json | | 深渊爆率实时控制 | 深渊爆率调整 | 深渊爆率实时控制_Nangua.json | | 独立掉落 | 自定义掉落系统 | 无 | | 自动刷新GM工具的邮件 | GM工具邮件管理 | 无 | | 装备镶嵌与时装镶嵌 | 装备和时装镶嵌扩展 | 装备镶嵌与时装镶嵌_Lenheart.json | | 记录服务器聊天内容 | 聊天内容记录 | 无 | | 门票进入副本 | 门票控制副本进入 | 门票进入副本配置_Maomi.json | #### OfficialConfig/ 目录规范 **OfficialConfig** 是官方配置文件目录,存储所有官方模块的配置。 ##### 配置文件命名规范 ``` 功能名称.json # 通用配置 功能名称_服务器名.json # 服务器特定配置 功能名称_管理员昵称.json # 管理员自定义配置 ``` ##### 通用配置结构 ```json { "功能配置": { "开关控制": true, "提示信息": "这是提示信息", "配置项1": "值1", "配置项2": ["数组值1", "数组值2"], "配置项3": { "子项1": "子值1", "子项2": "子值2" } }, "数据库配置": { "IP": "127.0.0.1", "端口": 3306, "用户名": "game", "密码": "password" } } ``` --- ## 🏢 官方模块开发模式 ### 标准模块结构 OfficialProject/ 目录下的每个模块应遵循以下结构: ``` 功能模块名/ ├── 功能模块名.nut # 主脚本文件 └── Proj.ifo # 项目信息文件(可选) ``` #### 主脚本文件模板 ```nut /* 文件名:功能模块名.nut 路径:OfficialProject/功能模块名/功能模块名.nut 创建日期:YYYY-MM-DD HH:MM 文件用途:功能模块描述 */ function _功能模块名_Main_() { // 加载配置 local config = GlobalConfig.Get("功能模块名配置.json"); // 读取配置开关 if (config["功能配置"]["开关控制"]) { // 执行功能初始化 // 注册回调 RegisterCallbacks(); // 初始化数据 InitData(); } // 注册回调和钩子 function RegisterCallbacks() { // 注册GM命令 Gm_InputFunc_Handle["命令名"] <- function(SUser, CmdString) { // 命令处理逻辑 }.bindenv(this); // 注册事件回调 Cb_reach_game_world_Func["功能模块名"] <- function(SUser) { // 事件处理逻辑 }.bindenv(this); // 注册Hook回调 Cb_HookName_Enter_Func["功能模块名"] <- function(args) { // Hook处理逻辑 return value; }.bindenv(this); } // 初始化数据 function InitData() { // 初始化数据库表 // 加载初始数据 } } ``` ### 配置文件管理 #### 读取配置 ```nut // 读取配置文件 local config = GlobalConfig.Get("配置文件名.json"); // 访问配置项 local switchState = config["功能配置"]["开关控制"]; local someValue = config["功能配置"]["配置项1"]; local arrayValue = config["功能配置"]["配置项2"][0]; ``` #### 配置热重载 ```nut // 在Main.nut中注册重载函数 GlobalOfficial_Project.ReloadProjectMap <- { "配置文件名" = "_功能模块名_Main_" }; // 重载函数 function _功能模块名_Main_(OldConfig) { // 使用旧配置清理资源(如果有) if (OldConfig) { // 清理逻辑 } // 重新加载配置 local config = GlobalConfig.Get("配置文件名.json"); // 重新初始化 // ... } ``` ### 官方模块最佳实践 #### 1. 战力榜模块模式 ```nut // 获取战力值 function GetRankNumber(charac_no) { local Config = GlobalConfig.Get("战力榜配置_服务器名.json"); local currentDB = Config["战力榜配置"]["当前选择"]; local dbConfig = Config["战力榜配置"]["数据库选择"][currentDB]; local SqlObj = MysqlPool.GetInstance().GetConnect(); local query = "SELECT " + dbConfig["字段名"] + " FROM " + dbConfig["数据库名"] + "." + dbConfig["表名"] + " WHERE " + dbConfig["条件字段"] + "=" + charac_no; local result = SqlObj.Select(query, ["string"]); MysqlPool.GetInstance().PutConnect(SqlObj); if (result.len() > 0) { return result[0][0].tointeger(); } return 0; } ``` #### 2. 副本播报模块模式 ```nut // 配置驱动的播报系统 function ReportDungeonClear(SUser, dgnName, timeUsed, monsterCount) { local config = GlobalConfig.Get("副本播报配置_服务器名.json"); // 检查开关 if (!config["副本播报开关"]) return; // 检查排除列表 local excludeDgns = config["不需要播报的副本ID"]; local excludeCIDs = config["指定角色CID不播报"]; if (excludeDgns.find(dgnName) != null) return; if (excludeCIDs.find(SUser.GetCID()) != null) return; // 构建播报消息 local msg = format(config["通关播报信息"], SUser.GetCharacName(), dgnName, GetDungeonDifficulty(dgnName), timeUsed, monsterCount ); // 发送播报 AdMsg().PutEquipment(msg, config["发送信息位置"]); } ``` #### 3. 杂项功能模块模式 ```nut // 多功能开关控制 function _杂项功能_Main_() { local config = GlobalConfig.Get("杂项功能开关_服务器名.json"); // 功能1: 设置最大等级 if (config["杂项功能开关"]["设置最高等级"][0]) { local level = config["杂项功能开关"]["设置最高等级"][1]; GameManager.SetGameMaxLevel(level); } // 功能2: 装备解锁时间 if (config["杂项功能开关"]["装备解锁(单位:秒)"][0]) { local time = config["杂项功能开关"]["装备解锁(单位:秒)"][1]; GameManager.SetItemLockTime(time); } // 功能3: 创建缔造者 if (config["杂项功能开关"]["创建缔造者"]) { GameManager.OpenCreateJob_CreatorMage(); } // Hook回调和Leave Hook返回值拦截 Cb_Item_IsBanRedeemItem_Leave_Func.BanRedeemItem <- function(args) { if (config["杂项功能开关"]["关闭商店回购"]) { return 1; // 返回1拦截默认行为 } } } ``` #### 4. 史诗掉落奖励模块模式 ```nut // 配置驱动的奖励系统 function GiveEpicReward(SUser, epicCount) { local config = GlobalConfig.Get("史诗掉落奖励配置_服务器名.json"); // 检查开关 if (!config["奖励控制"]["多件史诗奖励控制开关"]) return; // 获取奖励配置 local rewardConfig = config["奖励控制"]["多件SS对应奖励"][epicCount.tostring()]; if (rewardConfig) { foreach(reward in rewardConfig) { local itemId = reward[0]; local quantity = reward[1]; if (itemId == 0) { // 点券 SUser.RechargeCera(quantity); } else { // 道具 SUser.GiveItem(itemId, quantity); } } // 发送播报 local title = config["信息播报"]["标题"]; local contentColor = config["信息播报"]["内容颜色"]; local ending = config["信息播报"]["结尾"]; AdMsg().PutEquipment(title, 14); AdMsg().PutEquipment(ending, 14); } } ``` #### 5. 心悦播报模块模式 ```nut // 任务驱动的播报系统 function CheckXinyueStatus(SUser) { local config = GlobalConfig.Get("心悦播报配置_服务器名.json"); local xinyueConfig = config["心悦播报配置"]["心悦会员登录播报"]; // 检查开关 if (!xinyueConfig["开关"]) return; // 检查任务完成情况 local taskConfigs = config["心悦播报配置"]["任务等级配置"]; foreach(taskConfig in taskConfigs) { local taskId = taskConfig["任务ID"]; if (SUser.CheckQuest(taskId)) { // 构建播报消息 local msg = format("%s[%s]%s%s", xinyueConfig["标题"], taskConfig["心悦等级"], SUser.GetCharacName(), xinyueConfig["结尾信息内容"] ); // 发送播报 AdMsg().PutEquipment(msg, xinyueConfig["信息播报发送位置"]); break; } } } ``` ### 游戏管理器常用方法 ```nut // 设置游戏最大等级 GameManager.SetGameMaxLevel(85); // 设置装备解锁时间(秒) GameManager.SetItemLockTime(1); // 开启缔造者创建 GameManager.OpenCreateJob_CreatorMage(); // 自动解除魔法封印 GameManager.OpenRandomAutomaticUnblocking(); // 开启装备与时装镶嵌 GameManager.FixEquipUseJewel(); // 修复下线卡城镇 GameManager.FixSaveTown(); // 修复绝望之塔金币异常 GameManager.FixDespairGold(); // 设置每日可交易金币上限 GameManager.FixGlodTradeDaily(50000000); // 强化13以上免刷新 GameManager.Fix_13Upgrade(); // 开启14格技能栏 GameManager.Fix14Skill(); // 修复拍卖行消耗品上架 GameManager.Fix_Auction_Regist_Item(); // 设置副本内可丢弃物品品级 GameManager.FixDungeonDropGrade(3); // 修复邮件验证 GameManager.FixEmailRemovalVerification(); ``` ### 公告系统配置 ```nut // 登录器配置示例 { "noticeclass": ["公告", "活动", "玩法"], "notice": [ { "type": "img", "category": 1, "text": "公告标题", "link": "https://example.com", "content": "http://192.168.200.25:3000/image.png" }, { "type": "link", "category": 1, "text": "链接标题", "link": "https://example.com" } ], "scriptMd5": "", "pluginsMd5": [], "updateUrl": "www.baidu.com" } ``` --- ## 🔧 钩子系统 ### Hook 注册方法 ```nut // 步骤1: 声明回调表 Cb_HookName_Enter_Func <- {}; Cb_HookName_Leave_Func <- {}; // 步骤2: 注册Hook _Hook_Register_Currency_Func_( "0x内存地址", ["参数类型数组"], Cb_HookName_Enter_Func, Cb_HookName_Leave_Func ); // 步骤3: 添加处理函数 Cb_HookName_Enter_Func["模块名"] <- function(args) { local SUser = User(args[0]); // args是参数数组 // 处理逻辑 return value; // 可返回null或修改后的值 }.bindenv(this); ``` ### 常用钩子点 | 钩子名称 | 触发时机 | 参数说明 | |----------|----------|----------| | Cb_reach_game_world | 玩家进入游戏世界 | (C_User) | | Cb_player_exit | 玩家下线 | (C_User) | | Cb_User_Insert_Item | 玩家获得道具 | (C_User, ItemId, 数量, ...) | | Cb_Move_Area | 玩家区域移动 | (C_User, TownIndex, AreaIndex) | | Cb_base_input | 玩家普通输入 | (C_User, CmdString) | | Cb_gm_input | GM命令输入 | (C_User, CmdString) | | Cb_Use_Item_Sp | 特殊道具使用 | (C_User, ItemId) | | Cb_CInventory_ChangeEquip | 切换装备 | (C_User, EquipSlot) | | Cb_CParty_OnKillMonster | 击杀怪物 | (C_Party, C_User, MonsterId) | --- ## 📡 回调系统 ### 回调注册模式 ```nut // 简单回调 if (!("Cb_event_name_Func" in getroottable())) Cb_event_name_Func <- {}; Cb_event_name_Func["模块名"] <- function(SUser) { // 处理逻辑 }.bindenv(this); ``` ### 常用回调类型 ```nut // 玩家上线 Cb_reach_game_world_Func["模块名"] <- function(SUser) { local name = SUser.GetCharacName(); local level = SUser.GetCharacLevel(); } // 玩家下线 Cb_player_exit_Func["模块名"] <- function(SUser) { // 清理玩家数据 } // 每帧执行 Cb_timer_dispatch_Func["模块名"] <- function() { // 每帧执行逻辑 } // 副本通关 Cb_ClearDungeon_Enter_Func["模块名"] <- function(args) { local SUser = User(args[0]); // 奖励处理 } ``` --- ## 💻 GM 命令开发 ### 基本命令注册 ```nut Gm_InputFunc_Handle["命令名"] <- function(SUser, CmdString) { // 参数解析 local handler = []; local pos = 0; do { local start = pos; pos = CmdString.find(" ", pos + 1); if (pos != null) { handler.append(CmdString.slice(start + 1, pos)); } else handler.append(CmdString.slice(start + 1)); } while (pos != null); // 业务逻辑 if (handler.len() >= 1) { local itemId = handler[1].tointeger(); local quantity = (handler.len() >= 2) ? handler[2].tointeger() : 1; SUser.GiveItem(itemId, quantity); SUser.SendNotiPacketMessage("道具已发放", 8); } } ``` ### 快捷命令 ```nut Gm_InputFunc_Handle["满级"] <- function(SUser, CmdString) { SUser.SetCharacLevel(85); SUser.SendNotiPacketMessage("已满级", 8); } Gm_InputFunc_Handle["回城"] <- function(SUser, CmdString) { SUser.ChangeTown(0, 1, 0, 0); // 城镇, 区域, X, Y } ``` --- ## 🗄️ 数据库操作 ### 基本查询 ```nut // 单连接模式 MysqlObject = Mysql(Str_Ptr("127.0.0.1"), 3306, Str_Ptr("数据库名"), Str_Ptr("账号"), Str_Ptr("密码")); MysqlObject.Exec_Sql("SET NAMES 'latin1'"); // 查询 local Ret = MysqlObject.Select("SELECT id, name, level FROM users WHERE id = " + uid, ["int", "string", "int"]); foreach(Row in Ret) { local id = Row[0]; local name = Row[1]; local level = Row[2]; } // 插入/更新 MysqlObject.Exec_Sql(format("UPDATE users SET level = %d WHERE id = %d", newLevel, id)); // 获取自增ID MysqlObject.Exec_Sql("INSERT INTO users (name) VALUES ('test')"); local Ret = MysqlObject.Select("SELECT LAST_INSERT_ID()", ["int"]); local newId = Ret[0][0]; ``` ### 连接池模式 ```nut // 获取连接 local SqlObj = MysqlPool.GetInstance().GetConnect(); // 查询 local Ret = SqlObj.Select("SELECT * FROM table", ["int", "string"]); foreach(row in Ret) { // 处理数据 } // 执行 SqlObj.Exec_Sql("UPDATE table SET field = value"); // 归还连接 MysqlPool.GetInstance().PutConnect(SqlObj); ``` --- ## 🎒 装备操作 ### 装备基本操作 ```nut local InvenObj = SUser.GetInven(); // 获取装备 local Equip = InvenObj.GetSlot(Inven.INVENTORY_TYPE_BODY, 槽位); ifif (!Equip) return; // 读取属性 local upgrade = Equip.GetUpgrade(); // 强化等级 local amplification = Equip.GetAmplification(); // 增幅等级 local enchanting = Equip.GetEnchanting(); // 附魔ID local forging = Equip.GetForging(); // 镶嵌数据 local itemId = Equip.GetIndex(); // 道具ID // 修改属性 Equip.SetUpgrade(12); Equip.SetAmplification(3); Equip.SetEnchanting(1001); Equip.Flush(); // 必须调用 // 刷新客户端 SUser.SendUpdateItemList(1, 3, 槽位); ``` ### 装备继承模式 ```nut // 读取源装备属性 local sourceEquip = InvenObj.GetSlot(Inven.INVENTORY_TYPE_ITEM, 9); local forging = sourceEquip.GetForging(); local upgrade = sourceEquip.GetUpgrade(); local amplification = sourceEquip.GetAmplification(); local enchanting = sourceEquip.GetEnchanting(); // 应用到目标装备 local targetEquip = InvenObj.GetSlot(Inven.INVENTORY_TYPE_BODY, 10); targetEquip.SetForging(forging); targetEquip.SetUpgrade(upgrade); targetEquip.SetAmplification(amplification); targetEquip.SetEnchanting(enchanting); targetEquip.Flush(); // 刷新客户端 SUser.SendUpdateItemList(1, 0, 9); SUser.SendUpdateItemList(1, 3, 10); ``` --- ## ⏰ 定时器系统 ### 延迟任务 ```nut // 延迟执行(单位:游戏tick,60tick≈1秒) Timer.SetTimeOut(function() { SUser.SendNotiPacketMessage("延迟执行", 8); }, 300); // 5秒后执行 // 带参数的延迟执行 Timer.SetTimeOut(function(arg1, arg2) { print("参数1: " + arg1 + ", 参数2: " + arg2); }, 300, "hello", 123); ``` ### 定时任务 ```nut // 移除旧任务 Timer.RemoveCronTask("任务名称"); // 创建定时任务 Timer.SetCronTask(function() { // 定时执行的代码 print("定时任务执行"); return true; // 返回false取消下次执行 }.bindenv(this), { Cron = "0 */5 * * * *", // Cron表达式:每5分钟 Name = "任务名称" }); // Cron表达式格式:秒 分 时 日 月 周 // 示例: // "0 0 * * * *" - 每小时 // "0 */5 * * * *" - 每5分钟 // "0 0 0 * * *" - 每天0点 ``` --- ## 🔍 内存操作 ### 基本读写 ```nut // 写入操作 NativePointer("0x8360C38").add(3).writeU8(MaxLevel); NativePointer("0x081E907E").writeInt(value); // 读取操作 local value = NativePointer("0x8360C38").add(3).readS8(); local value = NativePointer(address).readInt(); local value = NativePointer(address).readPointer(); local str = NativePointer(address).readUtf8String(); ``` ### 字节数组操作 ```nut // 读取字节数组 local arr = NativePointer(address).readByteArray(size); // 写入字节数组(内存补丁) Sq_WriteByteArr(S_Ptr("0x081E907E"), [0x90, 0x90, 0x90, 0x90, 0x90]); ``` ### 原生函数调用 ```nut // 调用原生函数 local result = Sq_CallFunc( S_Ptr("0x082947A4"), // 函数地址 "pointer", // 返回类型 ["pointer", "int"], // 参数类型 arg1, arg2 // 参数值 ); // 常用原生函数 Sq_CallFunc(S_Ptr("0x0858EFDE"), "int", ["pointer", "pointer", "int"], S_Ptr("0x0"), SUser.C_Object, newLevel); ``` --- ## 🏗️ 模块开发模板 ### 标准模块结构 ```nut /* 文件名:模块名.nut 路径:MyProject/模块名.nut 创建日期:2026-03-16 HH:MM 文件用途:模块功能描述 */ Timer.SetTimeOut(function() { // 创建模块实例并挂载到根表 getroottable()._模块名_ <- ModuleClass(); print("模块名 - 已加载"); }, 1); class ModuleClass { MysqlObject = null; data = null; constructor() { // 初始化数据库 MysqlObject = Mysql(Str_Ptr("127.0.0.1"), 3306, Str_Ptr("数据库名"), Str_Ptr("账号"), Str_Ptr("密码")); // 初始化数据 data = {}; // 注册回调 RegisterCallbacks(); // 初始化数据 InitData(); } function RegisterCallbacks() { // 注册GM命令 Gm_InputFunc_Handle["模块命令"] <- function(SUser, CmdString) { // 命令处理 }.bindenv(this); // 注册事件回调 Cb_reach_game_world_Func["模块名"] <- function(SUser) { // 玩家上线处理 }.bindenv(this); // 注册Hook回调 Cb_HookName_Enter_Func["模块名"] <- function(args) { // Hook处理 }.bindenv(this); } function InitData() { // 初始化配置和数据 try { MysqlObject.Exec_Sql("CREATE TABLE IF NOT EXISTS table_name (...)"); print("数据表初始化成功"); } catch (exception) { print("数据表初始化失败"); } } function SaveData() { // 保存数据到数据库 } function LoadData() { // 从数据库加载数据 } } ``` --- ## 🐛 调试与测试 ### 调试命令 ``` // 在游戏中输入 T // 显示当前玩家调试信息 ResetScript // 重载所有脚本 ``` ### 调试输出 ```nut // 启用调试模式 getroottable().DebugModelFlag <- true; // 启用包调试 getroottable().PacketDebugModel <- true; // 输出调试信息 print("调试信息: " + value); // 输出表格 printT(TableObject); // 查看回调注册 print(Cb_reach_game_world_Func); ``` ### 错误处理 ```nut try { // 可能失败的操作 local result = SomeOperation(); } catch (exception) { print("Error: " + exception); if (SUser) { SUser.SendNotiPacketMessage("操作失败", 8); } } // 数据验证 if (!SUser) return; if (!InvenObj) return; if (!Equip) return; ``` --- ## 📋 常见任务清单 ### 任务1: 添加GM命令 - 创建命令处理函数 - 解析参数 - 实现功能逻辑 - 发送反馈消息 ### 任务2: 监听游戏事件 - 确定事件类型 - 找到对应回调表 - 注册处理函数 - 处理事件数据 ### 任务3: 修改游戏配置 - 找到配置内存地址 - 使用NativePointer写入 - 测试修改效果 ### 任务4: 创建自定义道具 - 注册道具使用回调 - 实现道具效果 - 验证和反馈 ### 任务5: 实现新功能模块 - 创建类结构 - 初始化数据库 - 注册回调和Hook - 实现业务逻辑 - 添加定时任务 --- ## 🎓 开发建议 ### 通用开发规范 1. **命名规范**: 使用 `_模块名_` 作为全局表前缀,避免冲突 2. **延迟加载**: 使用 `Timer.SetTimeOut` 避免初始化顺序问题 3. **错误处理**: 关键操作使用 try-catch 包裹 4. **内存管理**: 及时删除 Packet 对象,释放内存 5. **数据验证**: 检查 `rawin()` 和对象有效性 6. **性能优化**: 高频查询使用连接池,定时任务批量保存 7. **代码注释**: 添加文件头注释说明用途 8. **版本检查**: 使用 `DP_S_VERSION` 判断服务器版本 ### OfficialProject 开发规范 #### 1. 模块命名 - 使用中文命名,清晰表达功能 - 避免使用特殊字符和空格 - 示例: `杂项功能`, `战力榜`, `副本播报` #### 2. 文件结构 - 主脚本文件名与目录名一致 - 必须包含标准文件头注释 - 配置文件放在 OfficialConfig/ 目录 #### 3. 主函数命名 - 使用 `_模块名_Main_` 格式 - 用于模块初始化和重载 - 示例: `_杂项功能_Main_()`, `_战力榜_Main_()` #### 4. 配置管理 - 使用 GlobalConfig.Get() 读取配置 - 配置文件使用 JSON 格式 - 支持配置热重载 #### 5. Hook 回调命名 - 使用 `模块名.功能名` 格式 - 示例: `杂项功能.BanRedeemItem`, `战力榜.UpdateRank` #### 6. 数据库操作 - 使用连接池模式 - 使用 try-catch 处理异常 - 及时归还连接 #### 7. 播报系统 - 使用 AdMsg() 类发送公告 - 支持富文本和链接 - 注意公告频率控制 ### OfficialConfig 开发规范 #### 1. 配置文件命名 - `功能名.json` - 通用配置 - `功能名_服务器名.json` - 服务器特定配置 - `功能名_管理员昵称.json` - 管理员自定义配置 #### 2. JSON 结构规范 - 使用中文键名,提高可读性 - 包含必要的注释字段(如 "提示", "说明") - 支持嵌套结构 #### 3. 数据库配置 - 使用单独的配置节 - 包含 IP、端口、用户名、密码 - 提供默认值和提示 #### 4. 开关控制 - 使用布尔值控制功能开关 - 数组类型的配置使用 `[开关, 值]` 格式 - 提供清晰的说明 #### 5. 排除列表 - 使用数组存储排除项 - 支持 CID、道具ID、副本ID 等 - 提供注释说明如何获取 --- ## 📞 快速参考 ### User常用方法 - GetArea(), GetLocation(), GetUID(), GetCID() - GetCharacLevel(), SetCharacLevel() - GetCharacName(), GetCharacJob() - GiveItem(itemId, quantity) - SendNotiPacketMessage(msg, type) - ChangeTown(town, area, x, y) ### Packet方法 - Put_Header(op, sub), Put_Int(v), Put_Str(s) - Send(SUser) ### 数据类型 - 整数: `tointeger()` - 字符串: `tostring()` - 布尔: `true` / `false` - 表: `{key = value}` - 数组: `[value1, value2]`