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(fugg::String*, std::string*);
|
||||||
extern void w2c_f167(u32, u32);
|
extern void w2c_f167(u32, u32);
|
||||||
|
|
||||||
extern u32 w2c_f208(u64);
|
|
||||||
|
|
||||||
extern void w2c_f337(u32, u32, u32);
|
extern void w2c_f337(u32, u32, u32);
|
||||||
// f271_called_on_attack
|
// 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);
|
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 <fugg.h>
|
||||||
|
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
|
#include <iterator>
|
||||||
|
#include <bitset>
|
||||||
|
|
||||||
|
#include "ObjectType.h"
|
||||||
#include "core.h"
|
#include "core.h"
|
||||||
#include "math.h"
|
#include "math.h"
|
||||||
#include "ObjectType.h"
|
#include "item.h"
|
||||||
|
|
||||||
namespace flyff {
|
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 {
|
struct __attribute__((packed)) Mover {
|
||||||
union {
|
union {
|
||||||
DEFINE_MEMBER(0x18, flyff::Matrix4, world_matrix);
|
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(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);
|
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(1752, flyff::MoverID, attack_target);
|
||||||
DEFINE_MEMBER(1760, flyff::MoverID, follow_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(1768, flyff::MoverID, current_attack_target);
|
||||||
DEFINE_MEMBER(1776, flyff::MoverID, platform_standing_on);
|
DEFINE_MEMBER(1776, flyff::MoverID, platform_standing_on);
|
||||||
|
|
||||||
|
|
@ -29,16 +59,59 @@ struct __attribute__((packed)) Mover {
|
||||||
DEFINE_MEMBER(204, ObjectType, type);
|
DEFINE_MEMBER(204, ObjectType, type);
|
||||||
|
|
||||||
DEFINE_MEMBER(216, uint32_t, existence_check);
|
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(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;
|
const MinimumSize<4096> __size;
|
||||||
};
|
};
|
||||||
|
|
||||||
bool is_dead() const {
|
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");
|
// static_assert(offsetof(TestMover, name) == 0x7f4, "Mover.name needs to be at 2020");
|
||||||
|
|
||||||
namespace flyff {
|
namespace flyff {
|
||||||
|
namespace raw {
|
||||||
|
extern "C" {
|
||||||
|
// get_mover
|
||||||
|
extern u32 w2c_f208(u64);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
// Emscripten runtime:
|
// Emscripten runtime:
|
||||||
// 1. Pre-run
|
// 1. Pre-run
|
||||||
|
|
@ -14,10 +20,8 @@ namespace flyff {
|
||||||
// 4. Call main
|
// 4. Call main
|
||||||
// 5. Post-run
|
// 5. Post-run
|
||||||
|
|
||||||
Neuz::Neuz() {
|
Neuz::Neuz() : movers(make_ref<MoverMap>(0x00032968)) {
|
||||||
// 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::instance() {
|
Neuz& Neuz::instance() {
|
||||||
|
|
@ -27,6 +31,9 @@ Neuz& Neuz::instance() {
|
||||||
wasm_rt_init();
|
wasm_rt_init();
|
||||||
// Initialise the client.
|
// Initialise the client.
|
||||||
flyff::raw::init();
|
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.
|
// Only init the module once.
|
||||||
initialised = true;
|
initialised = true;
|
||||||
}
|
}
|
||||||
|
|
@ -42,4 +49,11 @@ int Neuz::main() const {
|
||||||
// TODO: Fix arguments.
|
// TODO: Fix arguments.
|
||||||
return (*flyff::raw::main)(0, 0);
|
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
|
} // namespace flyff
|
||||||
|
|
@ -3,6 +3,8 @@
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <client.h>
|
#include <client.h>
|
||||||
|
|
||||||
|
#include "Mover.h"
|
||||||
|
|
||||||
namespace flyff {
|
namespace flyff {
|
||||||
namespace raw {
|
namespace raw {
|
||||||
static const auto& init = &Z_client_init;
|
static const auto& init = &Z_client_init;
|
||||||
|
|
@ -24,9 +26,13 @@ namespace flyff {
|
||||||
Neuz(Neuz const&) = delete;
|
Neuz(Neuz const&) = delete;
|
||||||
void operator=(Neuz const&) = delete;
|
void operator=(Neuz const&) = delete;
|
||||||
|
|
||||||
|
MoverMap const& movers;
|
||||||
|
|
||||||
// Execute the `main` function of the flyff-client.
|
// Execute the `main` function of the flyff-client.
|
||||||
int main() const;
|
int main() const;
|
||||||
|
|
||||||
|
Pointer<Mover> get_mover(const flyff::MoverID& id) const;
|
||||||
|
|
||||||
// Easy to implement: Just send a EmscriptenKeyboardEvent* to the registered function.
|
// Easy to implement: Just send a EmscriptenKeyboardEvent* to the registered function.
|
||||||
// void send_keydown();
|
// void send_keydown();
|
||||||
// void send_keyup();
|
// void send_keyup();
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,9 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <string>
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
template <const size_t kSize>
|
template <const size_t kSize>
|
||||||
class MinimumSize {
|
class MinimumSize {
|
||||||
|
|
@ -12,23 +13,13 @@ class MinimumSize {
|
||||||
#define STR_MERGE_IMPL(a, b) a##b
|
#define STR_MERGE_IMPL(a, b) a##b
|
||||||
#define STR_MERGE(a, b) STR_MERGE_IMPL(a, b)
|
#define STR_MERGE(a, b) STR_MERGE_IMPL(a, b)
|
||||||
#define MAKE_PAD(size) STR_MERGE(_pad, __COUNTER__)[size]
|
#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 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 {
|
class Memory {
|
||||||
wasm_rt_memory_t** memory;
|
wasm_rt_memory_t** memory;
|
||||||
|
|
@ -36,17 +27,20 @@ class Memory {
|
||||||
public:
|
public:
|
||||||
explicit Memory(wasm_rt_memory_t** mem) : memory(mem) {}
|
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]);
|
return reinterpret_cast<uintptr_t>(&(*memory)->data[offset]);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template <typename T>
|
||||||
T* to_outside(T* offset) const {
|
T* to_outside(const T* offset) {
|
||||||
return reinterpret_cast<T*>(
|
return reinterpret_cast<T*>(
|
||||||
to_outside(
|
to_outside(reinterpret_cast<uintptr_t>(offset)));
|
||||||
reinterpret_cast<uintptr_t>(offset)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -56,15 +50,76 @@ class Table {};
|
||||||
|
|
||||||
static const auto& kTable = &Z_clientZ_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>
|
template <typename T>
|
||||||
class Pointer {
|
class __attribute__((packed)) Pointer {
|
||||||
|
// Always located INSIDE the flyff module.
|
||||||
uintptr_t offset;
|
uintptr_t offset;
|
||||||
|
|
||||||
|
T* as_outside() const {
|
||||||
|
return reinterpret_cast<T*>(kMemory.to_outside(offset));
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
T* operator->() { return reinterpret_cast<T*>(kMemory.to_outside(offset)); }
|
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 {
|
union {
|
||||||
DEFINE_MEMBER(0x0, char*, text);
|
DEFINE_MEMBER(0x0, char*, text);
|
||||||
DEFINE_MEMBER(0x4, size_t, length);
|
DEFINE_MEMBER(0x4, size_t, length);
|
||||||
|
|
@ -76,7 +131,7 @@ class String {
|
||||||
const MinimumSize<12> __size;
|
const MinimumSize<12> __size;
|
||||||
};
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// This has to be const until strings can allocate...
|
// This has to be const until strings can allocate...
|
||||||
operator const std::string() const {
|
operator const std::string() const {
|
||||||
auto copy = *this;
|
auto copy = *this;
|
||||||
|
|
@ -101,4 +156,39 @@ typedef unsigned long long MoverID;
|
||||||
|
|
||||||
static_assert(sizeof(String) == sizeof(std::string),
|
static_assert(sizeof(String) == sizeof(std::string),
|
||||||
"String needs to be the same size as 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
|
}; // 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 {
|
struct Vector3 {
|
||||||
float x, y, z;
|
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 {
|
struct Matrix4 {
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ set_target_properties(
|
||||||
fugg-client
|
fugg-client
|
||||||
PROPERTIES LINK_FLAGS "\
|
PROPERTIES LINK_FLAGS "\
|
||||||
-lembind \
|
-lembind \
|
||||||
|
-g \
|
||||||
-sINITIAL_MEMORY=2048MB \
|
-sINITIAL_MEMORY=2048MB \
|
||||||
-fsanitize=undefined \
|
-fsanitize=undefined \
|
||||||
-sASSERTIONS=1 \
|
-sASSERTIONS=1 \
|
||||||
|
|
|
||||||
|
|
@ -45,7 +45,7 @@ const flyff::String get_text(const std::string& id) {
|
||||||
return *reinterpret_cast<flyff::String*>(result.get());
|
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
|
// Copy the message into a new auto ptr
|
||||||
auto message_ = std::make_unique<fugg::String>(message);
|
auto message_ = std::make_unique<fugg::String>(message);
|
||||||
auto color_ = std::make_unique<flyff::Color>(color);
|
auto color_ = std::make_unique<flyff::Color>(color);
|
||||||
|
|
@ -208,9 +208,26 @@ void write_chat_message(const std::string& message) {
|
||||||
send_packet(0x2000, packet);
|
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) {
|
void on_keyup_hook(int event_type, const EmscriptenKeyboardEvent* event, void* user_data) {
|
||||||
// [
|
// BracketLeft
|
||||||
if(event->keyCode == 219) {
|
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();
|
// send_logout();
|
||||||
// show_message(get_text("ids_textclient_fly_noskill"), { 0xFF, 0xFF, 0xFF });
|
// show_message(get_text("ids_textclient_fly_noskill"), { 0xFF, 0xFF, 0xFF });
|
||||||
|
|
||||||
|
|
@ -222,13 +239,6 @@ void on_keyup_hook(int event_type, const EmscriptenKeyboardEvent* event, void* u
|
||||||
// interact_target(1);
|
// 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;
|
// std::stringstream str;
|
||||||
// str << "Position: "
|
// str << "Position: "
|
||||||
// << player.position.x << ", "
|
// << player.position.x << ", "
|
||||||
|
|
@ -249,6 +259,95 @@ void on_keyup_hook(int event_type, const EmscriptenKeyboardEvent* event, void* u
|
||||||
// send_motion_packet(0x404, 0x04, 535);
|
// send_motion_packet(0x404, 0x04, 535);
|
||||||
// send_motion_packet(0x404, 0x11, 1);
|
// 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);
|
||||||
|
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
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 {
|
struct __attribute__((packed)) MoverHolder {
|
||||||
uintptr_t next;
|
uintptr_t next;
|
||||||
|
|
@ -265,8 +364,6 @@ void on_keyup_hook(int event_type, const EmscriptenKeyboardEvent* event, void* u
|
||||||
|
|
||||||
const auto& map = fugg::module_ref<MoverHolderMap>(0x00032968);
|
const auto& map = fugg::module_ref<MoverHolderMap>(0x00032968);
|
||||||
|
|
||||||
std::cout << "Got mover map with " << map.capacity << " movers." << std::endl;
|
|
||||||
|
|
||||||
float lowest_distance = 999999.f;
|
float lowest_distance = 999999.f;
|
||||||
uintptr_t closest = 0;
|
uintptr_t closest = 0;
|
||||||
flyff::MoverID closest_hash = 0;
|
flyff::MoverID closest_hash = 0;
|
||||||
|
|
@ -276,16 +373,15 @@ void on_keyup_hook(int event_type, const EmscriptenKeyboardEvent* event, void* u
|
||||||
const auto& current_ = fugg::module_ref<MoverHolder>(current);
|
const auto& current_ = fugg::module_ref<MoverHolder>(current);
|
||||||
const auto& mover = fugg::module_ref<flyff::Mover>(current_.mover);
|
const auto& mover = fugg::module_ref<flyff::Mover>(current_.mover);
|
||||||
|
|
||||||
auto dx = mover.position.x - player.position.x;
|
auto dx = std::abs(player.position.x - mover.position.x);
|
||||||
auto dz = mover.position.z - player.position.z;
|
auto dz = std::abs(player.position.z - mover.position.z);
|
||||||
|
|
||||||
auto squared = (dx * dx) + (dz * dz);
|
auto squared = (dx * dx) + (dz * dz);
|
||||||
auto d = std::sqrt(squared);
|
auto d = std::sqrt(squared);
|
||||||
|
|
||||||
|
if(mover.world != 0 &&
|
||||||
if(mover.type == ObjectType::Mover &&
|
mover.set_in_constructor == false &&
|
||||||
current_.hash != player_object_id &&
|
mover.type == ObjectType::Item &&
|
||||||
!mover.is_dead() &&
|
|
||||||
d < lowest_distance) {
|
d < lowest_distance) {
|
||||||
|
|
||||||
closest = current_.mover;
|
closest = current_.mover;
|
||||||
|
|
@ -299,18 +395,190 @@ void on_keyup_hook(int event_type, const EmscriptenKeyboardEvent* event, void* u
|
||||||
if(closest != 0) {
|
if(closest != 0) {
|
||||||
const auto& closest_ = fugg::module_ref<flyff::Mover>(closest);
|
const auto& closest_ = fugg::module_ref<flyff::Mover>(closest);
|
||||||
|
|
||||||
std::cout << closest_.name << " (of type " << closest_.type << ") is closest to the player." << std::endl;
|
player.selected_target = closest_hash;
|
||||||
|
player.move_toward_target = closest_hash;
|
||||||
|
player.move_target = closest_.position;
|
||||||
|
|
||||||
set_target(closest_hash);
|
set_target(closest_hash);
|
||||||
interact_target(1);
|
interact_target(1);
|
||||||
} else {
|
|
||||||
std::cout << "There is no one close" << std::endl;
|
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() {
|
void before_main_loop() {
|
||||||
|
bot_tick();
|
||||||
|
|
||||||
// auto& client = fugg::Client::instance();
|
// auto& client = fugg::Client::instance();
|
||||||
|
|
||||||
// const auto& test = translate("ids_textclient_cannot_dropmoney");
|
// const auto& test = translate("ids_textclient_cannot_dropmoney");
|
||||||
|
|
|
||||||
Reference in New Issue