
#include "CConnectPool.h"
#include "controller.h"
#include "import.h"
#include "l_socket.h"
#include "l_squirrel.h"

extern HSQUIRRELVM v;
extern std::recursive_mutex SqMtx;
#define MY_VERSION ("BuildTime： " __DATE__ " " __TIME__)

int n_sleep_time = 10000;
int bGMMode = 0, bFairPVP = 0, bPickupRout = 0;

SUBHOOK_INIT(doDispatch, 0x08594922);
SUBHOOK_INIT(Inter_LoadGeolocation_dispatch_sig, 0x0816088A);
SUBHOOK_INIT(History_Log, 0x854F990);
SUBHOOK_INIT(Neof_startupGlobalInstances, 0x0829F7C5);
SUBHOOK_INIT(TimerQueue_GetTimerMess, 0x08630ECC);

int checkGame(const char *pName) {
  char path[256];
  char *path_end;

  memset(path, 0, sizeof(path));
  if (readlink("/proc/self/exe", path, sizeof(path)) <= 0)
    return -1;
  path_end = strrchr(path, '/');
  if (!path_end || strlen(path_end) < 9)
    return -1;
  return strcmp(pName, ++path_end);
}

int my_select(int __nfds, fd_set *__restrict __readfds,
              fd_set *__restrict __writefds, fd_set *__restrict __exceptfds,
              struct timeval *__restrict __timeout) {
  if (!__nfds && !__readfds && !__writefds && !__exceptfds) {
    if (!__timeout->tv_sec && __timeout->tv_usec >= 0 &&
        __timeout->tv_usec <= 1000) {
      __timeout->tv_usec = n_sleep_time;
    }
  }
  return select(__nfds, __readfds, __writefds, __exceptfds, __timeout);
}

int my_usleep(__useconds_t __useconds) {
  if (__useconds >= 0 && __useconds <= 1000) {
    __useconds = n_sleep_time;
  }
  return usleep(__useconds);
}

