/* 文件名:EquimentUseJewel.nut 路径:Dps_A/ProjectClass/EquimentUseJewel/EquimentUseJewel.nut 创建日期:2024-10-28 21:18 文件用途:装备镶嵌 */ class EquimentUseJewel { ExecUser = null; //建库建表 function CreateMysqlTable() { local CreateSql1 = "create database if not exists l_equ_jewel default charset utf8;" local CreateSql2 = "CREATE TABLE l_equ_jewel.equipment ( equ_id int(11) AUTO_INCREMENT, jewel_data blob NOT NULL,andonglishanbai_flag int(11),date VARCHAR(255), PRIMARY KEY (equ_id)) ENGINE=InnoDB DEFAULT CHARSET=utf8,AUTO_INCREMENT = 150;" local SqlObj = MysqlPool.GetInstance().GetConnect(); SqlObj.Exec_Sql(CreateSql1); SqlObj.Exec_Sql(CreateSql2); MysqlPool.GetInstance().PutConnect(SqlObj); } function api_get_jewel_socket_data(id) { //获取徽章数据,存在返回徽章数据,不存在返回空字节数据 local CheckSql = "SELECT jewel_data FROM l_equ_jewel.equipment where equ_id = " + id + ";"; //从池子拿连接 local SqlObj = MysqlPool.GetInstance().GetConnect(); local Ret = SqlObj.Select(CheckSql, ["binary"]); //把连接还池子 MysqlPool.GetInstance().PutConnect(SqlObj); //没结婚要返回false if (Ret.len()< 1 || Ret[0][0] == null) { return 0; } else { return Ret[0][0]; } } function api_exitjeweldata(id) { //0代表不存在,存在返回1 local CheckSql = "SELECT andonglishanbai_flag FROM l_equ_jewel.equipment where equ_id = " + id + ";"; //从池子拿连接 local SqlObj = MysqlPool.GetInstance().GetConnect(); local Ret = SqlObj.Select(CheckSql, ["int"]); //把连接还池子 MysqlPool.GetInstance().PutConnect(SqlObj); //没结婚要返回false if (Ret.len()< 1 || Ret[0][0] == null) { return 0; } else { return Ret[0][0]; } } function save_equiment_socket(socket_data, id) { //0代表不存在,存在返回1 local CheckSql = "UPDATE l_equ_jewel.equipment SET jewel_data = 0x" + socket_data + " WHERE equ_id = " + id + ";"; //从池子拿连接 local SqlObj = MysqlPool.GetInstance().GetConnect(); local Ret = SqlObj.Select(CheckSql, ["int"]); //把连接还池子 MysqlPool.GetInstance().PutConnect(SqlObj); //没结婚要返回false if (Ret.len()< 1 || Ret[0][0] == null) { return false; } else { return true; } } function CUser_SendCmdErrorPacket(SUser, id, id2) { local Pack = Packet(); Pack.Put_Header(1, id); Pack.Put_Byte(0); Pack.Put_Byte(id2); Pack.Finalize(true); SUser.Send(Pack); Pack.Delete(); } function api_PacketBuf_get_buf(packet_buf) { return NativePointer(NativePointer(packet_buf).add(20).readPointer()).add(13); } function add_equiment_socket(equipment_type) { //0代表开孔失败 成功返回标识 /* 武器10 称号11 上衣12 头肩13 下衣14 鞋子15 腰带16 项链17 手镯18 戒指19 辅助装备20 魔法石21 */ /* 红色:'010000000000010000000000000000000000000000000000000000000000' A 黄色:'020000000000020000000000000000000000000000000000000000000000' B 绿色:'040000000000040000000000000000000000000000000000000000000000' C 蓝色:'080000000000080000000000000000000000000000000000000000000000' D 白金:'100000000000100000000000000000000000000000000000000000000000' */ local DB_JewelsocketData = ""; switch (equipment_type) { case 10: //武器10 SS DB_JewelsocketData = "100000000000000000000000000000000000000000000000000000000000" break; case 11: //称号11 SS DB_JewelsocketData = "100000000000000000000000000000000000000000000000000000000000" break; case 12: //上衣12 C DB_JewelsocketData = "040000000000040000000000000000000000000000000000000000000000" break; case 13: //头肩13 B DB_JewelsocketData = "020000000000020000000000000000000000000000000000000000000000" break; case 14: //下衣14 C DB_JewelsocketData = "040000000000040000000000000000000000000000000000000000000000" break; case 15: //鞋子15 D DB_JewelsocketData = "080000000000080000000000000000000000000000000000000000000000" break; case 16: //腰带16 A DB_JewelsocketData = "010000000000010000000000000000000000000000000000000000000000" break; case 17: //项链17 B DB_JewelsocketData = "020000000000020000000000000000000000000000000000000000000000" break; case 18: //手镯18 D DB_JewelsocketData = "080000000000080000000000000000000000000000000000000000000000" break; case 19: //戒指19 A DB_JewelsocketData = "010000000000010000000000000000000000000000000000000000000000" break; case 20: //辅助装备20 S DB_JewelsocketData = "100000000000000000000000000000000000000000000000000000000000" break; case 21: //魔法石21 S DB_JewelsocketData = "100000000000000000000000000000000000000000000000000000000000" break; default: DB_JewelsocketData = "000000000000000000000000000000000000000000000000000000000000" break; } local date = time(); local Ct = Sq_GetTimestampString(); date = date.tostring() + Ct; local CheckSql = "INSERT INTO l_equ_jewel.equipment (andonglishanbai_flag,jewel_data,date) VALUES(1,0x" + DB_JewelsocketData + ",\'" + date + "\');"; local CheckSql1 = "SELECT equ_id FROM l_equ_jewel.equipment where date = \'" + date + "\';"; //从池子拿连接 local SqlObj = MysqlPool.GetInstance().GetConnect(); SqlObj.Select(CheckSql, ["int"]); local Ret = SqlObj.Select(CheckSql1, ["int"]); //把连接还池子 MysqlPool.GetInstance().PutConnect(SqlObj); if (Ret.len()< 1 || Ret[0][0] == null) { return 0; } else { return Ret[0][0]; } return 0; } function CStackableItem_getJewelTargetSocket(C_Object) { return Sq_CallFunc(S_Ptr("0x0822CA28"), "int", ["pointer"], C_Object); } function CUser_SendUpdateItemList_DB(SUser, Slot, DB_JewelSocketData) { local Pack = Packet(); Pack.Put_Header(0, 14); Pack.Put_Byte(0); Pack.Put_Short(1); local InvenObj = SUser.GetInven(); Sq_CallFunc(S_Ptr("0x084FC6BC"), "int", ["pointer", "int", "int", "pointer"], InvenObj.C_Object, 1, Slot, Pack.C_Object); Pack.Put_BinaryEx(DB_JewelSocketData.C_Object, 30); Pack.Finalize(true); SUser.Send(Pack); Pack.Delete(); } function GetByte(value) { local Blob = blob(); Blob.writen(value, 'w'); return Blob; } function intToHex(num) { if (num == 0) { return "0"; } local hexDigits = "0123456789abcdef"; local hexString = ""; while (num > 0) { local remainder = num % 16; hexString = hexDigits[remainder] + hexString; num = (num / 16).tointeger(); } return hexString; } function lengthCutting(str, ystr, num, maxLength) { // 如果字符串长度小于最大长度,在前面补0 local lengthDiff = maxLength - str.len(); if (lengthDiff > 0) { local zeroPadding = ""; for (local i = 0; i< lengthDiff; i++) { zeroPadding += "0"; } str = zeroPadding + str; } local strArr = ""; for (local i = 0; i< str.len(); i += num) { local endIndex = i + num; if (endIndex > str.len()) { endIndex = str.len(); } strArr += str.slice(i, endIndex); } return ystr + strArr; } 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) { local JewelSocketData = api_get_jewel_socket_data(NativePointer(args[3]).add(25).readU32()); local ret = args.pop(); if (JewelSocketData && NativePointer(JewelSocketData).add(0).readU8() != 0) { local Pack = Packet(args[1]); Pack.Put_BinaryEx(JewelSocketData.C_Object, 30); } return null; }.bindenv(this); //设计图继承 Cb_CUsercopyItemOption_Enter_Func.EquimentUseJewel <- function(args) { local jewelSocketID = NativePointer(args[2]).add(25).readU32(); NativePointer(args[1]).add(25).writeU32(jewelSocketID); return null; }.bindenv(this); //装备开孔 Cb_AddSocketToAvatar_Enter_Func.EquimentUseJewel <- function(args) { local SUser = User(args[1]); 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(); local CurCharacInvenW = SUser.GetInven(); local inven_item = CurCharacInvenW.GetSlot(1, equ_slot); if (equ_slot > 56) { //修改后:大于56则是时装装备 原:如果不是装备文件就调用原逻辑 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)) { CUser_SendCmdErrorPacket(SUser, 209, 19); HackAddSocketToAvatarLogic(true); return null; } local item = PvfItem.GetPvfItemById(equitem_id); local ItemType = Sq_CallFunc(S_Ptr("0x08514D26"), "int", ["pointer"], item.C_Object); if (ItemType == 10) { SUser.SendNotiBox("装备为武器类型,不支持打孔!", 1) CUser_SendCmdErrorPacket(SUser, 209, 0); HackAddSocketToAvatarLogic(true); return null; } else if (ItemType == 11) { SUser.SendNotiBox("装备为称号类型,不支持打孔!", 1) CUser_SendCmdErrorPacket(SUser, 209, 0); HackAddSocketToAvatarLogic(true); return null; } local id = add_equiment_socket(ItemType); Sq_Inven_RemoveItemFormCount(CurCharacInvenW.C_Object, 1, sta_slot, 1, 8, 1); //删除打孔道具 NativePointer(inven_item.C_Object).add(25).writeU32(id) //写入槽位标识 SUser.SendUpdateItemList(1, 0, equ_slot); local JewelSocketData = api_get_jewel_socket_data(id); CUser_SendUpdateItemList_DB(SUser, equ_slot, JewelSocketData); //用于更新镶嵌后的装备显示,这里用的是带镶嵌数据的更新背包函数,并非CUser_SendUpdateItemList local Pack = Packet(); Pack.Put_Header(1, 209); Pack.Put_Byte(1); Pack.Put_Short(equ_slot + 104); Pack.Put_Short(sta_slot); Pack.Finalize(true); SUser.Send(Pack); Pack.Delete(); HackAddSocketToAvatarLogic(true); return null; }.bindenv(this); Cb_AddSocketToAvatar_Leave_Func.EquimentUseJewel <- function(args) { HackAddSocketToAvatarLogic(false); return null; }.bindenv(this); //装备镶嵌和时装镶嵌 Cb_Dispatcher_UseJewel_Enter_Func.EquimentUseJewel <- function(args) { local SUser = User(args[1]); local Pack = Packet(args[2]); local PackIndex = NativePointer(args[2]).add(4).readInt(); local State = SUser.GetState(); if (State != 3) return null; local avartar_inven_slot = Pack.GetShort(); local avartar_item_id = Pack.GetInt(); local emblem_cnt = Pack.GetByte(); //下面是参照原时装镶嵌的思路写的。个别点标记出来。 if (avartar_inven_slot > 104) { local equipment_inven_slot = avartar_inven_slot - 104; //取出真实装备所在背包位置值 local Inven = SUser.GetInven(); local equipment = Inven.GetSlot(1, equipment_inven_slot); //校验是否合法 if (!equipment || equipment.IsEmpty || (equipment.GetIndex() != avartar_item_id) || SUser.CheckItemLock(1, equipment_inven_slot)) return; local id = NativePointer(equipment.C_Object).add(25).readU32(); local JewelSocketData = api_get_jewel_socket_data(id); if (!JewelSocketData) return; local emblems = {}; if (emblem_cnt <= 3) { for (local i = 0; i< emblem_cnt; i++) { local emblem_inven_slot = Pack.GetShort(); local emblem_item_id = Pack.GetInt(); local equipment_socket_slot = Pack.GetByte(); local emblem = Inven.GetSlot(1, emblem_inven_slot); //校验徽章及插槽数据是否合法 if (!emblem || emblem.IsEmpty || (emblem.GetIndex() != emblem_item_id) || (equipment_socket_slot >= 3)) return; //校验徽章是否满足时装插槽颜色要求 //获取徽章pvf数据 local citem = PvfItem.GetPvfItemById(emblem_item_id); if (!citem) return; //校验徽章类型 if (!citem.IsStackable() || citem.GetItemType() != 20) return; //获取徽章支持的插槽 local emblem_socket_type = CStackableItem_getJewelTargetSocket(citem.C_Object); //获取要镶嵌的时装插槽类型 local avartar_socket_type = JewelSocketData.add(equipment_socket_slot * 6).readShort(); if (!(emblem_socket_type & avartar_socket_type)) { return; } emblems[equipment_socket_slot] <- [emblem_inven_slot, emblem_item_id]; } } foreach(equipment_socket_slot, emblemObject in emblems) { //删除徽章 local emblem_inven_slot = emblemObject[0]; Sq_Inven_RemoveItemFormCount(Inven.C_Object, 1, emblem_inven_slot, 1, 8, 1); //删除打孔道具 //设置时装插槽数据 local emblem_item_id = emblemObject[1]; JewelSocketData.add(2 + 6 * equipment_socket_slot).writeU32(emblem_item_id); } local Buf = Sq_Point2Blob(JewelSocketData.C_Object, 30); local Str = ""; foreach(Value in Buf) { Str += format("%02X", Value); } save_equiment_socket(Str, id); // if (!save_equiment_socket(DB_JewelSocketData, id)) { // print("写入失败了"); // return null; // } CUser_SendUpdateItemList_DB(SUser, equipment_inven_slot, JewelSocketData); //用于更新镶嵌后的装备显示,这里用的是带镶嵌数据的更新背包函数,并非CUser_SendUpdateItemList local Pack = Packet(); Pack.Put_Header(1, 209); Pack.Put_Byte(1); Pack.Put_Short(equipment_inven_slot + 104); Pack.Finalize(true); SUser.Send(Pack); Pack.Delete(); return; } AvatarLogic(args, PackIndex); return null; }.bindenv(this); Cb_Dispatcher_UseJewel_Leave_Func.EquimentUseJewel <- function(args) { return -1; }.bindenv(this); //额外数据包,发送装备镶嵌数据给本地处理 Cb_InterfacePacketBuf_put_packet_Leave_Func.EquimentUseJewel <- function(args) { local ret = args.pop(); local Inven_Item = NativePointer(args[1]); if (Inven_Item.add(1).readU8() == 1) { local ItemObj = Item(args[1]); local JewelSocketData = api_get_jewel_socket_data(NativePointer(ItemObj.C_Object).add(25).readU32()); if (JewelSocketData && JewelSocketData.add(0).readU8() != 0) { local Pack = Packet(args[0]); Pack.Put_BinaryEx(JewelSocketData.C_Object, 30); } } return null; }.bindenv(this); L_HookEquimentUseJewel(); } function WongWork_CAvatarItemMgr_getJewelSocketData(a, b) { return Sq_CallFunc(S_Ptr("0x82F98F8"), "pointer", ["pointer", "int"], a, b); } function CStackableItem_getJewelTargetSocket(C_Object) { return Sq_CallFunc(S_Ptr("0x0822CA28"), "int", ["pointer"], C_Object); } function CInventory_delete_item(C_Object, Type, Slot, Count, Ps, Log) { return Sq_CallFunc(S_Ptr("0x850400C"), "int", ["pointer", "int", "int", "int", "int", "int"], C_Object, Type, Slot, Count, Ps, Log); } function api_set_JewelSocketData(jewelSocketData, slot, emblem_item_id) { if (jewelSocketData) { NativePointer(jewelSocketData).add(slot * 6 + 2).writeInt(emblem_item_id); } } function DB_UpdateAvatarJewelSlot_makeRequest(a, b, c) { return Sq_CallFunc(S_Ptr("0x843081C"), "pointer", ["int", "int", "pointer"], a, b, c); } //获取时装在数据库中的uid function api_get_avartar_ui_id(avartar) { return NativePointer(avartar).add(7).readInt(); } function AvatarLogic(args, PackIndex) { //角色 local SUser = User(args[1]); //包数据 local Pack = Packet(args[2]); //还原包读取数据号位 NativePointer(args[2]).add(4).writeInt(PackIndex); //校验角色状态是否允许镶嵌 if (!SUser || SUser.GetState() != 3) { return; } //时装所在的背包槽 local Inven_Slot = Pack.GetShort(); //时装item_id local Item_Id = Pack.GetInt(); //本次镶嵌徽章数量 local Emblem_Count = Pack.GetByte(); //获取时装道具 local InvemObj = SUser.GetInven(); local AvatarObj = InvemObj.GetSlot(2, Inven_Slot); //校验时装 数据是否合法 if (!AvatarObj || AvatarObj.IsEmpty || (AvatarObj.GetIndex() != Item_Id) || SUser.CheckItemLock(2, Inven_Slot)) return; local Avartar_AddInfo = AvatarObj.GetAdd_Info(); //获取时装管理器 local Inven_AvartarMgr = InvemObj.GetAvatarItemMgr(); //获取时装插槽数据 local Jewel_Socket_Data = WongWork_CAvatarItemMgr_getJewelSocketData(Inven_AvartarMgr, Avartar_AddInfo); if (!Jewel_Socket_Data) return; //最多只支持3个插槽 if (Emblem_Count <= 3) { local emblems = {}; for (local i = 0; i< Emblem_Count; i++) { //徽章所在的背包槽 local emblem_inven_slot = Pack.GetShort(); //徽章item_id local emblem_item_id = Pack.GetInt(); //该徽章镶嵌的时装插槽id local avartar_socket_slot = Pack.GetByte(); //获取徽章道具 local EmblemObje = InvemObj.GetSlot(1, emblem_inven_slot); //校验徽章及插槽数据是否合法 if (!EmblemObje || EmblemObje.IsEmpty || (EmblemObje.GetIndex() != emblem_item_id) || (avartar_socket_slot >= 3)) return; //校验徽章是否满足时装插槽颜色要求 //获取徽章pvf数据 local citem = PvfItem.GetPvfItemById(emblem_item_id); if (!citem) return; //校验徽章类型 if (!citem.IsStackable() || citem.GetItemType() != 20) return; //获取徽章支持的插槽 local emblem_socket_type = CStackableItem_getJewelTargetSocket(citem.C_Object); //获取要镶嵌的时装插槽类型 local avartar_socket_type = NativePointer(Jewel_Socket_Data).add(avartar_socket_slot * 6).readShort(); if (!(emblem_socket_type & avartar_socket_type)) return; emblems[avartar_socket_slot] <- [emblem_inven_slot, emblem_item_id]; } //开始镶嵌 foreach(avartar_socket_slot, emblemObject in emblems) { //删除徽章 local emblem_inven_slot = emblemObject[0]; CInventory_delete_item(InvemObj.C_Object, 1, emblem_inven_slot, 1, 8, 1); //设置时装插槽数据 local emblem_item_id = emblemObject[1]; api_set_JewelSocketData(Jewel_Socket_Data, avartar_socket_slot, emblem_item_id); } //时装插槽数据存档 DB_UpdateAvatarJewelSlot_makeRequest(SUser.GetCID(), api_get_avartar_ui_id(AvatarObj.C_Object), Jewel_Socket_Data); //通知客户端时装数据已更新 SUser.SendUpdateItemList(1, 1, Inven_Slot); //回包给客户端 local Pack = Packet(); Pack.Put_Header(1, 204); Pack.Put_Int(1); Pack.Finalize(true); SUser.Send(Pack); Pack.Delete(); } return null; } constructor() { CreateMysqlTable(); FixFunction(); } }