Pre FilemapVersion 70
This commit is contained in:
parent
dce2ca08f3
commit
be0fafb249
|
|
@ -24,8 +24,6 @@ namespace flyff {
|
|||
// extern void w2c_f167(fugg::String*, std::string*);
|
||||
extern void w2c_f167(u32, u32);
|
||||
|
||||
extern u32 w2c_f208(u64);
|
||||
|
||||
extern void w2c_f337(u32, u32, u32);
|
||||
// f271_called_on_attack
|
||||
extern u32 w2c_f271(u32 w2c_p0, u32 w2c_p1, u64 w2c_p2, u64 w2c_p3, u64 w2c_p4, u64 w2c_p5);
|
||||
|
|
|
|||
|
|
@ -3,22 +3,52 @@
|
|||
#include <fugg.h>
|
||||
|
||||
#include <cstddef>
|
||||
#include <iterator>
|
||||
#include <bitset>
|
||||
|
||||
#include "ObjectType.h"
|
||||
#include "core.h"
|
||||
#include "math.h"
|
||||
#include "ObjectType.h"
|
||||
#include "item.h"
|
||||
|
||||
namespace flyff {
|
||||
enum class MovementFlags : uint32_t {
|
||||
None = 0 << 0,
|
||||
CombatStance = 1 << 0,
|
||||
Walking = 1 << 1,
|
||||
Sitting = 1 << 2,
|
||||
Flying = 1 << 3,
|
||||
Unknown16 = 1 << 4,
|
||||
Unknown32 = 1 << 5,
|
||||
// Not sure, maybe for flying.
|
||||
TurboActivated = 1 << 6,
|
||||
};
|
||||
|
||||
inline constexpr MovementFlags operator&(MovementFlags x, MovementFlags y) {
|
||||
return static_cast<MovementFlags>(static_cast<uint32_t>(x) &
|
||||
static_cast<uint32_t>(y));
|
||||
}
|
||||
|
||||
struct __attribute__((packed)) Mover {
|
||||
union {
|
||||
DEFINE_MEMBER(0x18, flyff::Matrix4, world_matrix);
|
||||
DEFINE_MEMBER(0x98, flyff::Vector3, position);
|
||||
|
||||
DEFINE_MEMBER(152, flyff::Vector3, position);
|
||||
DEFINE_MEMBER(164, flyff::Vector3, rotation);
|
||||
|
||||
DEFINE_MEMBER(216, bool, set_in_constructor);
|
||||
|
||||
DEFINE_MEMBER(2020, const flyff::String, name);
|
||||
|
||||
DEFINE_MEMBER(1628, flyff::Vector3, move_target);
|
||||
|
||||
DEFINE_MEMBER(1728, flyff::MoverID, move_toward_target);
|
||||
DEFINE_MEMBER(1736, flyff::MoverID, last_attacked_target);
|
||||
DEFINE_MEMBER(1744, flyff::MoverID, selected_target);
|
||||
// The id of the target that it hit last.
|
||||
DEFINE_MEMBER(1752, flyff::MoverID, attack_target);
|
||||
DEFINE_MEMBER(1760, flyff::MoverID, follow_target);
|
||||
// The id, only non-zero when the attack animation plays, of the target it is attacking.
|
||||
DEFINE_MEMBER(1768, flyff::MoverID, current_attack_target);
|
||||
DEFINE_MEMBER(1776, flyff::MoverID, platform_standing_on);
|
||||
|
||||
|
|
@ -29,16 +59,59 @@ struct __attribute__((packed)) Mover {
|
|||
DEFINE_MEMBER(204, ObjectType, type);
|
||||
|
||||
DEFINE_MEMBER(216, uint32_t, existence_check);
|
||||
DEFINE_MEMBER(916, uint32_t, if_not_null_needsattackitem);
|
||||
|
||||
DEFINE_MEMBER(1804, uint32_t, pickup_things);
|
||||
|
||||
DEFINE_MEMBER(1806, uint16_t, pickup_flags);
|
||||
// Maybe status flags
|
||||
DEFINE_MEMBER(1807, uint8_t, is_dead_flags);
|
||||
DEFINE_MEMBER(1808, MovementFlags, movement_flags);
|
||||
|
||||
DEFINE_MEMBER(904, uint32_t, if_not_null_needsattackitem);
|
||||
|
||||
DEFINE_MEMBER(192, uintptr_t, world);
|
||||
|
||||
DEFINE_MEMBER(2264, flyff::MoverID, maybe_hash);
|
||||
// Only works on players.
|
||||
DEFINE_MEMBER(2472, uint32_t, level);
|
||||
|
||||
DEFINE_MEMBER(860, flyff::Vector<InventoryItem>, inventory);
|
||||
|
||||
const MinimumSize<4096> __size;
|
||||
};
|
||||
|
||||
bool is_dead() const {
|
||||
return (is_dead_flags & 8) != 0;
|
||||
static constexpr uint8_t const& IsDeadMask = 8;
|
||||
|
||||
return (is_dead_flags & IsDeadMask) != 0;
|
||||
}
|
||||
|
||||
bool is_walking() const {
|
||||
return (movement_flags & MovementFlags::Walking) != MovementFlags::None;
|
||||
}
|
||||
|
||||
bool is_flying() const {
|
||||
return (movement_flags & MovementFlags::Flying) != MovementFlags::None;
|
||||
}
|
||||
|
||||
// bool prevents_pickup_emote() const {
|
||||
// DEFINE_MEMBER(1806, uint16_t, pickup_flags);
|
||||
// // Returns true if in attack animation
|
||||
// return (pickup_flags & 0x8ff) != 0;
|
||||
// }
|
||||
};
|
||||
|
||||
};
|
||||
struct MoverMap {
|
||||
struct __attribute__((packed)) Node {
|
||||
Pointer<Node> next;
|
||||
unsigned int list_index;
|
||||
unsigned long long hash;
|
||||
Pointer<Mover> mover;
|
||||
};
|
||||
|
||||
Pointer<uintptr_t> buckets;
|
||||
size_t capacity;
|
||||
Pointer<Node> first;
|
||||
};
|
||||
|
||||
}; // namespace flyff
|
||||
|
|
@ -6,6 +6,12 @@
|
|||
// static_assert(offsetof(TestMover, name) == 0x7f4, "Mover.name needs to be at 2020");
|
||||
|
||||
namespace flyff {
|
||||
namespace raw {
|
||||
extern "C" {
|
||||
// get_mover
|
||||
extern u32 w2c_f208(u64);
|
||||
};
|
||||
};
|
||||
|
||||
// Emscripten runtime:
|
||||
// 1. Pre-run
|
||||
|
|
@ -14,10 +20,8 @@ namespace flyff {
|
|||
// 4. Call main
|
||||
// 5. Post-run
|
||||
|
||||
Neuz::Neuz() {
|
||||
// 1. Pre-run: There are no pre-runs in this binary.
|
||||
// 2. Init runtime: `___wasm_call_ctors` is added to on init runtime.
|
||||
(*flyff::raw::_wasm_call_ctors)();
|
||||
Neuz::Neuz() : movers(make_ref<MoverMap>(0x00032968)) {
|
||||
|
||||
}
|
||||
|
||||
Neuz& Neuz::instance() {
|
||||
|
|
@ -27,6 +31,9 @@ Neuz& Neuz::instance() {
|
|||
wasm_rt_init();
|
||||
// Initialise the client.
|
||||
flyff::raw::init();
|
||||
// 1. Pre-run: There are no pre-runs in this binary.
|
||||
// 2. Init runtime: `___wasm_call_ctors` is added to on init runtime.
|
||||
(*flyff::raw::_wasm_call_ctors)();
|
||||
// Only init the module once.
|
||||
initialised = true;
|
||||
}
|
||||
|
|
@ -42,4 +49,11 @@ int Neuz::main() const {
|
|||
// TODO: Fix arguments.
|
||||
return (*flyff::raw::main)(0, 0);
|
||||
}
|
||||
|
||||
Pointer<Mover> Neuz::get_mover(const flyff::MoverID& id) const {
|
||||
const auto& node = Pointer<MoverMap::Node>(raw::w2c_f208(id));
|
||||
|
||||
return node ? node->mover : nullptr;
|
||||
}
|
||||
|
||||
} // namespace flyff
|
||||
|
|
@ -3,6 +3,8 @@
|
|||
#include <cstdint>
|
||||
#include <client.h>
|
||||
|
||||
#include "Mover.h"
|
||||
|
||||
namespace flyff {
|
||||
namespace raw {
|
||||
static const auto& init = &Z_client_init;
|
||||
|
|
@ -24,9 +26,13 @@ namespace flyff {
|
|||
Neuz(Neuz const&) = delete;
|
||||
void operator=(Neuz const&) = delete;
|
||||
|
||||
MoverMap const& movers;
|
||||
|
||||
// Execute the `main` function of the flyff-client.
|
||||
int main() const;
|
||||
|
||||
Pointer<Mover> get_mover(const flyff::MoverID& id) const;
|
||||
|
||||
// Easy to implement: Just send a EmscriptenKeyboardEvent* to the registered function.
|
||||
// void send_keydown();
|
||||
// void send_keyup();
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
template <const size_t kSize>
|
||||
class MinimumSize {
|
||||
|
|
@ -12,23 +13,13 @@ class MinimumSize {
|
|||
#define STR_MERGE_IMPL(a, b) a##b
|
||||
#define STR_MERGE(a, b) STR_MERGE_IMPL(a, b)
|
||||
#define MAKE_PAD(size) STR_MERGE(_pad, __COUNTER__)[size]
|
||||
#define DEFINE_MEMBER(offset, type, name) struct {unsigned char MAKE_PAD(offset); type name;}
|
||||
#define DEFINE_MEMBER(offset, type, name) \
|
||||
struct { \
|
||||
unsigned char MAKE_PAD(offset); \
|
||||
type name; \
|
||||
}
|
||||
|
||||
namespace flyff {
|
||||
namespace detail {
|
||||
template<typename I, typename O>
|
||||
struct ArrowProxy {
|
||||
I value;
|
||||
|
||||
O* operator->() {
|
||||
return reinterpret_cast<O*>(&value);
|
||||
}
|
||||
|
||||
O& operator*() {
|
||||
return *(operator->)();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
class Memory {
|
||||
wasm_rt_memory_t** memory;
|
||||
|
|
@ -36,17 +27,20 @@ class Memory {
|
|||
public:
|
||||
explicit Memory(wasm_rt_memory_t** mem) : memory(mem) {}
|
||||
|
||||
const uintptr_t to_outside(const uintptr_t& offset) const {
|
||||
uintptr_t start() const {
|
||||
return reinterpret_cast<uintptr_t>((*memory)->data);
|
||||
}
|
||||
|
||||
uintptr_t to_inside(const uintptr_t offset) { return offset - start(); }
|
||||
|
||||
uintptr_t to_outside(const uintptr_t offset) {
|
||||
return reinterpret_cast<uintptr_t>(&(*memory)->data[offset]);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T* to_outside(T* offset) const {
|
||||
template <typename T>
|
||||
T* to_outside(const T* offset) {
|
||||
return reinterpret_cast<T*>(
|
||||
to_outside(
|
||||
reinterpret_cast<uintptr_t>(offset)
|
||||
)
|
||||
);
|
||||
to_outside(reinterpret_cast<uintptr_t>(offset)));
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -56,15 +50,76 @@ class Table {};
|
|||
|
||||
static const auto& kTable = &Z_clientZ_table;
|
||||
|
||||
|
||||
template<typename T>
|
||||
T& make_ref(uintptr_t address) {
|
||||
return *reinterpret_cast<T*>(kMemory.to_outside(address));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
class Pointer {
|
||||
class __attribute__((packed)) Pointer {
|
||||
// Always located INSIDE the flyff module.
|
||||
uintptr_t offset;
|
||||
|
||||
public:
|
||||
T* operator->() { return reinterpret_cast<T*>(kMemory.to_outside(offset)); }
|
||||
T* as_outside() const {
|
||||
return reinterpret_cast<T*>(kMemory.to_outside(offset));
|
||||
}
|
||||
|
||||
public:
|
||||
Pointer() : offset(0) { }
|
||||
Pointer(T* ptr) : offset(kMemory.to_inside(reinterpret_cast<uintptr_t>(ptr))) { }
|
||||
|
||||
explicit Pointer(uintptr_t ptr) : offset(ptr) { }
|
||||
|
||||
Pointer(const Pointer<T>& other) : offset(other.offset) { }
|
||||
Pointer<T>& operator=(Pointer<T> other) {
|
||||
offset = other.offset;
|
||||
return *this;
|
||||
}
|
||||
|
||||
T* operator->() {
|
||||
return as_outside();
|
||||
}
|
||||
|
||||
T const* operator->() const {
|
||||
return as_outside();
|
||||
}
|
||||
|
||||
T& operator*() {
|
||||
return *as_outside();
|
||||
}
|
||||
|
||||
T const& operator*() const {
|
||||
return *as_outside();
|
||||
}
|
||||
|
||||
explicit operator T*() {
|
||||
return as_outside();
|
||||
}
|
||||
|
||||
explicit operator T const*() {
|
||||
return as_outside();
|
||||
}
|
||||
|
||||
explicit operator bool() const {
|
||||
return offset != NULL;
|
||||
}
|
||||
|
||||
bool operator==(Pointer<T> const& rhs) const { return offset == rhs.offset; }
|
||||
|
||||
friend std::ostream& operator<<(std::ostream& os, const Pointer<T>& ptr) {
|
||||
os << "0x" << reinterpret_cast<void*>(ptr.offset);
|
||||
return os;
|
||||
}
|
||||
};
|
||||
|
||||
class String {
|
||||
// Allocates an unmanaged pointer inside the flyff module.
|
||||
// template <class T, class... Args>
|
||||
// Pointer<T> make_pointer(Args&&... args) {
|
||||
// return Pointer<T>(new T(std::forward<Args>(args)...));
|
||||
// }
|
||||
|
||||
class __attribute__((packed)) String {
|
||||
union {
|
||||
DEFINE_MEMBER(0x0, char*, text);
|
||||
DEFINE_MEMBER(0x4, size_t, length);
|
||||
|
|
@ -76,7 +131,7 @@ class String {
|
|||
const MinimumSize<12> __size;
|
||||
};
|
||||
|
||||
public:
|
||||
public:
|
||||
// This has to be const until strings can allocate...
|
||||
operator const std::string() const {
|
||||
auto copy = *this;
|
||||
|
|
@ -86,7 +141,7 @@ public:
|
|||
copy.text = kMemory.to_outside(text);
|
||||
// TODO: Probably offset capacity too.
|
||||
}
|
||||
|
||||
|
||||
return *reinterpret_cast<std::string*>(©);
|
||||
}
|
||||
|
||||
|
|
@ -96,9 +151,44 @@ public:
|
|||
return os;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
typedef unsigned long long MoverID;
|
||||
|
||||
static_assert(sizeof(String) == sizeof(std::string),
|
||||
"String needs to be the same size as std::string");
|
||||
|
||||
template<typename T>
|
||||
class __attribute__((packed)) Vector {
|
||||
Pointer<T> begin;
|
||||
Pointer<T> end;
|
||||
Pointer<T> capacity;
|
||||
|
||||
public:
|
||||
typedef T* iterator;
|
||||
typedef const T* const_iterator
|
||||
|
||||
// This has to be const until strings can allocate...
|
||||
T* begin() {
|
||||
return begin;
|
||||
}
|
||||
|
||||
T* end() {
|
||||
return end;
|
||||
}
|
||||
|
||||
// friend std::ostream& operator<<(std::ostream& os, const String& str) {
|
||||
// const std::string conv = str;
|
||||
// os << conv;
|
||||
// return os;
|
||||
// }
|
||||
};
|
||||
|
||||
static_assert(sizeof(Vector<char>) == sizeof(std::vector<char>),
|
||||
"Vector needs to be the same size as std::vector");
|
||||
|
||||
|
||||
class HashMap {
|
||||
|
||||
};
|
||||
|
||||
}; // namespace flyff
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
#pragma once
|
||||
|
||||
#include "core.h"
|
||||
|
||||
namespace flyff {
|
||||
struct __attribute__((packed)) ItemProperty {
|
||||
union {
|
||||
DEFINE_MEMBER(0, const flyff::String, model);
|
||||
DEFINE_MEMBER(12, uint32_t, id);
|
||||
|
||||
DEFINE_MEMBER(156, const flyff::String, name);
|
||||
DEFINE_MEMBER(168, const flyff::String, icon);
|
||||
DEFINE_MEMBER(180, const flyff::String, description);
|
||||
};
|
||||
};
|
||||
|
||||
struct __attribute__((packed)) InventoryItem {
|
||||
union {
|
||||
DEFINE_MEMBER(36, Pointer<ItemProperty>, item);
|
||||
|
||||
DEFINE_MEMBER(60, uint32_t, index);
|
||||
DEFINE_MEMBER(64, uint32_t, quantity);
|
||||
};
|
||||
};
|
||||
|
||||
} // namespace flyff
|
||||
|
|
@ -7,6 +7,11 @@ namespace flyff {
|
|||
|
||||
struct Vector3 {
|
||||
float x, y, z;
|
||||
|
||||
friend std::ostream& operator<<(std::ostream& os, const Vector3& pos) {
|
||||
os << pos.x << ", " << pos.y << ", " << pos.z;
|
||||
return os;
|
||||
}
|
||||
};
|
||||
|
||||
struct Matrix4 {
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ set_target_properties(
|
|||
fugg-client
|
||||
PROPERTIES LINK_FLAGS "\
|
||||
-lembind \
|
||||
-g \
|
||||
-sINITIAL_MEMORY=2048MB \
|
||||
-fsanitize=undefined \
|
||||
-sASSERTIONS=1 \
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ const flyff::String get_text(const std::string& id) {
|
|||
return *reinterpret_cast<flyff::String*>(result.get());
|
||||
}
|
||||
|
||||
void show_message(const std::string& message, const flyff::Color& color) {
|
||||
void show_message(const std::string& message, const flyff::Color& color = { 0xFF, 0xFF, 0xFF }) {
|
||||
// Copy the message into a new auto ptr
|
||||
auto message_ = std::make_unique<fugg::String>(message);
|
||||
auto color_ = std::make_unique<flyff::Color>(color);
|
||||
|
|
@ -208,9 +208,26 @@ void write_chat_message(const std::string& message) {
|
|||
send_packet(0x2000, packet);
|
||||
}
|
||||
|
||||
bool is_running = false;
|
||||
flyff::Vector3 start_position = { 0 };
|
||||
void on_keyup_hook(int event_type, const EmscriptenKeyboardEvent* event, void* user_data) {
|
||||
// [
|
||||
if(event->keyCode == 219) {
|
||||
// BracketLeft
|
||||
if(event->keyCode == 219 && is_running == false) {
|
||||
const auto& player_pointer = fugg::module_ref<uintptr_t>(0x0003546c);
|
||||
if(player_pointer == 0)
|
||||
return;
|
||||
|
||||
const auto& player = fugg::module_ref<flyff::Mover>(player_pointer);
|
||||
|
||||
start_position = { player.position.x, player.position.y, player.position.z };
|
||||
std::cout << "Start botting at " << start_position << std::endl;
|
||||
|
||||
is_running = true;
|
||||
|
||||
show_message("Bot started", { 0xFF, 0xFF, 0xFF });
|
||||
|
||||
// write_chat_message("Hi, how are you doing?");
|
||||
|
||||
// send_logout();
|
||||
// show_message(get_text("ids_textclient_fly_noskill"), { 0xFF, 0xFF, 0xFF });
|
||||
|
||||
|
|
@ -220,14 +237,7 @@ void on_keyup_hook(int event_type, const EmscriptenKeyboardEvent* event, void* u
|
|||
// Some aibatt NW of Flaris
|
||||
// set_target(0x069f7df5);
|
||||
// interact_target(1);
|
||||
|
||||
|
||||
const auto& player_pointer = fugg::module_ref<uintptr_t>(0x0003546c);
|
||||
if(player_pointer == 0)
|
||||
return;
|
||||
|
||||
const auto& player = fugg::module_ref<flyff::Mover>(player_pointer);
|
||||
const auto& player_object_id = fugg::module_ref<flyff::MoverID>(0x00034598);
|
||||
|
||||
// std::stringstream str;
|
||||
// str << "Position: "
|
||||
|
|
@ -248,69 +258,327 @@ void on_keyup_hook(int event_type, const EmscriptenKeyboardEvent* event, void* u
|
|||
// move_to(6968.38, 100.011, 3328.86);
|
||||
// send_motion_packet(0x404, 0x04, 535);
|
||||
// send_motion_packet(0x404, 0x11, 1);
|
||||
|
||||
}
|
||||
|
||||
if(event->keyCode == 221) {
|
||||
if(is_running == true) {
|
||||
is_running = false;
|
||||
|
||||
show_message("Bot stopped", { 0xFF, 0xFF, 0xFF });
|
||||
} else {
|
||||
const auto& player_pointer = fugg::module_ref<uintptr_t>(0x0003546c);
|
||||
if(player_pointer == 0)
|
||||
return;
|
||||
|
||||
// const auto& player = fugg::module_ref<flyff::Mover>(player_pointer);
|
||||
|
||||
// for(flyff::InventoryItem* item : player.inventory) {
|
||||
// std::cout << get_text(item.item->name) << std::endl;
|
||||
// }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
flyff::Pointer<flyff::Mover> attack_next_target(flyff::Vector3 const& start_position) {
|
||||
const auto& neuz = flyff::Neuz::instance();
|
||||
|
||||
const auto& player_pointer = fugg::module_ref<uintptr_t>(0x0003546c);
|
||||
if(player_pointer == 0)
|
||||
return nullptr;
|
||||
|
||||
auto& player = fugg::module_ref<flyff::Mover>(player_pointer);
|
||||
const auto& player_object_id = fugg::module_ref<flyff::MoverID>(0x00034598);
|
||||
|
||||
float lowest_distance = std::numeric_limits<float>::max();
|
||||
flyff::Pointer<flyff::Mover> closest = nullptr;
|
||||
flyff::MoverID closest_hash;
|
||||
|
||||
auto current = neuz.movers.first;
|
||||
do {
|
||||
const auto& mover = current->mover;
|
||||
|
||||
auto dx = std::abs(mover->position.x - start_position.x);
|
||||
auto dy = std::abs(mover->position.y - start_position.y) * 10;
|
||||
auto dz = std::abs(mover->position.z - start_position.z);
|
||||
|
||||
auto squared = (dx * dx) + (dy * dy) + (dz * dz);
|
||||
auto d = std::sqrt(squared);
|
||||
|
||||
|
||||
struct __attribute__((packed)) MoverHolder {
|
||||
uintptr_t next;
|
||||
unsigned int list_index;
|
||||
unsigned long long hash;
|
||||
uintptr_t mover;
|
||||
};
|
||||
|
||||
struct __attribute__((packed)) MoverHolderMap {
|
||||
uintptr_t buckets;
|
||||
size_t capacity;
|
||||
uintptr_t first;
|
||||
};
|
||||
|
||||
const auto& map = fugg::module_ref<MoverHolderMap>(0x00032968);
|
||||
|
||||
std::cout << "Got mover map with " << map.capacity << " movers." << std::endl;
|
||||
|
||||
float lowest_distance = 999999.f;
|
||||
uintptr_t closest = 0;
|
||||
flyff::MoverID closest_hash = 0;
|
||||
|
||||
auto current = map.first;
|
||||
do {
|
||||
const auto& current_ = fugg::module_ref<MoverHolder>(current);
|
||||
const auto& mover = fugg::module_ref<flyff::Mover>(current_.mover);
|
||||
|
||||
auto dx = mover.position.x - player.position.x;
|
||||
auto dz = mover.position.z - player.position.z;
|
||||
|
||||
auto squared = (dx * dx) + (dz * dz);
|
||||
auto d = std::sqrt(squared);
|
||||
|
||||
|
||||
if(mover.type == ObjectType::Mover &&
|
||||
current_.hash != player_object_id &&
|
||||
!mover.is_dead() &&
|
||||
d < lowest_distance) {
|
||||
|
||||
closest = current_.mover;
|
||||
closest_hash = current_.hash;
|
||||
if(mover->type == ObjectType::Mover &&
|
||||
current->hash != player_object_id &&
|
||||
!mover->is_dead()) {
|
||||
// If it's a monster that has me targetted
|
||||
if(mover->last_attacked_target == player_object_id) {
|
||||
closest = mover;
|
||||
closest_hash = current->hash;
|
||||
|
||||
std::cout << mover->name << " has attacked me, so I'm attacking" << std::endl;
|
||||
break;
|
||||
} else if(d < lowest_distance) {
|
||||
closest = mover;
|
||||
closest_hash = current->hash;
|
||||
lowest_distance = d;
|
||||
}
|
||||
|
||||
current = current_.next;
|
||||
} while(current != 0);
|
||||
|
||||
if(closest != 0) {
|
||||
const auto& closest_ = fugg::module_ref<flyff::Mover>(closest);
|
||||
|
||||
std::cout << closest_.name << " (of type " << closest_.type << ") is closest to the player." << std::endl;
|
||||
|
||||
set_target(closest_hash);
|
||||
interact_target(1);
|
||||
} else {
|
||||
std::cout << "There is no one close" << std::endl;
|
||||
}
|
||||
|
||||
current = current->next;
|
||||
} while(current);
|
||||
|
||||
if(closest) {
|
||||
player.selected_target = closest_hash;
|
||||
player.move_toward_target = closest_hash;
|
||||
player.attack_target = closest_hash;
|
||||
player.follow_target = closest_hash;
|
||||
|
||||
set_target(closest_hash);
|
||||
interact_target(1);
|
||||
|
||||
return closest;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const flyff::Mover* pickup_next_item() {
|
||||
const auto& player_pointer = fugg::module_ref<uintptr_t>(0x0003546c);
|
||||
if(player_pointer == 0)
|
||||
return nullptr;
|
||||
|
||||
auto& player = fugg::module_ref<flyff::Mover>(player_pointer);
|
||||
const auto& player_object_id = fugg::module_ref<flyff::MoverID>(0x00034598);
|
||||
|
||||
struct __attribute__((packed)) MoverHolder {
|
||||
uintptr_t next;
|
||||
unsigned int list_index;
|
||||
unsigned long long hash;
|
||||
uintptr_t mover;
|
||||
};
|
||||
|
||||
struct __attribute__((packed)) MoverHolderMap {
|
||||
uintptr_t buckets;
|
||||
size_t capacity;
|
||||
uintptr_t first;
|
||||
};
|
||||
|
||||
const auto& map = fugg::module_ref<MoverHolderMap>(0x00032968);
|
||||
|
||||
float lowest_distance = 999999.f;
|
||||
uintptr_t closest = 0;
|
||||
flyff::MoverID closest_hash = 0;
|
||||
|
||||
auto current = map.first;
|
||||
do {
|
||||
const auto& current_ = fugg::module_ref<MoverHolder>(current);
|
||||
const auto& mover = fugg::module_ref<flyff::Mover>(current_.mover);
|
||||
|
||||
auto dx = std::abs(player.position.x - mover.position.x);
|
||||
auto dz = std::abs(player.position.z - mover.position.z);
|
||||
|
||||
auto squared = (dx * dx) + (dz * dz);
|
||||
auto d = std::sqrt(squared);
|
||||
|
||||
if(mover.world != 0 &&
|
||||
mover.set_in_constructor == false &&
|
||||
mover.type == ObjectType::Item &&
|
||||
d < lowest_distance) {
|
||||
|
||||
closest = current_.mover;
|
||||
closest_hash = current_.hash;
|
||||
lowest_distance = d;
|
||||
}
|
||||
|
||||
current = current_.next;
|
||||
} while(current != 0);
|
||||
|
||||
if(closest != 0) {
|
||||
const auto& closest_ = fugg::module_ref<flyff::Mover>(closest);
|
||||
|
||||
player.selected_target = closest_hash;
|
||||
player.move_toward_target = closest_hash;
|
||||
player.move_target = closest_.position;
|
||||
|
||||
set_target(closest_hash);
|
||||
interact_target(1);
|
||||
|
||||
return &closest_;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool is_in_moverlist(const void* ptr) {
|
||||
|
||||
struct __attribute__((packed)) MoverHolder {
|
||||
uintptr_t next;
|
||||
unsigned int list_index;
|
||||
unsigned long long hash;
|
||||
uintptr_t mover;
|
||||
};
|
||||
|
||||
struct __attribute__((packed)) MoverHolderMap {
|
||||
uintptr_t buckets;
|
||||
size_t capacity;
|
||||
uintptr_t first;
|
||||
};
|
||||
|
||||
const auto& map = fugg::module_ref<MoverHolderMap>(0x00032968);
|
||||
|
||||
auto current = map.first;
|
||||
do {
|
||||
const auto& current_ = fugg::module_ref<MoverHolder>(current);
|
||||
const auto& mover = fugg::module_ref<flyff::Mover>(current_.mover);
|
||||
|
||||
if(&mover == ptr) {
|
||||
return true;
|
||||
}
|
||||
|
||||
current = current_.next;
|
||||
} while(current != 0);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
flyff::Pointer<flyff::Mover> current_target;
|
||||
flyff::Mover const* current_pickup_item = nullptr;
|
||||
|
||||
void bot_tick() {
|
||||
const auto& player_pointer = fugg::module_ref<uintptr_t>(0x0003546c);
|
||||
if(player_pointer == 0)
|
||||
return;
|
||||
|
||||
const auto& player = fugg::module_ref<flyff::Mover>(player_pointer);
|
||||
const auto& neuz = flyff::Neuz::instance();
|
||||
|
||||
// if(player.selected_target) {
|
||||
// const auto target = neuz.get_mover(player.selected_target);
|
||||
|
||||
// std::cout << "Target: "
|
||||
// << target->name << " "
|
||||
// << "(" << target << ")"
|
||||
// << " has "
|
||||
// << target->move_toward_target << ", "
|
||||
// << target->selected_target << ", "
|
||||
// << target->attack_target << ", "
|
||||
// << target->follow_target << ", "
|
||||
// // << target->
|
||||
// << std::endl;
|
||||
// }
|
||||
|
||||
// if(player.selected_target != 0) {
|
||||
// auto selected_target = neuz.get_mover(player.selected_target);
|
||||
|
||||
// std::cout << "Target: "
|
||||
// << selected_target->name << " at "
|
||||
// << selected_target->position.x << ", "
|
||||
// << selected_target->position.y << ", "
|
||||
// << selected_target->position.z << std::endl;
|
||||
|
||||
// } else {
|
||||
// std::cout << "Got no target." << std::endl;
|
||||
// }
|
||||
|
||||
// std::cout << get_text("ids_textclient_needsattackitem") << std::endl;
|
||||
|
||||
// const auto& neuz = flyff::Neuz::instance();
|
||||
|
||||
// auto first = neuz.movers.first;
|
||||
// do {
|
||||
// auto& mover = *first->mover;
|
||||
// std::cout << mover.position << std::endl;
|
||||
|
||||
// first = first->next;
|
||||
// } while(first);
|
||||
// std::cout << neuz.movers.capacity << std::endl;
|
||||
|
||||
// std::cout << reinterpret_cast<void*>(player.if_not_null_needsattackitem) << std::endl;
|
||||
|
||||
// std::cout << "Some flags & 4 = " << ((player.movement_flags & 4) != 0) << std::endl;
|
||||
// std::cout << player.prevents_pickup_emote() << std::endl;
|
||||
// std::cout << player.pickup_things << std::endl;
|
||||
|
||||
// std::cout << get_text("ids_textclient_party_changeitem") << std::endl;
|
||||
// Party Distribute Item changed to %s.
|
||||
|
||||
// std::cout << get_text("ids_textclient_invalid_target_item") << std::endl;
|
||||
// std::cout << get_text("ids_textclient_sbeve_notuseitem") << std::endl;
|
||||
// std::cout << get_text("ids_textclient_lackspace") << std::endl;
|
||||
// Cannot be done.
|
||||
// You cannot use that item.
|
||||
// Inventory is full. Please make room and try again.
|
||||
|
||||
// std::cout << get_text("ids_textclient_notdrop") << std::endl;
|
||||
// You cannot drop a premium item on the ground.
|
||||
|
||||
// std::cout << get_text("ids_textclient_return_useitem") << std::endl;
|
||||
// The item loses its potency 4 hours after being equipped if not returned to the inventory . Do you want to use the item?
|
||||
|
||||
// std::cout << get_text("ids_textclient_attentioncooltime") << std::endl;
|
||||
// Please wait a while before using the item again.
|
||||
|
||||
// std::cout << get_text("ids_textclient_remove_error") << std::endl;
|
||||
// That weapon is not possible to remove the element upgrading. Try again after checking.
|
||||
|
||||
// std::cout << get_text("ids_textclient_warningccls") << std::endl;
|
||||
// Your stats will reset after you change your job. Do you want to change your job?
|
||||
|
||||
if(is_running) {
|
||||
|
||||
if(current_pickup_item != nullptr) {
|
||||
// std::cout << "Item's World = " << current_pickup_item->world << std::endl;
|
||||
// There is an item to pick up.
|
||||
if(is_in_moverlist(current_pickup_item)) {
|
||||
// Wait
|
||||
show_message("Waiting for pickup");
|
||||
} else {
|
||||
show_message("Picked up, waiting for ready");
|
||||
|
||||
if((player.pickup_flags & 0x8ff) == 0 && player.current_animation == 0) {
|
||||
show_message("Picking up done.");
|
||||
|
||||
current_pickup_item = pickup_next_item();
|
||||
if(current_pickup_item != nullptr) {
|
||||
show_message("Picking up");
|
||||
}
|
||||
}
|
||||
// Maybe some confirmation...
|
||||
// send_motion_packet(0x01, *reinterpret_cast<const MotionParam*>(&player.rotation.y));
|
||||
|
||||
}
|
||||
} else if(current_target == nullptr) {
|
||||
if(player.pickup_things != 1)
|
||||
return;
|
||||
|
||||
current_pickup_item = nullptr;
|
||||
current_target = attack_next_target(start_position);
|
||||
|
||||
if(current_target) {
|
||||
std::string str = "Attacking ";
|
||||
str.append(current_target->name);
|
||||
|
||||
show_message(str, { 0xFF, 0xFF, 0xFF });
|
||||
} else {
|
||||
show_message("Unable to find target.", { 0xFF, 0x00, 0x00 });
|
||||
}
|
||||
} else if(current_target->is_dead()) {
|
||||
current_target = nullptr;
|
||||
|
||||
current_pickup_item = pickup_next_item();
|
||||
if(current_pickup_item != nullptr) {
|
||||
show_message("Picking up");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Reset current target is not running.
|
||||
current_target = nullptr;
|
||||
current_pickup_item = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void before_main_loop() {
|
||||
bot_tick();
|
||||
|
||||
// auto& client = fugg::Client::instance();
|
||||
|
||||
// const auto& test = translate("ids_textclient_cannot_dropmoney");
|
||||
|
|
|
|||
Reference in New Issue