int _doDispatch(PacketDispatcher *a1, CUser *user, int packet_class,
                int packet_id, char *packet_src, int packet_len, int a7,
                int a8) // 收包处理
{
  if (!user)
    return 0;
  if (packet_len <= 4)
    return 0;
  // 区域移动
  if (packet_id == 38) {
    std::lock_guard<std::recursive_mutex> lock(SqMtx);
    SQBool R;
    // 执行虚拟机Main函数
    SQInteger top = sq_gettop(v); // saves the stack size before the call
    sq_pushroottable(v);          // pushes the global table
    sq_pushstring(v, _SC("Cb_move_area"), -1);
    if (SQ_SUCCEEDED(
            sq_get(v, -2))) { // gets the fie123oo' from the global table
      sq_pushroottable(v); // push the 'this' (in this case is the global table)
      sq_pushuserpointer(v, user);
      sq_pushinteger(v, int(*(unsigned char *)(packet_src + 0x0D)));
      sq_pushinteger(v, int(*(unsigned char *)(packet_src + 0x0E)));
      sq_call(v, 4, SQTrue, SQTrue); // calls the function
      sq_getbool(v, -1, &R);
    }
    sq_settop(v, top); // restores the original stack size
    if (!R)
      return 0;
  }
  // GM输入
  else if (packet_id == 179) {
    // std::cout << "传入的: " << std::hex << (int)user << std::endl;
    std::string str =
        Utils::PackToHexString((const unsigned char *)packet_src, 13);
    str = str.substr(2);
    std::lock_guard<std::recursive_mutex> lock(SqMtx);
    // 执行虚拟机Main函数
    SQInteger top = sq_gettop(v); // saves the stack size before the call
    sq_pushroottable(v);          // pushes the global table
    sq_pushstring(v, _SC("Cb_gm_input"), -1);
    if (SQ_SUCCEEDED(
            sq_get(v, -2))) { // gets the fie123oo' from the global table
      sq_pushroottable(v); // push the 'this' (in this case is the global table)
      sq_pushuserpointer(v, user);
      sq_pushstring(v, _SC(str.c_str()), -1);
      sq_call(v, 3, SQFalse, SQTrue); // calls the function
    }
    sq_settop(v, top); // restores the original stack size
  }
  // 特殊道具使用
  else if (packet_id == 255) {
    std::lock_guard<std::recursive_mutex> lock(SqMtx);
    SQBool R = true;
    // 执行虚拟机Main函数
    SQInteger top = sq_gettop(v); // saves the stack size before the call
    sq_pushroottable(v);          // pushes the global table
    sq_pushstring(v, _SC("Cb_use_item_sp"), -1);
    if (SQ_SUCCEEDED(
            sq_get(v, -2))) { // gets the fie123oo' from the global table
      sq_pushroottable(v); // push the 'this' (in this case is the global table)
      sq_pushuserpointer(v, user);
      sq_pushinteger(v, int(*(int *)(packet_src + 0x0D)));
      sq_call(v, 3, SQTrue, SQTrue); // calls the function
      sq_getbool(v, -1, &R);
    }
    sq_settop(v, top); // restores the original stack size
    if (!R)
      return 0;
  }
  // 返回选择角色
  else if (packet_id == 7) {
    std::lock_guard<std::recursive_mutex> lock(SqMtx);
    // 执行虚拟机Main函数
    SQInteger top = sq_gettop(v); // saves the stack size before the call
    sq_pushroottable(v);          // pushes the global table
    sq_pushstring(v, _SC("Cb_return_select_character"), -1);
    if (SQ_SUCCEEDED(
            sq_get(v, -2))) { // gets the fie123oo' from the global table
      sq_pushroottable(v); // push the 'this' (in this case is the global table)
      sq_pushuserpointer(v, user);
      sq_call(v, 2, SQFalse, SQTrue); // calls the function
    }
    sq_settop(v, top); // restores the original stack size
  }
  // 更换装备
  else if (packet_id == 19) {
    int Ret = doDispatch(a1, user, packet_class, packet_id, packet_src,
                         packet_len, a7, a8);
    std::lock_guard<std::recursive_mutex> lock(SqMtx);
    // 执行虚拟机Main函数
    SQInteger top = sq_gettop(v); // saves the stack size before the call
    sq_pushroottable(v);          // pushes the global table
    sq_pushstring(v, _SC("Cb_player_chanage_equ"), -1);
    if (SQ_SUCCEEDED(
            sq_get(v, -2))) { // gets the fie123oo' from the global table
      sq_pushroottable(v); // push the 'this' (in this case is the global table)
      sq_pushuserpointer(v, user);
      sq_call(v, 2, SQFalse, SQTrue); // calls the function
    }
    sq_settop(v, top); // restores the original stack size

    return Ret;
  }
  // 组队  创建和加入
  else if (packet_id == 10) {
    std::lock_guard<std::recursive_mutex> lock(SqMtx);
    SQBool R;
    // 执行虚拟机Main函数
    SQInteger top = sq_gettop(v); // saves the stack size before the call
    sq_pushroottable(v);          // pushes the global table
    sq_pushstring(v, _SC("Cb_userpartycreate"), -1);
    if (SQ_SUCCEEDED(
            sq_get(v, -2))) { // gets the fie123oo' from the global table
      sq_pushroottable(v); // push the 'this' (in this case is the global table)
      sq_pushuserpointer(v, user);
      sq_call(v, 2, SQTrue, SQTrue); // calls the function
      sq_getbool(v, -1, &R);
    }
    sq_settop(v, top); // restores the original stack size
    if (!R)
      return 0;
  }
  // 组队  同意组队和同意加入
  else if (packet_id == 11) {
    int Ret = doDispatch(a1, user, packet_class, packet_id, packet_src,
                         packet_len, a7, a8);
    std::lock_guard<std::recursive_mutex> lock(SqMtx);
    // 执行虚拟机Main函数
    SQInteger top = sq_gettop(v); // saves the stack size before the call
    sq_pushroottable(v);          // pushes the global table
    sq_pushstring(v, _SC("Cb_userpartyagree"), -1);
    if (SQ_SUCCEEDED(
            sq_get(v, -2))) { // gets the fie123oo' from the global table
      sq_pushroottable(v); // push the 'this' (in this case is the global table)
      sq_pushuserpointer(v, user);
      sq_call(v, 2, SQFalse, SQTrue); // calls the function
    }
    sq_settop(v, top); // restores the original stack size
    return Ret;
  }
  // 组队  退出队伍
  else if (packet_id == 13) {
    int Ret = doDispatch(a1, user, packet_class, packet_id, packet_src,
                         packet_len, a7, a8);
    std::lock_guard<std::recursive_mutex> lock(SqMtx);
    // 执行虚拟机Main函数
    SQInteger top = sq_gettop(v); // saves the stack size before the call
    sq_pushroottable(v);          // pushes the global table
    sq_pushstring(v, _SC("Cb_userpartyexit"), -1);
    if (SQ_SUCCEEDED(
            sq_get(v, -2))) { // gets the fie123oo' from the global table
      sq_pushroottable(v); // push the 'this' (in this case is the global table)
      sq_pushuserpointer(v, user);
      sq_call(v, 2, SQFalse, SQTrue); // calls the function
    }
    sq_settop(v, top); // restores the original stack size
    return Ret;
  }
  // 组队  踢出队伍
  else if (packet_id == 14) {
    int Ret = doDispatch(a1, user, packet_class, packet_id, packet_src,
                         packet_len, a7, a8);
    std::lock_guard<std::recursive_mutex> lock(SqMtx);
    // 执行虚拟机Main函数
    SQInteger top = sq_gettop(v); // saves the stack size before the call
    sq_pushroottable(v);          // pushes the global table
    sq_pushstring(v, _SC("Cb_userpartykick"), -1);
    if (SQ_SUCCEEDED(
            sq_get(v, -2))) { // gets the fie123oo' from the global table
      sq_pushroottable(v); // push the 'this' (in this case is the global table)
      sq_pushuserpointer(v, user);
      sq_call(v, 2, SQFalse, SQTrue); // calls the function
    }
    sq_settop(v, top); // restores the original stack size
    return Ret;
  }
  // 组队  委任队长
  else if (packet_id == 124) {
    int Ret = doDispatch(a1, user, packet_class, packet_id, packet_src,
                         packet_len, a7, a8);
    std::lock_guard<std::recursive_mutex> lock(SqMtx);
    // 执行虚拟机Main函数
    SQInteger top = sq_gettop(v); // saves the stack size before the call
    sq_pushroottable(v);          // pushes the global table
    sq_pushstring(v, _SC("Cb_userpartygivemaster"), -1);
    if (SQ_SUCCEEDED(
            sq_get(v, -2))) { // gets the fie123oo' from the global table
      sq_pushroottable(v); // push the 'this' (in this case is the global table)
      sq_pushuserpointer(v, user);
      sq_call(v, 2, SQFalse, SQTrue); // calls the function
    }
    sq_settop(v, top); // restores the original stack size
    return Ret;
  }

  // 下线
  else if (packet_id == 3) {
    std::lock_guard<std::recursive_mutex> lock(SqMtx);
    // 执行虚拟机Main函数
    SQInteger top = sq_gettop(v); // saves the stack size before the call
    sq_pushroottable(v);          // pushes the global table
    sq_pushstring(v, _SC("Cb_player_exit"), -1);
    if (SQ_SUCCEEDED(
            sq_get(v, -2))) { // gets the fie123oo' from the global table
      sq_pushroottable(v); // push the 'this' (in this case is the global table)
      sq_pushuserpointer(v, user);
      sq_call(v, 2, SQFalse, SQTrue); // calls the function
    }
    sq_settop(v, top); // restores the original stack size
  }
  // 查看信息
  else if (packet_id == 8) {
    std::lock_guard<std::recursive_mutex> lock(SqMtx);
    // 执行虚拟机Main函数
    SQInteger top = sq_gettop(v); // saves the stack size before the call
    sq_pushroottable(v);          // pushes the global table
    sq_pushstring(v, _SC("Cb_see_information"), -1);
    if (SQ_SUCCEEDED(
            sq_get(v, -2))) { // gets the fie123oo' from the global table
      sq_pushroottable(v); // push the 'this' (in this case is the global table)
      sq_pushuserpointer(v, user);
      sq_pushuserpointer(v, packet_src);
      sq_call(v, 3, SQFalse, SQTrue); // calls the function
    }
    sq_settop(v, top); // restores the original stack size
  }
  // 自定义包
  else if (packet_id == 130) {
    std::string str =
        Utils::PackToHexString((const unsigned char *)packet_src, 13);
    std::lock_guard<std::recursive_mutex> lock(SqMtx);
    SQInteger top = sq_gettop(v);
    sq_pushroottable(v);
    sq_pushstring(v, _SC("OnClientSocketMsg"), -1);
    if (SQ_SUCCEEDED(sq_get(v, -2))) {
      sq_pushroottable(v);
      sq_pushuserpointer(v, user);
      sq_pushstring(v, _SC(str.c_str()), -1);
      sq_call(v, 3, SQFalse, SQTrue); // calls the function
    }
    sq_settop(v, top);
  }
  return doDispatch(a1, user, packet_class, packet_id, packet_src, packet_len,
                    a7, a8);
}

