diff --git a/flyff-api/src/Neuz.h b/flyff-api/src/Neuz.h index 6cbe174..34fd913 100644 --- a/flyff-api/src/Neuz.h +++ b/flyff-api/src/Neuz.h @@ -29,11 +29,12 @@ namespace flyff { const Pointer &messages_ui; const Pointer &announcements_ui; + protected: + Neuz(Neuz const &) = default; + public: static Neuz &instance(); - Neuz(Neuz const &) = delete; - void operator=(Neuz const &) = delete; MoverMap const &movers; diff --git a/flyff-api/src/object/mover/Mover.h b/flyff-api/src/object/mover/Mover.h index 3f295fb..84bb83f 100644 --- a/flyff-api/src/object/mover/Mover.h +++ b/flyff-api/src/object/mover/Mover.h @@ -163,12 +163,15 @@ namespace flyff { DEFINE_MEMBER(192, uintptr_t, world); DEFINE_MEMBER(860, Vector, inventory); + // If the index of the InventoryItem is below this, it's in the inventory. Otherwise it's equipped. + DEFINE_MEMBER(872, const uint32_t, max_inventory_slots); + DEFINE_MEMBER(880, const uint32_t, locked_inventory_slots); DEFINE_MEMBER(2432, const flyff::Pointer, job_property); - DEFINE_MEMBER(3324, Timestamp, last_food_time); - DEFINE_MEMBER(3348, Timestamp, last_refresher_time); - DEFINE_MEMBER(3356, Timestamp, last_vitaldrink_time); + DEFINE_MEMBER(3224, Timestamp, last_food_time); + DEFINE_MEMBER(3248, Timestamp, last_refresher_time); + DEFINE_MEMBER(3256, Timestamp, last_vitaldrink_time); DEFINE_MEMBER(3424, Vector, skills); @@ -192,6 +195,10 @@ namespace flyff { return raw::w2c_f2466(kMemory.to_inside(&last_food_time), static_cast(property)); } + uint32_t get_inventory_slots() const { + return max_inventory_slots - locked_inventory_slots; + } + bool is_in_combat() const; Parameter get_param(uint32_t index, Parameter base) const { diff --git a/fugg-client/CMakeLists.txt b/fugg-client/CMakeLists.txt index 35addd4..c3a49a9 100644 --- a/fugg-client/CMakeLists.txt +++ b/fugg-client/CMakeLists.txt @@ -1,7 +1,7 @@ add_executable( fugg-client "src/main.cpp" - "src/client.cpp" + "src/Client.cpp" # Symbols that flyff-client imports. "src/export/gl.cpp" "src/export/al.cpp" @@ -9,7 +9,7 @@ add_executable( "src/export/embind.cpp" "src/export/env.cpp" "src/export/platform.cpp" - src/Bot.cpp src/Bot.h src/Action.h) + src/Bot.cpp src/Bot.h src/Action.h src/Packet.h) # Flyff is based on c++14 add_definitions(-std=c++14 -Os) diff --git a/fugg-client/src/client.cpp b/fugg-client/src/Client.cpp similarity index 74% rename from fugg-client/src/client.cpp rename to fugg-client/src/Client.cpp index 181105c..fc6021a 100644 --- a/fugg-client/src/client.cpp +++ b/fugg-client/src/Client.cpp @@ -1,4 +1,4 @@ -#include "client.h" +#include "Client.h" #include @@ -6,16 +6,6 @@ #include #include -namespace fugg { - Client::Client() { - - } -} - -constexpr const uint32_t hash_to_id(const uint32_t hashed) { - return hashed ^ flyff::PACKET_HEADER_HASH; -} - template void packet_push(std::vector &packet, const T &value, std::vector::iterator offset) { union ToBytes { @@ -33,37 +23,139 @@ void packet_push(std::vector &packet, const T &value) { return packet_push(packet, value, std::end(packet)); } -void send_packet(const uint32_t &id, std::vector payload) { - const uint32_t header = id < 0x400 ? id : id ^ flyff::PACKET_HEADER_HASH; - // Add header - packet_push(payload, header, std::begin(payload)); +namespace fugg { + Client::Client() : flyff::Neuz(flyff::Neuz::instance()) { - struct Vector { - uintptr_t begin; - uintptr_t end; - uintptr_t capacity; - }; + } - auto raw_payload = reinterpret_cast(&payload); - // Copy the message into a new ptr - auto payload_ = std::make_unique(Vector{ - .begin = fugg::RuntimePointer(raw_payload->begin).as_raw(), - .end = fugg::RuntimePointer(raw_payload->end).as_raw(), - .capacity = fugg::RuntimePointer(raw_payload->capacity).as_raw() - }); + Client &Client::instance() { + // Constructor will be called. + static Client instance; + // Whole module is initialised now. + return instance; + } - flyff::api::finalize_packet( - fugg::RuntimePointer(payload_.get()).as_raw() - ); + void Client::send_packet(const uint32_t &id, std::vector payload) const { + const uint32_t header = id < 0x400 ? id : id ^ flyff::PACKET_HEADER_HASH; + // Add header + packet_push(payload, header, std::begin(payload)); - flyff::api::websocket_send( - payload_->begin, - payload_->end - payload_->begin - ); -} + struct Vector { + uintptr_t begin; + uintptr_t end; + uintptr_t capacity; + }; -void send_logout() { - send_packet(0x403, {}); + auto raw_payload = reinterpret_cast(&payload); + // Copy the message into a new ptr + auto payload_ = std::make_unique(Vector{ + .begin = fugg::RuntimePointer(raw_payload->begin).as_raw(), + .end = fugg::RuntimePointer(raw_payload->end).as_raw(), + .capacity = fugg::RuntimePointer(raw_payload->capacity).as_raw() + }); + + flyff::api::finalize_packet( + fugg::RuntimePointer(payload_.get()).as_raw() + ); + + flyff::api::websocket_send( + payload_->begin, + payload_->end - payload_->begin + ); + } + + void Client::send_logout() const { + send_packet(0x403, {}); + } + + void Client::send_move_item_in_inventory(const uint32_t &from_slot, const uint32_t &to_slot) const { + std::vector packet; + + packet_push(packet, from_slot); + packet_push(packet, to_slot); + + send_packet(0x2001, packet); + } + + void Client::send_use_item_in_inventory(const uint32_t &slot) const { + std::vector packet; + + packet_push(packet, slot); + // Unknown yet + packet_push(packet, 0); + + send_packet(0x410, packet); + } + + void Client::send_motion_packet(const uint32_t &action, unsigned long long param0, unsigned long long param1, + unsigned long long param2, unsigned long long param3) const { + const int32_t motion_packet_id = 0x404; + const auto &neuz = flyff::Neuz::instance(); + + if (!neuz.player) return; + + std::vector packet; + + uint8_t param_flags = 0; + if (param0 != 0) param_flags |= 1; + if (param1 != 0) param_flags |= 2; + if (param2 != 0) param_flags |= 4; + if (param3 != 0) param_flags |= 8; + + packet_push(packet, neuz.player->position); + packet_push(packet, action); + packet_push(packet, param_flags); + packet_push(packet, neuz.player->server_tick); + + if (param0 != 0) packet_push(packet, param0); + if (param1 != 0) packet_push(packet, param1); + if (param2 != 0) packet_push(packet, param2); + if (param3 != 0) packet_push(packet, param3); + + send_packet(motion_packet_id, packet); + } + + void Client::set_target(const unsigned long long &id) const { + send_motion_packet(0x04, id); + } + + void Client::clear_target() const { + send_motion_packet(0x04, {}); + } + + void Client::interact_target(const unsigned long long &index) const { + send_motion_packet(0x11, index); + } + + void Client::use_skill(const flyff::SkillID &id, unsigned long long target) const { + send_motion_packet(0x5, static_cast(id), target); + } + + void Client::send_move_to(const double &x, const double &y, const double &z) const { + // Mouse click + send_motion_packet( + 0, + *reinterpret_cast(&x), + *reinterpret_cast(&y), + *reinterpret_cast(&z) + ); + } + + void Client::send_chat_message(const std::string &message) const { + std::vector packet; + // Message length + packet_push(packet, message.length()); + // Write message + for (const auto &character: message) { + packet_push(packet, character); + } + // Unknown 1 + packet_push(packet, 0); + // Unknown 2 + packet_push(packet, 0); + + send_packet(0x2000, packet); + } } #include @@ -77,109 +169,6 @@ void send_logout() { #include -void move_item_in_inventory(const uint32_t &from_slot, const uint32_t &to_slot) { - std::vector packet; - - packet_push(packet, from_slot); - packet_push(packet, to_slot); - - send_packet(0x2001, packet); -} - -void use_item_in_inventory(const uint32_t &slot) { - std::vector packet; - - packet_push(packet, slot); - // Unknown yet - packet_push(packet, 0); - - send_packet(0x410, packet); -} - -struct MotionPacketParams { - unsigned long long param0 = 0; - unsigned long long param1 = 0; - unsigned long long param2 = 0; - unsigned long long param3 = 0; -}; - -void send_motion_packet( - const uint32_t &action, - MotionPacketParams params, - uint32_t server_tick_delta = 0 -) { - const int32_t motion_packet_id = 0x404; - const auto &neuz = flyff::Neuz::instance(); - - if (!neuz.player) return; - - std::vector packet; - - uint8_t param_flags = 0; - if (params.param0 != 0) param_flags |= 1; - if (params.param1 != 0) param_flags |= 2; - if (params.param2 != 0) param_flags |= 4; - if (params.param3 != 0) param_flags |= 8; - - packet_push(packet, neuz.player->position); - packet_push(packet, action); - packet_push(packet, param_flags); - packet_push(packet, neuz.player->server_tick + server_tick_delta); - - if (params.param0 != 0) packet_push(packet, params.param0); - if (params.param1 != 0) packet_push(packet, params.param1); - if (params.param2 != 0) packet_push(packet, params.param2); - if (params.param3 != 0) packet_push(packet, params.param3); - - send_packet(motion_packet_id, packet); -} - -void set_target(const unsigned long long &id) { - send_motion_packet(0x04, {id}); -} - -void clear_target() { - send_motion_packet(0x04, {}); -} - -void interact_target(const unsigned long long &index) { - send_motion_packet(0x11, {index}); -} - -void use_skill(const flyff::SkillID &id, uint32_t server_tick_delta = 0) { - static constexpr unsigned long long param1 = -1; - - send_motion_packet(0x5, {static_cast(id), param1}, server_tick_delta); -} - -// void move_to(const float& x, const float& y, const float& z) { -// // Mouse click -// send_motion_packet( -// 0, -// // This is not right, it reads 8 bytes where there are 4 bytes. -// *reinterpret_cast(&x), -// *reinterpret_cast(&y), -// *reinterpret_cast(&z) -// ); -// } - -void write_chat_message(const std::string &message) { - // 00 94 4A 64 [0B 00 00 00] [48 65 6C 6C 6F 20 77 6F 72 6C 64] 00 00 00 00 00 00 00 00 - - std::vector packet; - // Message length - packet_push(packet, message.length()); - // Write message - for (const auto &character: message) { - packet_push(packet, character); - } - // Unknown 1 - packet_push(packet, 0); - // Unknown 2 - packet_push(packet, 0); - - send_packet(0x2000, packet); -} flyff::Pointer find_skill_buff(const flyff::Pointer &mover, const flyff::SkillID &skill_index) { @@ -257,17 +246,47 @@ flyff::Vector3 start_position = {0}; int object_property_index = 0; void on_keyup_hook(int event_type, const EmscriptenKeyboardEvent *event, void *user_data) { - const auto &neuz = flyff::Neuz::instance(); + const auto &client = fugg::Client::instance(); if (event->keyCode == 220) { + const auto &player = client.player; + + auto items = player->inventory.begin(); + + std::cout << "Player has " << player->get_inventory_slots() << " slots" << std::endl; + std::cout << "Player has " << player->get_hp_percent() << "% HP" << std::endl; + + for (auto i = 0; i < player->get_inventory_slots(); i++) { + + if (items[i].property && items[i].property->is_food()) { + std::cout << client.get_text(items[i].property->name) << ": " + << "Is food? " << (items[i].property->is_food() ? "Yes" : "No") << ", " + << "Can use? " << (player->can_use_item(items[i].property) ? "Yes" : "No") + << std::endl; + } + +// if (items[i].property && +// items[i].property->is_food() && +// player->can_use_item(items[i].property)) { +// std::string str = "Eating "; +// str.append(client.get_text(items[i].property->name)); +// str.append(" because HP is below 75%"); +// +// client.show_message(str); +// +// client.send_use_item_in_inventory(i); +// +// break; +// } + } // if (!main_hand || main_hand->item_kind3 != flyff::ItemProperty::CheerStick) { // const auto &stick = find_first_equippable_item(flyff::ItemProperty::CheerStick); // // if (stick) { // std::string str = "Found valid cheerstick: "; -// str.append(neuz.get_text(stick->property->name)); -// neuz.show_message(str, {0, 0xFF, 0}); +// str.append(client.get_text(stick->property->name)); +// client.show_message(str, {0, 0xFF, 0}); // // use_item_in_inventory(stick->id); // } @@ -285,7 +304,7 @@ void on_keyup_hook(int event_type, const EmscriptenKeyboardEvent *event, void *u // ); // std::cout << "BuffSkill " - // << neuz.get_text(skill_property->name) + // << client.get_text(skill_property->name) // << " ReqLv. " << skill_property->required_level // << " Lv." << skill_property->level // << " Id: " << reinterpret_cast(skill_property->id) @@ -314,7 +333,7 @@ void on_keyup_hook(int event_type, const EmscriptenKeyboardEvent *event, void *u // // else Equipped // // std::cout << items[i].id << std::endl; - // std::cout << neuz.get_text(items[i].property->name) << " at " << items[i].id << ": " + // std::cout << client.get_text(items[i].property->name) << " at " << items[i].id << ": " // << "IK2=" << items[i].property->item_kind2 << ", " // << "IK3=" << items[i].property->item_kind3 // << std::endl; @@ -336,62 +355,62 @@ void on_keyup_hook(int event_type, const EmscriptenKeyboardEvent *event, void *u // // Use skill Heal // use_skill(0x2c, 10); // } else { - // neuz.show_message("Could not find a stick to heal myself.", { 0xFF, 0, 0 }); + // client.show_message("Could not find a stick to heal myself.", { 0xFF, 0, 0 }); // } } // BracketLeft if (event->keyCode == 219 && !is_running) { - if (!neuz.player) + if (!client.player) return; - if (neuz.player->selected_target == 0) { - neuz.show_message("No monster selected, unable to start bot.", {0xFF, 0, 0}); + if (client.player->selected_target == 0) { + client.show_message("No monster selected, unable to start bot.", {0xFF, 0, 0}); return; } - auto target = neuz.get_mover(neuz.player->selected_target); + auto target = client.get_mover(client.player->selected_target); if (!target) { - neuz.show_message("No monster selected, unable to start bot.", {0xFF, 0xFF, 0}); + client.show_message("No monster selected, unable to start bot.", {0xFF, 0xFF, 0}); return; } std::string str = "I'm only going to kill "; - str.append(neuz.get_text(target->name)); + str.append(client.get_text(target->name)); str.append("get_level())); str.append(">"); - neuz.show_message(str); + client.show_message(str); object_property_index = target->property_id; - start_position = {neuz.player->position.x, neuz.player->position.y, neuz.player->position.z}; + start_position = {client.player->position.x, client.player->position.y, client.player->position.z}; std::cout << "Start botting at " << start_position << std::endl; is_running = true; - neuz.show_message("Bot started"); + client.show_message("Bot started"); } if (event->keyCode == 221) { if (is_running) { is_running = false; - neuz.show_message("Bot stopped"); + client.show_message("Bot stopped"); } else { - if (!neuz.player) return; + if (!client.player) return; - std::cout << "My job is " << neuz.player->get_job() << std::endl; + std::cout << "My job is " << client.player->get_job() << std::endl; -// neuz.show_announcement("Hello world!", {0xFF, 0, 0}); +// client.show_announcement("Hello world!", {0xFF, 0, 0}); -// auto current = neuz.movers.first; +// auto current = client.movers.first; // do { // const auto &mover = current->mover; // // if (mover->type == flyff::ObjectType::Mover) { // // int level = mover->get_level(); // -// std::cout << neuz.get_text(mover->name) << " get_level() << ">): " +// std::cout << client.get_text(mover->name) << " get_level() << ">): " // << (mover->is_dead() ? "Dead" : "Not dead") << ", " // << (mover->is_fly() ? "Flying" : "Not flying") << ", " // << (mover->is_jumping() ? "Jumping" : "Not jumping") << ", " @@ -412,7 +431,7 @@ void on_keyup_hook(int event_type, const EmscriptenKeyboardEvent *event, void *u // // std::cout << items[i].id << std::endl; // std::cout << "(Property address: " << static_cast(items[i].property) << ", " // << "Item address: " << &items[i] << ") " - // << neuz.get_text(items[i].property->name) << ": " + // << client.get_text(items[i].property->name) << ": " // << "Cooldown=" << items[i].property->cooldown_time << ", " // << "Maybe category=" << items[i].property->category << ", " // << "Maybe subcategory=" << items[i].property->sub_category << ", " @@ -426,6 +445,7 @@ void on_keyup_hook(int event_type, const EmscriptenKeyboardEvent *event, void *u flyff::MoverID attack_next_target(flyff::Vector3 const &start_position) { auto &neuz = flyff::Neuz::instance(); + auto &client = fugg::Client::instance(); if (!neuz.player) return 0; @@ -466,10 +486,10 @@ flyff::MoverID attack_next_target(flyff::Vector3 const &start_position) { if (closest) { neuz.player->selected_target = closest->object_id; - set_target(closest->object_id); + client.set_target(closest->object_id); neuz.player->move_toward_target = closest->object_id; - interact_target(1); + client.interact_target(1); return closest->object_id; } @@ -521,15 +541,16 @@ flyff::MoverID find_next_item() { void interact(flyff::MoverID id) { const auto &neuz = flyff::Neuz::instance(); + const auto &client = fugg::Client::instance(); if (!neuz.player) return; neuz.player->selected_target = id; - set_target(id); + client.set_target(id); neuz.player->move_toward_target = id; - interact_target(1); + client.interact_target(1); } flyff::MoverID current_target = 0; @@ -537,6 +558,7 @@ flyff::MoverID current_pickup_item = 0; void bot_tick() { const auto &neuz = flyff::Neuz::instance(); + const auto &client = fugg::Client::instance(); if (!neuz.player) return; @@ -567,16 +589,11 @@ void bot_tick() { // attack_target() if (neuz.player->get_hp_percent() < 75) { - // neuz.show_message("Fooding because HP is under 75%"); - - const auto &player = neuz.player; - + // neuz.show_message("Fooding because HP is under 75%");W auto items = player->inventory.begin(); - auto length = ((uintptr_t) player->inventory.end() - (uintptr_t) player->inventory.begin()) / 0x60; - - for (auto i = 0; i < length; i++) { - if (items[i].index != -1 && - items[i].property && + std::cout << "Player has " << player->get_inventory_slots() << " slots" << std::endl; + for (auto i = 0; i < player->get_inventory_slots(); i++) { + if (items[i].property && items[i].property->is_food() && player->can_use_item(items[i].property)) { std::string str = "Eating "; @@ -585,7 +602,7 @@ void bot_tick() { neuz.show_message(str); - use_item_in_inventory(i); + client.send_use_item_in_inventory(i); break; } @@ -620,15 +637,15 @@ void bot_tick() { if (stick) { buffs.pop_back(); - use_item_in_inventory(stick->index); - use_skill(skill_index); + client.send_use_item_in_inventory(stick->index); + client.use_skill(skill_index); return; } else { neuz.show_message("Unable to find a stick", {0xFF, 0, 0}); } } else { buffs.pop_back(); - use_skill(skill_index); + client.use_skill(skill_index); return; } } @@ -638,7 +655,7 @@ void bot_tick() { const auto &knuckle = find_first_equippable_item(flyff::ItemKind3::KnuckleHammer); if (knuckle) { - use_item_in_inventory(knuckle->index); + client.send_use_item_in_inventory(knuckle->index); } else { neuz.show_message("Unable to find a knuckle", {0xFF, 0, 0}); } @@ -648,7 +665,7 @@ void bot_tick() { const auto &shield = find_first_equippable_item(flyff::ItemKind3::Shield); if (shield) { - use_item_in_inventory(shield->index); + client.send_use_item_in_inventory(shield->index); } else { neuz.show_message("Unable to find a shield", {0xFF, 0, 0}); } diff --git a/fugg-client/src/Client.h b/fugg-client/src/Client.h new file mode 100644 index 0000000..c5205c1 --- /dev/null +++ b/fugg-client/src/Client.h @@ -0,0 +1,44 @@ +#include + +#include + +#include + +#include "Packet.h" + +namespace fugg { + class Client : public flyff::Neuz { + Client(); + + public: + static Client &instance(); + + Client(Client const &) = delete; + + void operator=(Client const &) = delete; + + void send_packet(const uint32_t &id, std::vector payload) const; + + void send_logout() const; + + void send_move_item_in_inventory(const uint32_t &from_slot, const uint32_t &to_slot) const; + + void send_use_item_in_inventory(const uint32_t &slot) const; + + void send_motion_packet(const uint32_t &action, unsigned long long param0 = 0, unsigned long long param1 = 0, + unsigned long long param2 = 0, unsigned long long param3 = 0) const; + + void set_target(const unsigned long long &id) const; + + void clear_target() const; + + void interact_target(const unsigned long long &index) const; + + void use_skill(const flyff::SkillID &id, unsigned long long target = -1) const; + + void send_move_to(const double &x, const double &y, const double &z) const; + void send_chat_message(const std::string &message) const; + + + }; +} \ No newline at end of file diff --git a/fugg-client/src/Packet.h b/fugg-client/src/Packet.h new file mode 100644 index 0000000..05137ba --- /dev/null +++ b/fugg-client/src/Packet.h @@ -0,0 +1,23 @@ +// +// Created by main on 24-10-22. +// + +#ifndef FUGG_PACKET_H +#define FUGG_PACKET_H + +namespace fugg { + struct Packet { + uint32_t id; + }; + + struct PacketMoveItemInInventory : Packet { + uint32_t from_slot; + uint32_t to_slot; + + PacketMoveItemInInventory(uint32_t from_slot, uint32_t to_slot) : Packet{0x2001}, + from_slot(from_slot), to_slot(to_slot) {} + }; +}; + + +#endif //FUGG_PACKET_H diff --git a/fugg-client/src/client.h b/fugg-client/src/client.h deleted file mode 100644 index 68a33b8..0000000 --- a/fugg-client/src/client.h +++ /dev/null @@ -1,11 +0,0 @@ -#include - -namespace fugg { - class Client { - Client(); - - public: - - - }; -} \ No newline at end of file