找回密码
 register

QQ登录

只需一步,快速开始

查看: 1389|回复: 0

[系统函数] YuanBao 发放、扣除、查询元宝

[复制链接]

[系统函数] YuanBao 发放、扣除、查询元宝

[复制链接]
  • 打卡等级:热心大叔
  • 打卡总天数:94
  • 打卡月天数:17
  • 打卡总奖励:94
  • 最近打卡:2025-01-18 01:28:20
Waylee

主题

0

回帖

1万

积分

仙帝

积分
11929
Waylee 2020-8-21 21:59 | 显示全部楼层 |阅读模式

马上注册,查看网站隐藏内容!!

您需要 登录 才可以下载或查看,没有账号?register

×

***付费内容***

IDA伪代码(085原版)

// 函数: LuaFnYuanBao
// 描述: Lua绑定函数,用于操作元宝(游戏内货币)
// 参数: 
//   lua_State *L - 包含函数参数的Lua状态
int __cdecl LuaFnTbl::LuaFnYuanBao(lua_State *L)
{
  // 变量声明
  int i; // 循环索引,用于参数验证
  unsigned int v2; // selfId(玩家ID)
  int v3; // targetId(目标玩家ID)
  int v4; // optType(操作类型:添加、减少、获取)
  SceneManager_1 *const v5; // 场景管理器实例
  Scene_3 *Scene; // 当前场景
  Obj *v7; // 对应selfId的对象
  int v9; // 临时变量,用于元宝数量
  int v10; // 临时变量,用于元宝数量
  int v11; // 减少后新的元宝数量
  int YuanBao; // 当前元宝数量
  int v13; // 添加后的新元宝数量
  Packet *v14; // 网络通信的包
  IODataStream *v15; // 包的数据流
  GUID_t v16; // 对象的GUID
  bool v17; // 检查数据流操作的标志
  int n; // 临时循环变量
  INT v19; // 数据流的临时变量
  int ii; // 临时循环变量
  INT v21; // 数据流的临时变量
  int jj; // 临时循环变量
  INT v23; // 数据流的临时变量
  Packet *Packet; // 网络通信的包
  IODataStream *v25; // 包的数据流
  GUID_t v26; // 对象的GUID
  int j; // 临时循环变量
  INT m_CurNum; // 数据流中的当前编号
  int k; // 临时循环变量
  INT v30; // 数据流的临时变量
  int m; // 临时循环变量
  INT v32; // 数据流的临时变量
  const CHAR *v33; // 错误字段名称
  const CHAR *v34; // 错误信息
  double v35; // 返回值
  GUID_t v36; // 日志记录用的GUID
  GUID_t v37; // 日志记录用的GUID
  GUID_t GUID; // 日志记录用的GUID
  GUID_t v39; // 日志记录用的GUID
  GUID_t v40; // 日志记录用的GUID
  GUID_t v41; // 日志记录用的GUID
  GUID_t v42; // 日志记录用的GUID
  GUID_t v43; // 日志记录用的GUID
  GUID_t v44; // 日志记录用的GUID
  unsigned int v45; // 操作后的元宝数量
  unsigned int v46; // 操作后的元宝数量
  unsigned int v47; // 操作后的元宝数量
  Packets::GWYuanBao *pMsgYuanBao_0; // 元宝操作的包消息(减少)
  Packets::GWYuanBao *pMsgYuanBao; // 元宝操作的包消息(添加)
  Obj_Human *v50; // 人类对象
  unsigned int Param; // 操作的参数(金额)
  SceneID_t sceneId; // Lua参数中的场景ID
  __int16 v53; // 数据流的临时变量
  unsigned int v54; // 数据流的参数值
  _DWORD v55[2]; // GUID的临时存储
  MONEY_OP_TYPE nOpType; // 操作类型枚举(用于减少)
  GUID_t gTargetGuid; // 操作的目标GUID
  unsigned int v58; // 数据流的参数值
  _DWORD v59[2]; // GUID的临时存储
  MONEY_OP_TYPE v60; // 操作类型枚举(用于添加)
  GUID_t v61; // 操作的目标GUID
  char s[1048]; // 错误信息的缓冲区

  // 验证前5个Lua参数是否为数字
  for (i = 1; i <= 5; ++i)
  {
    if (L)
    {
      if (lua_isnumber((lua_State_0 *)L, i) == 1)
        continue; // 如果参数是数字,继续下一个参数
      // 如果参数不是数字,准备错误信息
      snprintf(s, 0x200u, "ERROR: [%s]Param %d is illegal!", "LuaFnYuanBao", i);
    }
    else
    {
      // 如果Lua状态为空,准备错误信息
      snprintf(s, 0x200u, "ERROR: [%s] Lua_State==NULL!", "LuaFnYuanBao");
    }
    // 以级别3记录错误信息
    CacheLog(3, s);
  }

  // 获取Lua参数
  sceneId = (__int16)lua_tonumber((lua_State_0 *)L, 1); // 第一个参数:场景ID
  v2 = (int)lua_tonumber((lua_State_0 *)L, 2); // 第二个参数:self ID(玩家ID)
  v3 = (int)lua_tonumber((lua_State_0 *)L, 3); // 第三个参数:目标ID
  v4 = (int)lua_tonumber((lua_State_0 *)L, 4); // 第四个参数:操作类型
  Param = (int)lua_tonumber((lua_State_0 *)L, 5); // 第五个参数:参数(金额)

  // 记录函数调用开始的信息
  CacheLog(1, "LuaFnYuanBao:: begin sceneId=%d selfId=%d targetId=%d opttype=%d Param=%d", sceneId, v2, v3, v4, Param);

  // 从场景管理器获取当前场景
  Scene = SceneManager::GetScene(v5, g_pSceneManager);
  if (!Scene)
  {
    // 如果场景不存在,准备错误信息并断言
    v34 = "Scene ID ErrorLuaFnYuanBao";
    v33 = "pScene";
LABEL_16:
    __assertex__("./Script/LuaFnTbl_Shop.h", 0x25Fu, "int LuaFnTbl::LuaFnYuanBao(lua_State*)", v33, v34);
  }

  // 检查当前线程ID是否与场景的线程ID匹配,确保线程安全
  if (ThreadValueManager::GetCurrentThreadID() != Scene->m_ThreadID)
    __assertex__(
      "./Script/LuaFnTbl_Shop.h",
      0x25Fu,
      "int LuaFnTbl::LuaFnYuanBao(lua_State*)",
      "ThreadValueManager::GetCurrentThreadID()==pScene->m_ThreadID",
      "ThreadValueManager::GetCurrentThreadID()==pScene->m_ThreadIDLuaFnYuanBao");

  // 验证selfId是否在有效范围内,并获取对应的对象
  if (v2 > 0x752F || (v7 = Scene->m_pObjManager->m_pObj[v2], (v50 = (Obj_Human *)v7) == 0))
  {
    // 如果selfId无效或对象不存在,准备错误信息并断言
    v34 = "selfId ErrorLuaFnYuanBao";
    v33 = "pObj";
    goto LABEL_16;
  }

  // 检查对象是否为人类类型(可能是通过虚函数表的第二个函数)
  if ((*((int (__cdecl **)(Obj *))v7->_vptr_Obj + 2))(v7) != 1)
    goto LABEL_12; // 如果不是,跳转到默认情况

  // 检查人类对象是否可以进行逻辑操作
  if (!Obj_Human::IsCanLogic((Obj_Human *const)v7))
    __assertex__(
      "./Script/LuaFnTbl_Shop.h",
      0x25Fu,
      "int LuaFnTbl::LuaFnYuanBao(lua_State*)",
      "pHuman->IsCanLogic()",
      "IsCanLogic() test return falseLuaFnYuanBao");

  // 验证操作类型是否有效:1(添加)、2(减少)、3(获取)
  if ((unsigned int)(v4 - 1) > 2)
  {
    // 如果操作类型无效,记录错误日志
    GUID = Obj_Human::GetGUID((const Obj_Human *const)v7);
    CacheLog(1, "LuaFnYuanBao::ObjGUID=%X Invalid opttype=%d", GUID, v4);
    goto LABEL_25; // 准备返回错误
  }

  // 根据操作类型执行相应操作
  switch (v4)
  {
    case 1: // 添加元宝
      if (Param <= 0xBEBC200) // 检查添加金额是否在允许范围内
      {
        YuanBao = Obj_Human::GetYuanBao((Obj_Human *const)v7); // 获取当前元宝数量
        v13 = Param + YuanBao; // 计算添加后的新元宝数量
        if (Param + YuanBao > 0xBEBC200) // 检查新元宝数量是否超过最大限制
        {
          v47 = Param + YuanBao;
          v44 = Obj_Human::GetGUID((const Obj_Human *const)v7);
          // 记录超出范围的添加尝试
          CacheLog(
            1,
            "LuaFnYuanBao::ObjGUID=%X OPT_YUANBAO_ADD OUTRANGE(0, yuanbaoamount, MAX_YUANBAO) yuanbaoamount=%d",
            v44,
            v47);
          goto LABEL_25; // 准备返回错误
        }

        // 检查对象位置数据中的某个标志(可能用于防止重复更新)
        if ((BYTE1(v7[1518].m_Pos.m_fZ) & 8) != 0)
        {
          v40 = Obj_Human::GetGUID((const Obj_Human *const)v7);
          // 记录已经在进行更新的日志
          CacheLog(1, "LuaFnYuanBao::ObjGUID=%X OPT_YUANBAO_ADD BLT_YUANBAO_OPT yuanbaoamount=%d", v40, v13);
          goto LABEL_25; // 准备返回错误
        }

        // 执行添加操作
        Obj_Human::GetYuanBao((Obj_Human *const)v7); // (冗余?可能有副作用)
        v61 = -1;
        v60 = MONEY_OP_TYPE::YUANBAO_SCRIPT_ADD; // 定义操作类型为添加
        Obj_Human::SetYuanBao((Obj_Human *const)v7, v13, &v60, 0, &v61, 0); // 更新元宝数量
        LODWORD(v7[1518].m_Pos.m_fZ) |= 0x800u; // 在对象位置数据中设置标志(表示更新)

        // 创建一个网络包以通知客户端
        Packet = PacketFactoryManager::CreatePacket(g_pPacketFactoryManager, 0x17Eu); // 创建GWYuanBao包
        v25 = (IODataStream *)&Packet[1]; // 从包中获取数据流
        pMsgYuanBao = (Packets::GWYuanBao *)Packet; // 转换为特定包类型
        IODataStream::Begin((IODataStream *const)&Packet[1], IODataStream::OPT_TYPE::OPT_WRITE); // 开始写入数据流

        v26 = Obj_Human::GetGUID((const Obj_Human *const)v7); // 获取对象的GUID
        v17 = v25->m_Opt == 1; // 检查数据流是否处于写入模式
        v59[1] = v26; // 存储GUID
        if (!v17)
          __assertex__(
            "../../Common/DataStream.h",
            0x1B0u,
            "IODataStream& IODataStream::operator<<(T) [with T = unsigned int]",
            "0",
            "m_Opt != IODataStream::OPT_WRITE");

        // 如果数据流有空间,写入GUID
        if (v25->m_CurNum <= 0x13u)
        {
          for (j = 4; j > 0; --j)
            (*((void (__cdecl **)(IODataStream *, _DWORD))v25->_vptr_InputStream + 3))(
              v25,
              *((unsigned __int8 *)v59 + j + 3));
          // 设置数据类型和长度
          m_CurNum = v25->m_CurNum;
          v25->m_DataT[m_CurNum] = 3;
          v25->m_DataL[m_CurNum] = 4;
          v25->m_CurNum = m_CurNum + 1;
        }

        v17 = v25->m_Opt == 1; // 检查写入模式
        v59[0] = 1; // 操作类型标识符
        if (!v17)
          __assertex__(
            "../../Common/DataStream.h",
            0x1B0u,
            "IODataStream& IODataStream::operator<<(T) [with T = int]",
            "0",
            "m_Opt != IODataStream::OPT_WRITE");

        // 写入操作类型到数据流
        if (v25->m_CurNum <= 0x13u)
        {
          for (k = 4; k > 0; --k)
            (*((void (__cdecl **)(IODataStream *, _DWORD))v25->_vptr_InputStream + 3))(
              v25,
              *((unsigned __int8 *)&v58 + k + 3));
          // 设置数据类型和长度
          v30 = v25->m_CurNum;
          v25->m_DataT[v30] = 2;
          v25->m_DataL[v30] = 4;
          v25->m_CurNum = v30 + 1;
        }

        v17 = v25->m_Opt == 1; // 检查写入模式
        v58 = Param; // 存储参数值
        if (!v17)
          __assertex__(
            "../../Common/DataStream.h",
            0x1B0u,
            "IODataStream& IODataStream::operator<<(T) [with T = unsigned int]",
            "0",
            "m_Opt != IODataStream::OPT_WRITE");

        // 写入参数到数据流
        if (v25->m_CurNum <= 0x13u)
        {
          for (m = 4; m > 0; --m)
            (*((void (__cdecl **)(IODataStream *, _DWORD))v25->_vptr_InputStream + 3))(
              v25,
              *((unsigned __int8 *)&gTargetGuid + m + 3));
          // 设置数据类型和长度
          v32 = v25->m_CurNum;
          v25->m_DataT[v32] = 3;
          v25->m_DataL[v32] = 4;
          v25->m_CurNum = v32 + 1;
        }

        // 完成数据流写入
        IODataStream::End(v25, IODataStream::OPT_TYPE::OPT_WRITE);
        // 发送包到所有客户端
        ServerManager::SendPacket(*(ServerManager *const *)&g_pServerManager, pMsgYuanBao, -1, 0);
        // 记录成功添加的日志
        v43 = Obj_Human::GetGUID(v50);
        CacheLog(1, "LuaFnYuanBao::ObjGUID=%X OPT_YUANBAO_ADD success yuanbaoamount=%d", v43);
        goto LABEL_76; // 准备返回成功
      }
      // 如果参数超过最大允许值
      v37 = Obj_Human::GetGUID((const Obj_Human *const)v7);
      CacheLog(1, "LuaFnYuanBao::ObjGUID=%X OPT_YUANBAO_ADD OUTRANGE(0, Param, MAX_YUANBAO) Param=%d", v37, Param);
LABEL_25:
      HIDWORD(v35) = -1074790400; // 设置返回值的高位,表示错误
LABEL_26:
      LODWORD(v35) = 0; // 设置返回值的低位为0
      lua_pushnumber((lua_State_0 *)L, v35); // 将返回值推入Lua栈
      return 1; // 返回1个值给Lua
    case 2: // 减少元宝
      if (Param > 0xBEBC200) // 检查减少金额是否在允许范围内
      {
        v36 = Obj_Human::GetGUID((const Obj_Human *const)v7);
        // 记录超出范围的减少尝试
        CacheLog(1, "LuaFnYuanBao::ObjGUID=%X OPT_YUANBAO_SUB OUTRANGE(0, Param, MAX_YUANBAO) Param=%d", v36, Param);
        goto LABEL_25; // 准备返回错误
      }
      v10 = Obj_Human::GetYuanBao((Obj_Human *const)v7); // 获取当前元宝数量
      v11 = v10 - Param; // 计算减少后的新元宝数量
      if (v10 - Param > 0xBEBC200) // 检查减少后的元宝数量是否超过最大限制(减少操作通常不会超过)
      {
        v46 = v10 - Param;
        v42 = Obj_Human::GetGUID((const Obj_Human *const)v7);
        // 记录超出范围的减少结果
        CacheLog(
          1,
          "LuaFnYuanBao::ObjGUID=%X OPT_YUANBAO_SUB OUTRANGE(0, yuanbaoamount, MAX_YUANBAO) yuanbaoamount=%d",
          v42,
          v46);
        goto LABEL_25; // 准备返回错误
      }
      // 检查对象位置数据中的某个标志(可能用于防止重复更新)
      if ((BYTE1(v7[1518].m_Pos.m_fZ) & 8) != 0)
      {
        v45 = v10 - Param;
        v39 = Obj_Human::GetGUID((const Obj_Human *const)v7);
        // 记录已经在进行更新的日志
        CacheLog(1, "LuaFnYuanBao::ObjGUID=%X OPT_YUANBAO_SUB BLT_YUANBAO_OPT yuanbaoamount=%d", v39, v45);
        goto LABEL_25; // 准备返回错误
      }

      // 执行减少操作
      Obj_Human::GetYuanBao((Obj_Human *const)v7); // (冗余?可能有副作用)
      gTargetGuid = -1;
      nOpType = MONEY_OP_TYPE::YUANBAO_SCRIPT_COST; // 定义操作类型为减少
      Obj_Human::SetYuanBao((Obj_Human *const)v7, v11, &nOpType, 0, &gTargetGuid, 0); // 更新元宝数量
      LODWORD(v7[1518].m_Pos.m_fZ) |= 0x800u; // 在对象位置数据中设置标志(表示更新)

      // 创建一个网络包以通知客户端
      v14 = PacketFactoryManager::CreatePacket(g_pPacketFactoryManager, 0x17Eu); // 创建GWYuanBao包
      v15 = (IODataStream *)&v14[1]; // 从包中获取数据流
      pMsgYuanBao_0 = (Packets::GWYuanBao *)v14; // 转换为特定包类型
      IODataStream::Begin((IODataStream *const)&v14[1], IODataStream::OPT_TYPE::OPT_WRITE); // 开始写入数据流

      v16 = Obj_Human::GetGUID((const Obj_Human *const)v7); // 获取对象的GUID
      v17 = v15->m_Opt == 1; // 检查数据流是否处于写入模式
      v55[1] = v16; // 存储GUID
      if (!v17)
        __assertex__(
          "../../Common/DataStream.h",
          0x1B0u,
          "IODataStream& IODataStream::operator<<(T) [with T = unsigned int]",
          "0",
          "m_Opt != IODataStream::OPT_WRITE");

      // 如果数据流有空间,写入GUID
      if (v15->m_CurNum <= 0x13u)
      {
        for (n = 4; n > 0; --n)
          (*((void (__cdecl **)(IODataStream *, _DWORD))v15->_vptr_InputStream + 3))(
            v15,
            *((unsigned __int8 *)v55 + n + 3));
        // 设置数据类型和长度
        v19 = v15->m_CurNum;
        v15->m_DataT[v19] = 3;
        v15->m_DataL[v19] = 4;
        v15->m_CurNum = v19 + 1;
      }

      v17 = v15->m_Opt == 1; // 检查写入模式
      v55[0] = -1; // 操作类型标识符为减少
      if (!v17)
        __assertex__(
          "../../Common/DataStream.h",
          0x1B0u,
          "IODataStream& IODataStream::operator<<(T) [with T = int]",
          "0",
          "m_Opt != IODataStream::OPT_WRITE");

      // 写入操作类型到数据流
      if (v15->m_CurNum <= 0x13u)
      {
        for (ii = 4; ii > 0; --ii)
          (*((void (__cdecl **)(IODataStream *, _DWORD))v15->_vptr_InputStream + 3))(
            v15,
            *((unsigned __int8 *)&v54 + ii + 3));
        // 设置数据类型和长度
        v21 = v15->m_CurNum;
        v15->m_DataT[v21] = 2;
        v15->m_DataL[v21] = 4;
        v15->m_CurNum = v21 + 1;
      }

      v17 = v15->m_Opt == 1; // 检查写入模式
      v54 = Param; // 存储参数值
      if (!v17)
        __assertex__(
          "../../Common/DataStream.h",
          0x1B0u,
          "IODataStream& IODataStream::operator<<(T) [with T = unsigned int]",
          "0",
          "m_Opt != IODataStream::OPT_WRITE");

      // 写入参数到数据流
      if (v15->m_CurNum <= 0x13u)
      {
        for (jj = 4; jj > 0; --jj)
          (*((void (__cdecl **)(IODataStream *, _DWORD))v15->_vptr_InputStream + 3))(
            v15,
            *((unsigned __int8 *)&v53 + jj + 1));
        // 设置数据类型和长度
        v23 = v15->m_CurNum;
        v15->m_DataT[v23] = 3;
        v15->m_DataL[v23] = 4;
        v15->m_CurNum = v23 + 1;
      }

      // 完成数据流写入
      IODataStream::End(v15, IODataStream::OPT_TYPE::OPT_WRITE);
      // 发送包到所有客户端
      ServerManager::SendPacket(*(ServerManager *const *)&g_pServerManager, pMsgYuanBao_0, -1, 0);
      // 记录成功减少的日志
      v41 = Obj_Human::GetGUID(v50);
      CacheLog(1, "LuaFnYuanBao::ObjGUID=%X OPT_YUANBAO_SUB success yuanbaoamount=%d", v41);
LABEL_76:
      HIDWORD(v35) = 0; // 设置返回值的高位,表示成功
      goto LABEL_26; // 准备返回成功
    case 3: // 获取元宝
      v9 = Obj_Human::GetYuanBao((Obj_Human *const)v7); // 获取当前元宝数量
      if ((unsigned int)v9 > 0xBEBC200) // 检查元宝数量是否超过最大值
        goto LABEL_25; // 准备返回错误
      lua_pushnumber((lua_State_0 *)L, (double)v9); // 将元宝数量推入Lua栈
      break;
    default:
LABEL_12:
      lua_pushnumber((lua_State_0 *)L, -1.0); // 推入-1.0,表示失败
      break;
  }
  return 1; // 返回1个值给Lua
}
付费看帖
剩余 6% 内容需要支付 10.00 金币 后可完整阅读
支持付费阅读,激励作者创作更好的作品。
您需要登录后才可以回帖 登录 | register

本版积分规则

雪舞知识库 | 浙ICP备15015590号-1 | 萌ICP备20232229号|浙公网安备33048102000118号 |天天打卡

GMT+8, 2025-1-18 15:59 , Processed in 0.104876 second(s), 9 queries , Redis On.

Powered by XueWu Licensed

Copyright © Tencent Cloud.

快速回复 返回顶部 返回列表