int _Inter_LoadGeolocation_dispatch_sig(void *pThis, void *pUser, char *a3) {
  std::lock_guard<std::recursive_mutex> lock(SqMtx);
  // 执行虚拟机Main函数
  SQInteger top = sq_gettop(v); // saves the stack size before the call
  sq_pushroottable(v);          // pushes the global table
  sq_pushstring(v, _SC("sqr_main"), -1);
  if (SQ_SUCCEEDED(
          sq_get(v, -2))) { // gets the field 'foo' from the global table
    sq_pushroottable(v); // push the 'this' (in this case is the global table)
    sq_call(v, 1, SQFalse, SQTrue); // calls the function
  }
  sq_settop(v, top); // restores the original stack size

  int Ret = Inter_LoadGeolocation_dispatch_sig(pThis, pUser, a3);

  return Ret;
}
int _History_Log(int a1, char *format, ...) {
  char Buffer[2048];

  va_list args;
  va_start(args, format);
  va_list args_copy;
  va_copy(args_copy, args);
  vsprintf(Buffer, format, args);
  va_end(args);

  std::vector<std::string> Data;
  Tool::Split(Buffer, Data, ",");
  // std::cout << Buffer << std::endl;
  std::lock_guard<std::recursive_mutex> lock(SqMtx);
  // 执行虚拟机Main函数
  SQInteger top = sq_gettop(v); // saves the stack size before the call
  sq_pushroottable(v);          // pushes the global table
  sq_pushstring(v, _SC("Cb_History_Log"), -1);
  if (SQ_SUCCEEDED(
          sq_get(v, -2))) { // gets the field 'foo' from the global table
    sq_pushroottable(v); // push the 'this' (in this case is the global table)
    sq_newarray(v, 0);
    for (std::string Str : Data) {
      sq_pushstring(v, Str.c_str(), -1);
      sq_arrayappend(v, -2);
    }
    sq_call(v, 2, SQFalse, SQTrue); // calls the function
  }
  sq_settop(v, top); // restores the original stack size

  // std::cout << "Current Stack: " << top << std::endl;

  // 调用原始函数
  int result = History_Log(a1, format, args_copy);
  va_end(args_copy);
  return result;
}

int _Neof_startupGlobalInstances() {
  int ret = Neof_startupGlobalInstances();
  // 初始化松鼠
  InitSquirrel();
  return ret;
}

int _TimerQueue_GetTimerMess(void *thisC, void *timerEntry) {
  int ret = TimerQueue_GetTimerMess(thisC, timerEntry);
  l_socket::getInstance().Logic();
  return ret;
}

void Lenheart() {
  // 主程序才加载插件
  if (!checkGame("df_game_r")) {
    // HOOK五国标志开始初始化松鼠
    SUBHOOK_SETUP(Neof_startupGlobalInstances);
    SUBHOOK_SETUP(Inter_LoadGeolocation_dispatch_sig);
    SUBHOOK_SETUP(History_Log);

    SUBHOOK_SETUP(doDispatch);
    SUBHOOK_SETUP(TimerQueue_GetTimerMess); // 收包注册
  }
}

void __attribute__((constructor)) lenheart_init(void) { Lenheart(); }
