From bafe1532850f2e3c26c5318aea61e605c9cd3996 Mon Sep 17 00:00:00 2001 From: Lenheart <947330670@qq.com> Date: Wed, 19 Nov 2025 23:22:00 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=8D=A2=E5=9B=BD=E5=86=85=E6=9C=8D?= =?UTF-8?q?=E5=8A=A1=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- AllCallBack/AllCallBack.md | 63 ++++++++++++ Object/GameManager/GameManager.md | 39 ++++++++ Object/ScriptData/ScriptData.md | 4 +- Object/Timer/Timer.md | 54 ++++++++++- README.md | 14 ++- Start/Example/15.md | 41 ++++---- Start/Example/16.md | 155 +++++++++++++++++------------- Start/Example/17.md | 69 +++++++++++++ _sidebar.md | 1 + desktop.ini | 2 + 10 files changed, 347 insertions(+), 95 deletions(-) create mode 100644 Start/Example/17.md create mode 100644 desktop.ini diff --git a/AllCallBack/AllCallBack.md b/AllCallBack/AllCallBack.md index fd4d83a..acd7ce2 100644 --- a/AllCallBack/AllCallBack.md +++ b/AllCallBack/AllCallBack.md @@ -429,5 +429,68 @@ Cb_PacketBuf_get_short_Leave_Func <- {}; 0x0858D0B0 +//公会普通信息回包 +Cb_MonitorNoticeGuildChatMsg_Enter_Func <- {}; +Cb_MonitorNoticeGuildChatMsg_Leave_Func <- {}; +0x084C9E30 + + +//公会超链接信息回包 +Cb_MonitorNoticeGuildChatMsgHyperLink_Enter_Func <- {}; +Cb_MonitorNoticeGuildChatMsgHyperLink_Leave_Func <- {}; +0x084E503C + + +//检查移动技能槽位 +Cb_CheckMoveComboSkillSlot_Enter_Func <- {}; +Cb_CheckMoveComboSkillSlot_Leave_Func <- {}; +0x08608C98 + +//检查插入快捷技能槽位 +Cb_CheckComboSkillInsertQuickSlot_Enter_Func <- {}; +Cb_CheckComboSkillInsertQuickSlot_Leave_Func <- {}; +0x08608D58 + +//检查每日日程时间 提供者: ZZ +Cb_User_CheckDailyScheduleTime_Enter_Func<-{}; +Cb_User_CheckDailyScheduleTime_Leave_Func<-{}; +0x846C0A8 + +//绝望之塔获取上次挑战时间 提供者: ZZ +Cb_User_TOD_UserState_getLastClearTime_Enter_Func<-{}; +Cb_User_TOD_UserState_getLastClearTime_Leave_Func<-{}; +0x864387E + +//时装填充 提供者: ZZ +Cb_AradUseAvatarRecharge_Enter_Func<-{}; +Cb_AradUseAvatarRecharge_Leave_Func<-{}; +0x0819FA56 + +//物品随机品级 提供者: 凌众 +Cb_CItem_IsRoutingItem_Enter_Func<-{}; +Cb_CItem_IsRoutingItem_Leave_Func<-{}; +0x08150f18 + +//调整箱使用 提供者: 凌众 +Cb_ModItemattr_Enter_Func <- {}; +Cb_ModItemattr_Leave_Func <- {}; +0x8200B08 + + +//个人金库整理 提供者: 起舞弄清影 +Cb_CCargo_sort_Enter_Func <- {}; +Cb_CCargo_sort_Leave_Func <- {}; +0x850BD0C + + +// 玩家断开链接时 提供者:南瓜 +Cb_CUser_LogoutToPCRoom_Enter_Func <- {}; +Cb_CUser_LogoutToPCRoom_Leave_Func <- {}; +0x0868170C + +// 购买道具时的检查错误 +Cb_BuyItem_check_error_Enter_Func <- {}; +Cb_BuyItem_check_error_Leave_Func <- {}; +0x081BE46A ``` --- \ No newline at end of file diff --git a/Object/GameManager/GameManager.md b/Object/GameManager/GameManager.md index 962658d..b107cfb 100644 --- a/Object/GameManager/GameManager.md +++ b/Object/GameManager/GameManager.md @@ -90,3 +90,42 @@ ### 函数签名 - `function Fix_Auction_Regist_Item()` --- + + + +## 十四、副本可丢弃品级 传入一个值 3为神器 +### 函数签名 +- `function FixDungeonDropGrade(Level)` +--- + + + +## 十五、邮件去除验证 +### 函数签名 +- `function FixEmailRemovalVerification()` +--- + + +## 十五、开启独立掉落模式 +### 此功能需要传入一个回调函数 参数为 //角色 怪物ID 怪物等级 坐标X 坐标Y 副本名称 副本ID 副本等级 副本难度 深渊标识 +### 函数签名 +- `function OpenIndependenceDropMode(Func)` +- `此功能相对复杂因此给一个例子` + +``` + function IndependenceDropLogic(SUser, MonsterId, MonsterLevel, Xpos, Ypos, DgnName, DgnId, DgnLevel,DgnDiff, HellDiff) + { + //注意这里组队时每一个队员都会调用一次这个函数 + + //如果角色名字为游戏管理员 掉落3037 + if(SUser.GetCharacName() == "游戏管理员") + SUser.DropItem(3037, Xpos, Ypos); + //如果怪物ID 为 1 掉落 3038 + if(MonsterId == 1) + SUser.DropItem(3038, Xpos, Ypos); + } + + GameManager.OpenIndependenceDropMode(IndependenceDropLogic); +``` +--- + diff --git a/Object/ScriptData/ScriptData.md b/Object/ScriptData/ScriptData.md index a27f22e..f50fa65 100644 --- a/Object/ScriptData/ScriptData.md +++ b/Object/ScriptData/ScriptData.md @@ -19,8 +19,8 @@ ``` //在默认路径的PVF Script(); - //在指定路径的PVF 例如/home/xxx/Scirpt.pvf - Script("/home/xxx/Scirpt.pvf"); + //在指定路径的PVF 例如/home/neople/game/Script.pvf + Script("/home/neople/game/Script.pvf"); ``` --- diff --git a/Object/Timer/Timer.md b/Object/Timer/Timer.md index 6d18a98..f100414 100644 --- a/Object/Timer/Timer.md +++ b/Object/Timer/Timer.md @@ -37,14 +37,15 @@ ### 函数签名 **公有函数**: -- `function SetCronTask(target_func, CronString, ...)` +- `function SetCronTask(target_func, build_info, ...)` ### 参数 - `target_func`:函数体,要获执行的函数 -- `CronString`:字符串,计划任务格式 让gpt帮你写cron字符串 +- `build_info`:可以是字符串,计划任务格式 让gpt帮你写cron字符串 也可以是一个结构体 包含 Cron 和 Name - `...`:可变参数,传入的参数可再函数体回调函数中使用 +### 注意 +- `关于定时任务的销毁`:在执行的任务中 如果不返回 或者返回null 返回true 任务都将继续执行 如果返回false 任务将不再继续执行 - -**这里给出两个个例子**: +**这里给出三个例子**: > 无参数 ``` Timer.SetCronTask(function() { @@ -60,4 +61,49 @@ print("注册 每五秒 执行") }, "*/5 * * * * ?","字符串",123); ``` +> 结构体 +``` + Timer.SetCronTask(function(str,num) { + print(str);//将打印 "字符串" + print(num);//将打印 123 + print("注册 每五秒 执行") + }, { + Cron = "0/5 * * * * *", + Name = "TestCronName" + },"字符串",123); +``` +--- + + +### 函数签名 +**公有函数**: +- `function RemoveCronTask(name)` +### 参数 +- `name`:要移除的定时任务的名字 + + +**这里给出一个例子**: +``` +//定义一个显示的变量 +getroottable().TaskCount <- 0; + +//任务 +function Task() { + getroottable().TaskCount++; + print("定时任务执行了一次,当前执行次数为:" + getroottable().TaskCount); +} + +//注册一个定时任务 每五秒执行一次 任务名为 TestCronName +Timer.SetCronTask(Task, { + Cron = "0/5 * * * * *", + Name = "TestCronName" +}); + +//十秒钟后删除之前注册的定时任务 +Timer.SetTimeOut(function() { + print("删除定时任务"); + //这里执行删除定时任务的逻辑以后 上面的定时任务将不会在继续生效 + Timer.RemoveCronTask("TestCronName"); +}, 10000) +``` --- diff --git a/README.md b/README.md index 0cad782..da59138 100644 --- a/README.md +++ b/README.md @@ -2,12 +2,20 @@ > 我该去哪里下载 -[点我下载](https://www.baidu.com) +[点我下载](https://qm.qq.com/q/cavwGu9TVu) > 是否有交流学习的地方 -[点我加群](https://qm.qq.com/q/cavwGu9TVu) +[旧群被封!这是新群!点击加入](https://qm.qq.com/q/r1QVHSIE38) > 插件是否收费 -完全免费,并且以后也不会收费。 \ No newline at end of file +完全免费,并且以后也不会收费。 + +> 最新DP-S可视化后台管理工具 小白也能轻松上手 + +[点我查看详情](https://www.bilibili.com/video/BV1xRZHYZEa4/) + +--南瓜-- + +--Davi-- diff --git a/Start/Example/15.md b/Start/Example/15.md index 9548e1e..4fad187 100644 --- a/Start/Example/15.md +++ b/Start/Example/15.md @@ -234,20 +234,20 @@ class EquimentUseJewel { } - HackReturnAddSocketToAvatarFalg = null; - function HackReturnAddSocketToAvatar(Code) { - //标记flag - HackReturnAddSocketToAvatarFalg = Code; - Cb_PacketBuf_get_short_Leave_Func.EquimentUseJewel <- function(args) { - Cb_PacketBuf_get_short_Leave_Func.rawdelete("EquimentUseJewel"); - return 0; - }.bindenv(this); + function HackAddSocketToAvatarLogic(Flag) { + if (Flag) { + Sq_WriteByteArr(S_Ptr("821A449"), [0x90,0x90]); + Sq_WriteByteArr(S_Ptr("0x821A44B"), array(36,0x90)); + } else { + Sq_WriteByteArr(S_Ptr("821A449"), [0x74,0x2B]); + } } + function FixFunction() { //称号回包 Cb_CTitleBook_putItemData_Leave_Func.EquimentUseJewel <- function(args) { @@ -270,7 +270,9 @@ class EquimentUseJewel { //装备开孔 Cb_AddSocketToAvatar_Enter_Func.EquimentUseJewel <- function(args) { local SUser = User(args[1]); - local Pack = Packet(args[2]); + local PackCopyBuffer = Memory.alloc(10001); + Memory.copy(PackCopyBuffer, NativePointer(args[2]), 1000); + local Pack = Packet(PackCopyBuffer.C_Object); local equ_slot = Pack.GetShort(); local equitem_id = Pack.GetInt(); local sta_slot = Pack.GetShort(); @@ -281,13 +283,15 @@ class EquimentUseJewel { equ_slot = equ_slot - 57; local C_PacketBuf = api_PacketBuf_get_buf(args[2]) //获取原始封包数据 C_PacketBuf.add(0).writeShort(equ_slot) //修改掉装备位置信息 时装类镶嵌从57开始。 + //执行原逻辑 return null; } //如果已开启镶嵌槽则不执行 local equ_id = NativePointer(inven_item.C_Object).add(25).readU32(); if (api_exitjeweldata(equ_id)) { - HackReturnAddSocketToAvatar(0x13); + CUser_SendCmdErrorPacket(SUser, 209, 19); + HackAddSocketToAvatarLogic(true); return null; } @@ -296,11 +300,13 @@ class EquimentUseJewel { if (ItemType == 10) { SUser.SendNotiBox("装备为武器类型,不支持打孔!", 1) - HackReturnAddSocketToAvatar(0x0); + CUser_SendCmdErrorPacket(SUser, 209, 0); + HackAddSocketToAvatarLogic(true); return null; } else if (ItemType == 11) { SUser.SendNotiBox("装备为称号类型,不支持打孔!", 1) - HackReturnAddSocketToAvatar(0x0); + CUser_SendCmdErrorPacket(SUser, 209, 0); + HackAddSocketToAvatarLogic(true); return null; } @@ -321,19 +327,12 @@ class EquimentUseJewel { Pack.Finalize(true); SUser.Send(Pack); Pack.Delete(); - HackReturnAddSocketToAvatar(0x0); + HackAddSocketToAvatarLogic(true); return null; }.bindenv(this); Cb_AddSocketToAvatar_Leave_Func.EquimentUseJewel <- function(args) { - //跳的错误返回0 正常调用的话不处理返回值 - if (HackReturnAddSocketToAvatarFalg != null) { - local SUser = User(args[1]); - // SUser.SendItemSpace(0); - CUser_SendCmdErrorPacket(SUser, 209, HackReturnAddSocketToAvatarFalg); - HackReturnAddSocketToAvatarFalg = null; - return 0; - } + HackAddSocketToAvatarLogic(false); return null; }.bindenv(this); diff --git a/Start/Example/16.md b/Start/Example/16.md index 9fa6eaf..ceb5d9e 100644 --- a/Start/Example/16.md +++ b/Start/Example/16.md @@ -15,78 +15,103 @@ 创建日期:2025-03-25 14:42 文件用途:一键入库 */ -//获取金库 -function User::GetCharacCargo() { - return Sq_CallFunc(S_Ptr("0x008151A94"), "pointer", ["pointer"], this.C_Object); -} - -//检查金库是否有指定ID道具 -function CharacCargo_Check_Item_Exist(Cargo_C_Object, ItemId) { - return Sq_CallFunc(S_Ptr("0x0850BC14"), "int", ["pointer", "int"], Cargo_C_Object, ItemId); -} - -//检查物上限品堆叠 -function Check_Item_Stack(ItemId, ItemCount) { - return Sq_CallFunc(S_Ptr("0x08501A79"), "int", ["int", "int"], ItemId, ItemCount); -} - -//将物品存入仓库 -function CharacCargo_Insert_Item(Cargo_C_Object, Item_C_Object) { - return Sq_CallFunc(S_Ptr("0x0850B400"), "int", ["pointer", "pointer"], Cargo_C_Object, Item_C_Object); -} - -Gm_InputFunc_Handle.AAWW <- function(SUser, CmdString) { - //获取金库 - local Cargo_C_Object = SUser.GetCharacCargo(); - //获取背包 +//在游戏中输入//一键入库即可调用 +Gm_InputFunc_Handle["一键入库"] <- function (SUser) { + // 获取角色背包 local InvenObj = SUser.GetInven(); - - // 物品槽范围: 57-152 (材料、消耗品栏) - local INVENTORY_SLOT_START = 57; - local INVENTORY_SLOT_END = 152; - - local anyItemInserted = false; // 标志变量,用于跟踪是否有物品被成功插入 - - for (local slot = INVENTORY_SLOT_START; slot <= INVENTORY_SLOT_END; slot++) { - local ItemObject = InvenObj.GetSlot(1, slot); - local ItemId = ItemObject.GetIndex(); - local ItemName = PvfItem.GetNameById(ItemId); - - // 如果物品ID无效,跳过当前循环 - if (ItemId <= 0) continue; - local CheckFlag = CharacCargo_Check_Item_Exist(Cargo_C_Object, ItemId); - // 如果仓库中没有该物品,跳过 - if (CheckFlag == -1) continue; - - local Cargo_M_Object = NativePointer(Cargo_C_Object); - // 获取仓库中对应物品的指针和数量 - local CargoItemPointer = NativePointer(Cargo_M_Object.add(4).readPointer()).add(61 * CheckFlag).readPointer(); - local CargoItem = Item(CargoItemPointer); - local CargoItemId = NativePointer(Cargo_M_Object.add(4).readPointer()).add(61 * CheckFlag + 2).readU32(); - //仓库中的数量 - local CargoItemCount = CargoItem.GetAdd_Info() ? CargoItem.GetAdd_Info() : 1; - //背包中的数量 - local InventoryItemCount = ItemObject.GetAdd_Info(); - - //检查物品堆叠是否超过上限 - local CanStack = Check_Item_Stack(ItemId, InventoryItemCount + CargoItemCount); - if (CanStack == 0) { - SUser.SendNotiPacketMessage("[ " + ItemName + " ]" + "超过堆叠上限,无法放入", 8); + // 角色仓库 + local CargoObj = Sq_CallFunc(S_Ptr("0x08151a94"), "pointer", ["pointer"], SUser.C_Object); + // 添加计数器 + local transferCount = 0; + // 遍历背包消耗品栏及材料栏 + for (local i = 57; i <= 152; ++i) { + // 获取背包物品 + local ItemObj = InvenObj.GetSlot(1, i); + // 获取背包物品ID + local Item_Id = ItemObj.GetIndex(); + local ItemName = PvfItem.GetNameById(Item_Id); + // 如果物品ID为0或3037,跳过(在此可以添加其他需要跳过的物品ID) + if (Item_Id == 0 || Item_Id == 3037) { continue; } - // 将物品存入仓库 - local InsertResult = CharacCargo_Insert_Item(Cargo_C_Object, ItemObject.C_Object); - if(InsertResult >= 0){ - SUser.SendNotiPacketMessage("[ " + ItemName + " ]" + "成功入库 x " + InventoryItemCount, 8); - InvenObj.DeleteItemCount(ItemId,InventoryItemCount); - SUser.SendUpdateItemList(1,0,slot); + // 角色仓库是否存在背包物品 + local CargoSlot = Sq_CallFunc(S_Ptr("0x850bc14"), "int", ["pointer", "int"], CargoObj, Item_Id); + // 如果角色仓库中没有该物品,跳过 + if(CargoSlot == -1) { + continue; } + + // 获取仓库物品指针 + local cargoItemPointer = NativePointer(CargoObj).add(4).readPointer(); + // 获取角色仓库物品对象 + local cargoItemObj = NativePointer(cargoItemPointer).add(61 * CargoSlot); + // 获取角色仓库物品ID + local cargoItemId = NativePointer(cargoItemPointer).add(61 * CargoSlot + 2).readU32(); + // 获取角色仓库物品数量 + local cargoItemCount = Sq_CallFunc(S_Ptr("0x80F783A"), "int", ["pointer"], cargoItemObj.C_Object); + + // 获取物品对象 + local PvfItem = PvfItem.GetPvfItemById(cargoItemId); + + // 获取物品可堆叠数量 + local getStackableLimit = Sq_CallFunc(S_Ptr("0x0822C9FC"), "int", ["pointer"], PvfItem.C_Object); + + // 如果仓库已达堆叠上限,跳过此物品 + if(cargoItemCount >= getStackableLimit) { + continue; + } + + // 获取背包物品数量 + local inventoryItemCount = Sq_CallFunc(S_Ptr("0x80F783A"), "int", ["pointer"], ItemObj.C_Object); + // 获取物品是否可堆叠 + local checkStackableLimit = Sq_CallFunc(S_Ptr("0x08501A79"), "int", ["int", "int"], cargoItemId, cargoItemCount + inventoryItemCount); + // 尝试将物品储存至角色仓库中 + local tryAddStackItem = Sq_CallFunc(S_Ptr("0x0850B4B0"), "int", ["pointer", "pointer", "int"], CargoObj, ItemObj.C_Object, CargoSlot); + if (tryAddStackItem >= 0) { + // 正式将物品插入角色仓库中 + Sq_CallFunc(S_Ptr("0x850b672"), "pointer", ["pointer", "pointer", "int"], CargoObj, ItemObj.C_Object, CargoSlot); + // 删除背包中的物品 + ItemObj.Delete(); + transferCount++; + SUser.SendNotiPacketMessage("[ " + ItemName + " ]" + "成功入库 x " + inventoryItemCount, 8); + } + + // 处理可堆叠物品 + if(checkStackableLimit == 0) { + // 获取物品总数 + local totalCount = cargoItemCount + inventoryItemCount; + + // 如果总数不超过上限,全部堆到仓库 + if(totalCount <= getStackableLimit) { + // 将物品堆到仓库 + Sq_CallFunc(S_Ptr("0x80CB884"), "int", ["pointer", "int"], cargoItemObj.C_Object, totalCount); + // 删除背包中的物品 + ItemObj.Delete(); + transferCount++; + SUser.SendNotiPacketMessage("[ " + ItemName + " ]" + "成功入库 x " + inventoryItemCount, 8); + } else { + // 如果总数超过上限 + // 将仓库的物品数量设置为最大数量 + Sq_CallFunc(S_Ptr("0x80CB884"), "int", ["pointer", "int"], cargoItemObj.C_Object, getStackableLimit); + // 将背包数量减去转移至仓库的数量 + local transferAmount = getStackableLimit - cargoItemCount; + Sq_CallFunc(S_Ptr("0x80CB884"), "int", ["pointer", "int"], ItemObj.C_Object, totalCount - getStackableLimit); + transferCount++; + SUser.SendNotiPacketMessage("[ " + ItemName + " ]" + "成功入库 x " + transferAmount, 8); + } + } + + // 通知客户端更新背包 + SUser.SendUpdateItemList(1, 0, i); } - //更新仓库 - SUser.SendItemSpace(2); -}; + if (transferCount == 0) { + SUser.SendNotiBox("没有可转移的物品!", 1); + } + // 通知客户端更新仓库 + SUser.SendItemSpace(2); +} ``` diff --git a/Start/Example/17.md b/Start/Example/17.md new file mode 100644 index 0000000..c5af670 --- /dev/null +++ b/Start/Example/17.md @@ -0,0 +1,69 @@ +## 史诗药剂 (贡献者: 倾泪寒 && 南瓜) + +> 首先我们先在dp_s文件夹中建立一个项目文件夹 MyProject 方便管理 + +![Alt text](../../image/6.png) + +> 然后我们建立一个新文件 史诗药剂.nut 用于编写我们的代码 + +> 然后我们在史诗药剂.nut中写入以下代码 + +``` +/* +文件名:史诗药剂.nut +路径:MyProject/史诗药剂.nut +创建日期:2025-03-28 10:21 +文件用途:史诗药剂 +*/ + +//➢SS药剂的ID +EpicPotionID <- 2600006; +//➢默认的药剂增加倍率 +EpicPotionOdds <- 0.1; +//➢指定玩家增加深渊爆率 +EpicPotionlist <- {}; +//角色ID:增加个人深渊爆率 +EpicPotionlist[1] <- 1; + + +Cb_GetItemRarity_Enter_Func["史诗药剂_逻辑"] <- function(args) { + local Addr = NativePointer(args[0]); + local VectorSize = (Addr.add(4).readU32() - Addr.readU32()) / 4; + // 遍历队伍成员,找到使用了史诗药剂的玩家 + local userWithPotion = null; + for (local i = 0; i< VectorSize; i++) { + local elementAddr = NativePointer(Addr.readPointer()).add(i * 4); + local user = elementAddr.readPointer(); + if (user && Sq_CallFunc(S_Ptr("0x865E994"), "int", ["pointer", "int", ], user, EpicPotionID) ) { + userWithPotion = User(user); + break; + } + } + if (userWithPotion && Haker.NextReturnAddress == "0x853583a") { + local partyobj = userWithPotion.GetParty(); + // 检查是否单人 + if (Sq_CallFunc(S_Ptr("0x0859A16A"), "int", ["pointer", ], partyobj.C_Object) == 1) { + local MaxRoll = NativePointer(args[1]).add(16).readU32(); + local odds = EpicPotionOdds; // 默认药剂的增加几率 + // 检查是否VIP玩家 + local charac_no = userWithPotion.GetCID(); + if (EpicPotionlist.rawin(charac_no)) { + odds = EpicPotionlist[charac_no]; + } + // 计算新的roll值 + args[2] = MathClass.getMin(args[2] + args[2] * odds, MaxRoll); + } + } + return args; +} +``` + + + +> 最后我们回到dp_s文件夹中,打开Main.nut 加载我们刚才编写的逻辑 如果你已经开启过数据库连接池则不需要初始化数据库连接池的代码 + +``` +sq_RunScript("MyProject/史诗药剂.nut"); +``` + +> 至此一个简单的史诗药剂的逻辑就写完了 \ No newline at end of file diff --git a/_sidebar.md b/_sidebar.md index 5d6c322..472d11c 100644 --- a/_sidebar.md +++ b/_sidebar.md @@ -20,6 +20,7 @@ - [反外挂](Start/Example/14.md) - [装备和时装镶嵌](Start/Example/15.md) - [仓库材料一键入库](Start/Example/16.md) + - [史诗药剂](Start/Example/17.md) * [API文档](/) - [对象类](/) - [User 类](Object/User/User.md) diff --git a/desktop.ini b/desktop.ini new file mode 100644 index 0000000..60a9b2e --- /dev/null +++ b/desktop.ini @@ -0,0 +1,2 @@ +[.ShellClassInfo] +LocalizedResourceName=@docs,0