From ce380a92f699dcfbb0f94121ab74ea48a6c31b1c Mon Sep 17 00:00:00 2001 From: Knaapchen Date: Mon, 17 Oct 2022 14:11:41 +0200 Subject: [PATCH] Added a shit ton Added Constants for object state found in SourceFlyff --- flyff-api/src/Mover.h | 173 ++++++++++++++++++------- flyff-api/src/Neuz.cpp | 28 ++++ flyff-api/src/Neuz.h | 10 +- flyff-api/src/Object.h | 136 ++++++++++++++++++++ flyff-api/src/core.h | 26 ++-- flyff-api/src/item.h | 41 +++++- flyff-client/src/client.c | 8 +- fugg-client/src/client.cpp | 256 ++++++++++++++++++++++--------------- fugg-client/src/main.cpp | 15 +++ 9 files changed, 528 insertions(+), 165 deletions(-) create mode 100644 flyff-api/src/Object.h diff --git a/flyff-api/src/Mover.h b/flyff-api/src/Mover.h index 9e68955..99a4245 100644 --- a/flyff-api/src/Mover.h +++ b/flyff-api/src/Mover.h @@ -7,50 +7,52 @@ #include #include "ObjectType.h" +#include "Object.h" #include "core.h" #include "math.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(static_cast(x) & - static_cast(y)); -} - struct __attribute__((packed)) Mover { + using ObjectStateFlags = Object::StateFlags; + using ObjectState = Object::State; + + struct __attribute__((packed)) Vtable { + union { + DEFINE_MEMBER(52, u32, get_level); + DEFINE_MEMBER(56, u32, get_gender); + + const MinimumSize<220> __size; + }; + }; + + union { - DEFINE_MEMBER(0x18, flyff::Matrix4, world_matrix); + DEFINE_MEMBER(0x0, const Pointer, vtable); - DEFINE_MEMBER(152, flyff::Vector3, position); - DEFINE_MEMBER(164, flyff::Vector3, rotation); + DEFINE_MEMBER(0x18, Matrix4, world_matrix); - DEFINE_MEMBER(216, bool, set_in_constructor); + DEFINE_MEMBER(152, Vector3, position); + DEFINE_MEMBER(164, Vector3, rotation); - DEFINE_MEMBER(2020, const flyff::String, name); + DEFINE_MEMBER(188, Pointer, property); - DEFINE_MEMBER(1628, flyff::Vector3, move_target); + DEFINE_MEMBER(216, bool, is_despawned); + DEFINE_MEMBER(352, MoverID, object_id); - 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(2020, const String, name); + + DEFINE_MEMBER(1628, Vector3, move_target); + + DEFINE_MEMBER(1728, MoverID, move_toward_target); + DEFINE_MEMBER(1736, MoverID, last_attacked_target); + DEFINE_MEMBER(1744, 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); + DEFINE_MEMBER(1752, MoverID, attack_target); + DEFINE_MEMBER(1760, 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); + DEFINE_MEMBER(1768, MoverID, current_attack_target); + DEFINE_MEMBER(1776, MoverID, platform_standing_on); DEFINE_MEMBER(1820, uint32_t, server_tick); @@ -60,40 +62,121 @@ struct __attribute__((packed)) Mover { DEFINE_MEMBER(216, uint32_t, existence_check); - 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(1804, uint32_t, object_state); + DEFINE_MEMBER(1808, uint32_t, object_state_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, inventory); + DEFINE_MEMBER(860, Vector, inventory); const MinimumSize<4096> __size; }; + uint32_t get_state() const { + return object_state; + } + + uint32_t get_move_state() const { + return (object_state & ObjectState::MovementAll); + } + + uint32_t get_turn_state() const { + return (object_state & ObjectState::TurnAll); + } + + uint32_t get_look_state() const { + return (object_state & ObjectState::LookAll); + } + + uint32_t get_jump_state() const { + return (object_state & ObjectState::JumpAll); + } + + uint32_t get_attack_state() const { + return (object_state & ObjectState::AtkAll); + } + + uint32_t get_damage_state() const { + return (object_state & ObjectState::DmgAll); + } + + uint32_t get_action_state() const { + return (object_state & ObjectState::ActionAll); + } + + bool is_fly() const { + return (object_state_flags & ObjectStateFlags::Fly) != 0; + } + bool is_dead() const { - static constexpr uint8_t const& IsDeadMask = 8; - - return (is_dead_flags & IsDeadMask) != 0; + return (object_state & ObjectState::DieAll) != 0; } - bool is_walking() const { - return (movement_flags & MovementFlags::Walking) != MovementFlags::None; + bool is_sit() const { + return (object_state_flags & ObjectStateFlags::Sit) != 0; + } + // Whether the movement state is running, not if the Mover + // is actually moving. See `is_moving()` + bool is_run() const { + return (object_state_flags & ObjectStateFlags::Walk) == 0; + } + // Whether the movement state is walking, not if the Mover + // is actually moving. See `is_moving()` + bool is_walk() const { + return (object_state_flags & ObjectStateFlags::Walk) != 0; + } + // Normal action - No other commands have any effect during this action. + bool is_action() const { + return (object_state & ObjectState::ActionAll) != 0; } - bool is_flying() const { - return (movement_flags & MovementFlags::Flying) != MovementFlags::None; + bool is_moving() const { + return (get_move_state() == ObjectState::MoveForward || + get_move_state() == ObjectState::MoveBackward || + get_move_state() == ObjectState::Left || + get_move_state() == ObjectState::Right); } + bool is_jumping() const { + return (object_state & ObjectState::JumpAll) != 0; + } + + bool is_attacking() const { + return (object_state & ObjectState::AtkAll) != 0; + } + + bool is_damaged() const { + return (object_state & ObjectState::DmgAll) != 0; + } + + bool is_turning() const { + return (object_state & ObjectState::TurnAll) != 0; + } + + // int32_t get_level() { + // // The function itself works but I fear it returns wrong results. + // // Npc = 1 + // // Players = 0 + // const auto& fn = fugg::function_ref>>(vtable->get_level); + + // return fn(Pointer(this)); + // } + + // int32_t get_gender() { + // // The function itself works but I fear it returns wrong results. + // // Female player = 0 + // // Male player = 0 + // // Npc = 2 + // const auto& fn = fugg::function_ref>>(vtable->get_gender); + + // return fn(Pointer(this)); + // } + // bool prevents_pickup_emote() const { // DEFINE_MEMBER(1806, uint16_t, pickup_flags); // // Returns true if in attack animation diff --git a/flyff-api/src/Neuz.cpp b/flyff-api/src/Neuz.cpp index 293ab72..39bb49f 100644 --- a/flyff-api/src/Neuz.cpp +++ b/flyff-api/src/Neuz.cpp @@ -14,6 +14,7 @@ static const uintptr_t& PLAYER = WORLD + 4; static const uintptr_t& PLAYER_OBJECT_ID = 0x00035090; // The messages that are limited to 5 that are show temporarily. static const uintptr_t& MESSAGES_UI = 0x00036060; +static const uintptr_t& ANNOUNCEMENTS_UI = 0x00034e2c; static const uintptr_t& MOVER_MAP = 0x00033460; extern "C" { @@ -23,10 +24,15 @@ extern u32 w2c_f208(u64); extern void w2c_f167(u32, u32); // show_message extern void w2c_f340(u32, u32, u32); +// show_announcement +extern void w2c_f605(u32, u32, u32); +// can_attack_target +extern u32 w2c_f514(u32, u32); }; static const auto& get_text = w2c_f167; static const auto& show_message = w2c_f340; +static const auto& show_announcement = w2c_f605; }; // namespace raw // Emscripten runtime: @@ -40,6 +46,7 @@ Neuz::Neuz() : movers(make_ref(raw::MOVER_MAP)), player(make_ref>(raw::PLAYER)), messages_ui(make_ref>(raw::MESSAGES_UI)), + announcements_ui(make_ref>(raw::ANNOUNCEMENTS_UI)), player_object_id(make_ref(raw::PLAYER_OBJECT_ID)) {} Neuz& Neuz::instance() { @@ -100,4 +107,25 @@ void Neuz::show_message(const std::string& message, fugg::RuntimePointer(color_.get()).as_raw()); } +void Neuz::show_announcement(const std::string& message, + const flyff::Color& color) const { + if (!announcements_ui) return; + + // Copy the message into a new auto ptr + auto message_ = std::make_unique(message); + auto color_ = std::make_unique(color); + + raw::show_announcement( + static_cast(announcements_ui), + fugg::RuntimePointer(message_.get()).as_raw(), + fugg::RuntimePointer(color_.get()).as_raw()); +} + +bool Neuz::is_valid_attack(const Pointer& attacker, + const Pointer& defender) const { + auto result = raw::w2c_f514(static_cast(attacker), + static_cast(defender)); + + return result != 0; +} } // namespace flyff \ No newline at end of file diff --git a/flyff-api/src/Neuz.h b/flyff-api/src/Neuz.h index 7a9ce82..955ff0c 100644 --- a/flyff-api/src/Neuz.h +++ b/flyff-api/src/Neuz.h @@ -7,7 +7,7 @@ #include "Mover.h" namespace flyff { - +// Find this is f195_calls_websocket_send const uint32_t PACKET_HEADER_HASH = 0x644ab000; namespace raw { @@ -26,6 +26,7 @@ class Neuz { Neuz(); const Pointer& messages_ui; + const Pointer& announcements_ui; public: static Neuz& instance(); @@ -41,10 +42,17 @@ class Neuz { int main() const; const Pointer get_mover(const flyff::MoverID& id) const; + const flyff::String get_text(const std::string& id) const; + void show_message(const std::string& message, const flyff::Color& color = {0xFF, 0xFF, 0xFF}) const; + void show_announcement(const std::string& message, + const flyff::Color& color = {0xFF, 0xFF, 0xFF}) const; + + bool is_valid_attack(const Pointer& attacker, const Pointer& defender) const; + // Easy to implement: Just send a EmscriptenKeyboardEvent* to the registered // function. void send_keydown(); void send_keyup(); void send_keypress(); }; diff --git a/flyff-api/src/Object.h b/flyff-api/src/Object.h new file mode 100644 index 0000000..5e2394a --- /dev/null +++ b/flyff-api/src/Object.h @@ -0,0 +1,136 @@ +#pragma once + +#include + +namespace flyff { +struct __attribute__((packed)) Object { + struct StateFlags { + StateFlags() = delete; + + static constexpr uint32_t Combat = 0x00000001; // battle mode + static constexpr uint32_t Walk = 0x00000002; // walking mode + static constexpr uint32_t Sit = 0x00000004; // sitting state + static constexpr uint32_t Fly = 0x0000008; // flight mode + static constexpr uint32_t Acceleration = 0x00000010; // Acceleration status + static constexpr uint32_t Etc = 0x00000020; // custom motion + static constexpr uint32_t AccelerationTurn = 0x00000040; // Sharp turn. + static constexpr uint32_t Turbo = 0x00000080; // Turbo mode. + }; + + struct State { + State() = delete; + + static constexpr uint32_t None = 0x00000000; // Nothing. + + // stop/move + + // Standby + static constexpr uint32_t Stand = 0x00000001; + // Standby EX + static constexpr uint32_t Stand2 = 0x00000002; + // sit down + static constexpr uint32_t Sit = 0x00000003; + // walk forward + static constexpr uint32_t MoveForward = 0x00000004; + // Walk backwards + static constexpr uint32_t MoveBackward = 0x00000005; + // Walk sideways (horizontal movement) + static constexpr uint32_t Left = 0x0000006; + static constexpr uint32_t Right = 0x00000007; + // Pick up (things, etc.) + static constexpr uint32_t PickUp = 0x0000008; + // Walk horizontally left + static constexpr uint32_t MoveLeft = 0x00000009; + // Walk to the right of the span + static constexpr uint32_t MoveRight = 0x0000000a; + // Run in place + static constexpr uint32_t StopRun = 0x0000000b; + // All movement + static constexpr uint32_t MovementAll = 0x000000FF; + // Is there anything other than STAND? + static constexpr uint32_t NotStand = (MovementAll & (~Stand)); + + // turn left + static constexpr uint32_t TurnLeft = 0x00000100; + // right turn + static constexpr uint32_t TurnRight = 0x00000200; + static constexpr uint32_t TurnAll = 0x00000300; + // look up/down + static constexpr uint32_t LookUp = 0x00000400; + static constexpr uint32_t LookDown = 0x00000800; + static constexpr uint32_t LookAll = 0x00000C00; + + // jump + + // Jump before jump - Jump before + static constexpr uint32_t FJumpReady = 0x00001000; + // Jumping + static constexpr uint32_t FJump = 0x00002000; + // Falling + static constexpr uint32_t FFall = 0x00003000; + // Landing + static constexpr uint32_t FLand = 0x00004000; + // Jump before jump - Jump in place + static constexpr uint32_t SJump1 = 0x00005000; + // Jumping + static constexpr uint32_t SJump2 = 0x00006000; + // Falling + static constexpr uint32_t SJump3 = 0x00007000; + // Landing + static constexpr uint32_t SJump4 = 0x00008000; + // jump before jump - back jump + static constexpr uint32_t BJumpReady = 0x00009000; + // Jumping + static constexpr uint32_t BJump = 0x0000a000; + // Falling + static constexpr uint32_t BFall = 0x0000b000; + // Landing + static constexpr uint32_t BLand = 0x0000c000; + static constexpr uint32_t JumpAll = 0x0000F000; + + // attack + + // 1st hit attack in action + static constexpr uint32_t Atk1 = 0x00010000; + static constexpr uint32_t Atk2 = 0x00020000; // Double hit attack in action + static constexpr uint32_t Atk3 = 0x00030000; // ... + static constexpr uint32_t Atk4 = 0x00040000; // ... // Might be incorporated into the concept of "attacking" later.... + // wand attack + static constexpr uint32_t AtkMagic1 = 0x00050000; // wand attack in action + static constexpr uint32_t AtkRange1 = 0x00060000; // Ranged attack in action + static constexpr uint32_t Range3 = 0x00070000; // + static constexpr uint32_t Range4 = 0x00080000; // + // melee skill + static constexpr uint32_t AtkMeleeSkill = 0x00090000; // Melee combat skill in action + static constexpr uint32_t AtkRangeSkill = 0x000a0000; // Long range combat skill in action + static constexpr uint32_t AtkCasting1 = 0x000b0000; // Magic Casting #1 (Start) + static constexpr uint32_t AtkCasting2 = 0x000c0000; // Magic Casting 2 times (repeat.) + static constexpr uint32_t AtkMagicSkill = 0x000d0000; // Magic firing action. + static constexpr uint32_t SpecialAtk1 = 0x00100000; // Special Attack: Used by monsters. + static constexpr uint32_t SpecialAtk2 = 0x00200000; // Special Attack 2: Used by monsters. + static constexpr uint32_t AtkAll = 0x00FF0000; + //static constexpr uint32_t RANGE_ALL 0x0f000000 + + + // Dead state (dead state) + static constexpr uint32_t Dead = 0x08000000; + // Dead state + static constexpr uint32_t Disappear = 0x09000000; + // Resurrection 0xd = 1101 + static constexpr uint32_t Resurrection = 0x0C000000; + static constexpr uint32_t DeadReserved1 = 0x0D000000; + // Death - If the 0x00800000 bit is on, it is dead. + static constexpr uint32_t DieAll = 0x08000000; + // Both Hit & Die + static constexpr uint32_t DmgAll = 0x0F000000; + + // Normal action - No other commands have any effect during this action. + static constexpr uint32_t Collect = 0x10000000; // Collect. + static constexpr uint32_t Appear = 0x20000000; // Appearance scene. + static constexpr uint32_t Appear2 = 0x30000000; // Appearance 2 + static constexpr uint32_t Stun = 0x40000000; // Stun status. + static constexpr uint32_t ActionAll = 0xF0000000; // + }; +}; + +}; \ No newline at end of file diff --git a/flyff-api/src/core.h b/flyff-api/src/core.h index 2e0f743..18d2e2d 100644 --- a/flyff-api/src/core.h +++ b/flyff-api/src/core.h @@ -5,6 +5,9 @@ #include #include +template +using FunctionPointer = ReturnType(*)(Args...); + template class MinimumSize { unsigned char __padding[kSize]; @@ -31,10 +34,12 @@ class Memory { return reinterpret_cast((*memory)->data); } - uintptr_t to_inside(const uintptr_t offset) { return offset - start(); } + uintptr_t to_inside(const uintptr_t offset) { + return offset != NULL ? offset - start() : NULL; + } uintptr_t to_outside(const uintptr_t offset) { - return reinterpret_cast(&(*memory)->data[offset]); + return offset != NULL ? reinterpret_cast(&(*memory)->data[offset]) : NULL; } template @@ -65,9 +70,10 @@ class __attribute__((packed)) Pointer { return reinterpret_cast(kMemory.to_outside(offset)); } - public: Pointer() : offset(0) { } - Pointer(T* ptr) : offset(kMemory.to_inside(reinterpret_cast(ptr))) { } + + public: + Pointer(T* ptr) : offset(ptr == nullptr ? 0 : kMemory.to_inside(reinterpret_cast(ptr))) { } explicit Pointer(uintptr_t ptr) : offset(ptr) { } @@ -94,13 +100,13 @@ class __attribute__((packed)) Pointer { } explicit operator bool() const { - return offset != NULL; + return as_outside() != nullptr; } bool operator==(Pointer const& rhs) const { return offset == rhs.offset; } friend std::ostream& operator<<(std::ostream& os, const Pointer& ptr) { - os << "0x" << reinterpret_cast(ptr.offset); + os << reinterpret_cast(ptr.offset); return os; } }; @@ -165,12 +171,12 @@ class __attribute__((packed)) Vector { typedef const T* const_iterator; // This has to be const until strings can allocate... - T* begin() { - return begin_; + T* begin() const { + return static_cast(begin_); } - T* end() { - return end_; + T* end() const { + return static_cast(end_); } // friend std::ostream& operator<<(std::ostream& os, const String& str) { diff --git a/flyff-api/src/item.h b/flyff-api/src/item.h index ee3b7d3..97fd348 100644 --- a/flyff-api/src/item.h +++ b/flyff-api/src/item.h @@ -2,24 +2,59 @@ #include "core.h" +#include + namespace flyff { struct __attribute__((packed)) ItemProperty { + static constexpr uint32_t ITEM_CATEGORY_RECOVERY = 0xe; + + static constexpr uint32_t COOLDOWN_FOOD = 0x00; + static constexpr uint32_t COOLDOWN_REFRESHER = 0x03; + static constexpr uint32_t COOLDOWN_VITALDRINK = 0x04; + + static constexpr uint32_t RECOVERY_COOLDOWN_INDEX[] = { + 0x03, 0x04, 0x00, 0x00, 0x01 + }; + union { DEFINE_MEMBER(0, const flyff::String, model); - DEFINE_MEMBER(12, uint32_t, id); + DEFINE_MEMBER(12, const uint32_t, id); DEFINE_MEMBER(156, const flyff::String, name); DEFINE_MEMBER(168, const flyff::String, icon); DEFINE_MEMBER(180, const flyff::String, description); + + // Has to be bigger that 0 to be considered for cooldown. + DEFINE_MEMBER(112, const int32_t, cooldown_time); + + DEFINE_MEMBER(348, const uint32_t, category); + DEFINE_MEMBER(352, const uint32_t, sub_category); + + const MinimumSize<456> __size; }; + + bool is_food_item() { + static const uint32_t RECOVERY_SUB_CATEGORY_START = 1400; + + if(category == ITEM_CATEGORY_RECOVERY) { + const uint32_t cd = sub_category - RECOVERY_SUB_CATEGORY_START; + if(cd < 5) { + return RECOVERY_COOLDOWN_INDEX[cd] == COOLDOWN_FOOD; + } + } + + return false; + } }; struct __attribute__((packed)) InventoryItem { union { - DEFINE_MEMBER(36, Pointer, item); + DEFINE_MEMBER(36, Pointer, property); - DEFINE_MEMBER(60, uint32_t, index); + DEFINE_MEMBER(60, int32_t, index); DEFINE_MEMBER(64, uint32_t, quantity); + + const MinimumSize<96> __size; }; }; diff --git a/flyff-client/src/client.c b/flyff-client/src/client.c index 1cc70ba..7dc45d4 100644 --- a/flyff-client/src/client.c +++ b/flyff-client/src/client.c @@ -755,7 +755,7 @@ static u32 w2c_f510(u32); static u32 w2c_f511(u32, u32, f32); static u32 w2c_f512(u32); static void w2c_f513(u32); -static u32 w2c_f514(u32, u32); +u32 w2c_f514(u32, u32); static void w2c_f515(u32, u32); static void w2c_f516(u32, u32); static void w2c_f517(u32); @@ -846,7 +846,7 @@ static u32 w2c_f601(u32); static void w2c_f602(u32, u32); static void w2c_f603(u32, u32); static u32 w2c_f604(u32); -static void w2c_f605(u32, u32, u32); +void w2c_f605(u32, u32, u32); static void w2c_f606(u32, u32, u32); static u32 w2c_f607(u32, u32, u32, u32); static void w2c_f608(u32, u32, u32); @@ -143020,7 +143020,7 @@ static void w2c_f513(u32 w2c_p0) { FUNC_EPILOGUE; } -static u32 w2c_f514(u32 w2c_p0, u32 w2c_p1) { +u32 w2c_f514(u32 w2c_p0, u32 w2c_p1) { u32 w2c_l2 = 0, w2c_l3 = 0, w2c_l4 = 0, w2c_l5 = 0; f32 w2c_l6 = 0; FUNC_PROLOGUE; @@ -167914,7 +167914,7 @@ static u32 w2c_f604(u32 w2c_p0) { return w2c_i0; } -static void w2c_f605(u32 w2c_p0, u32 w2c_p1, u32 w2c_p2) { +void w2c_f605(u32 w2c_p0, u32 w2c_p1, u32 w2c_p2) { u32 w2c_l3 = 0, w2c_l4 = 0, w2c_l5 = 0, w2c_l6 = 0, w2c_l7 = 0, w2c_l8 = 0, w2c_l9 = 0, w2c_l10 = 0, w2c_l11 = 0; f32 w2c_l12 = 0; diff --git a/fugg-client/src/client.cpp b/fugg-client/src/client.cpp index 266538a..6d5bb8e 100644 --- a/fugg-client/src/client.cpp +++ b/fugg-client/src/client.cpp @@ -138,19 +138,20 @@ void clear_target() { send_motion_packet(0x04); } -void interact_target(const unsigned long long& id) { - send_motion_packet(0x11, id); +void interact_target(const unsigned long long& index) { + send_motion_packet(0x11, index); } -void move_to(const float& x, const float& y, const float& z) { - // Mouse click - send_motion_packet( - 0, - *reinterpret_cast(&x), - *reinterpret_cast(&y), - *reinterpret_cast(&z) - ); -} +// 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 @@ -196,11 +197,45 @@ void on_keyup_hook(int event_type, const EmscriptenKeyboardEvent* event, void* u } else { if(!neuz.player) return; - // const auto& player = fugg::module_ref(player_pointer); - - // for(flyff::InventoryItem* item : player.inventory) { - // std::cout << get_text(item.item->name) << std::endl; - // } + const auto& player = *neuz.player; + + neuz.show_announcement("Hello world!", { 0xFF, 0, 0 }); + + auto current = neuz.movers.first; + do { + const auto& mover = current->mover; + + if(mover->type == ObjectType::Mover) { + // int level = mover->get_level(); + + std::cout << neuz.get_text(mover->name) << ": " + << (mover->is_dead() ? "Dead" : "Not dead") << ", " + << (mover->is_fly() ? "Flying" : "Not flying") << ", " + << (mover->is_jumping() ? "Jumping" : "Not jumping") << ", " + << (mover->is_moving() ? "Moving" : "Not moving") + << std::endl; + } + + current = current->next; + } while(current); + + // auto items = player.inventory.begin(); + // auto length = ((uintptr_t)player.inventory.end() - (uintptr_t)player.inventory.begin()) / 0x60; + + // std::cout << length << " items!" << std::endl; + // for(auto i = 0; i < length; i++) { + // if(items[i].index != -1) { + // // std::cout << items[i].index << std::endl; + // std::cout << "(Property address: " << static_cast(items[i].property) << ", " + // << "Item address: " << &items[i] << ") " + // << neuz.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 << ", " + // << "Is this food ? " << (items[i].property->is_food_item() ? "Yes" : "No") + // << std::endl; + // } + // } } } } @@ -210,16 +245,18 @@ flyff::Pointer attack_next_target(flyff::Vector3 const& start_posi if(!neuz.player) return nullptr; + // Found in the code somewhere. + static constexpr float max_distance = 144.; + float lowest_distance = std::numeric_limits::max(); flyff::Pointer 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 dy = std::abs(mover->position.y - start_position.y); auto dz = std::abs(mover->position.z - start_position.z); auto squared = (dx * dx) + (dy * dy) + (dz * dz); @@ -227,17 +264,16 @@ flyff::Pointer attack_next_target(flyff::Vector3 const& start_posi if(mover->type == ObjectType::Mover && current->hash != neuz.player_object_id && - !mover->is_dead()) { + !mover->is_dead() && + d <= max_distance) { // If it's a monster that has me targetted if(mover->last_attacked_target == neuz.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; } } @@ -246,12 +282,10 @@ flyff::Pointer attack_next_target(flyff::Vector3 const& start_posi } while(current); if(closest) { - neuz.player->selected_target = closest_hash; - neuz.player->move_toward_target = closest_hash; - neuz.player->attack_target = closest_hash; - neuz.player->follow_target = closest_hash; + neuz.player->selected_target = closest->object_id; + set_target(closest->object_id); - set_target(closest_hash); + neuz.player->move_toward_target = closest->object_id; interact_target(1); return closest; @@ -260,7 +294,7 @@ flyff::Pointer attack_next_target(flyff::Vector3 const& start_posi return nullptr; } -const flyff::Mover* pickup_next_item() { +const flyff::Mover* find_next_item() { const auto& neuz = flyff::Neuz::instance(); if(!neuz.player) return nullptr; @@ -281,7 +315,7 @@ const flyff::Mover* pickup_next_item() { const auto& map = fugg::module_ref(0x00033460); - float lowest_distance = 999999.f; + float lowest_distance = 32.f; uintptr_t closest = 0; flyff::MoverID closest_hash = 0; @@ -297,7 +331,7 @@ const flyff::Mover* pickup_next_item() { auto d = std::sqrt(squared); if(mover.world != 0 && - mover.set_in_constructor == false && + mover.is_despawned == false && mover.type == ObjectType::Item && d < lowest_distance) { @@ -312,52 +346,26 @@ const flyff::Mover* pickup_next_item() { if(closest != 0) { const auto& closest_ = fugg::module_ref(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) { +void interact(const flyff::MoverID& id) { + const auto& neuz = flyff::Neuz::instance(); - struct __attribute__((packed)) MoverHolder { - uintptr_t next; - unsigned int list_index; - unsigned long long hash; - uintptr_t mover; - }; + if(!neuz.player) + return; - struct __attribute__((packed)) MoverHolderMap { - uintptr_t buckets; - size_t capacity; - uintptr_t first; - }; + // neuz.player->selected_target = id; + set_target(id); - const auto& map = fugg::module_ref(0x00033460); - - auto current = map.first; - do { - const auto& current_ = fugg::module_ref(current); - const auto& mover = fugg::module_ref(current_.mover); - - if(&mover == ptr) { - return true; - } - - current = current_.next; - } while(current != 0); - - return false; + // neuz.player->move_toward_target = id; + interact_target(1); } -flyff::Pointer current_target; +flyff::Pointer current_target = nullptr; flyff::Mover const* current_pickup_item = nullptr; void bot_tick() { @@ -366,52 +374,96 @@ void bot_tick() { if(!neuz.player) return; - if(is_running) { + if(is_running) { + if(neuz.player->is_dead()) { + neuz.show_message("Player is dead, stopping...", {0xFF, 0x00, 0x00}); + is_running = false; + return; + } - 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 - neuz.show_message("Waiting for pickup"); - } else { - neuz.show_message("Picked up, waiting for ready"); - - if((neuz.player->pickup_flags & 0x8ff) == 0 && neuz.player->current_animation == 0) { - neuz.show_message("Picking up done."); + // if is_idle: + // if item_target: + // pickup_item() + // elif attacK_target: + // attack_target() - current_pickup_item = pickup_next_item(); - if(current_pickup_item != nullptr) { - neuz.show_message("Picking up"); - } + if(neuz.player->get_move_state() == 1 && + !neuz.player->is_attacking()) { + if(current_pickup_item != nullptr && !current_pickup_item->is_despawned && neuz.player->move_toward_target == 0) { + // Pickup + interact(current_pickup_item->object_id); + } else if(current_target && !current_target->is_dead() && neuz.player->attack_target == 0) { + // Attack + interact(current_target->object_id); + // neuz.player->attack_target = current_target->object_id; + } else if((current_pickup_item == nullptr || current_pickup_item->is_despawned) && + (!current_target || current_target->is_dead())) { + std::cout << "No item, no target. Searching..." << std::endl; + // No item target and no attack target + current_pickup_item = find_next_item(); + if(current_pickup_item != nullptr) { + // flyff::ItemProperty* prop = (flyff::ItemProperty*)static_cast(current_pickup_item->property); + + std::string str = "Picking up "; + std::cout << str << std::endl; + // str.append(prop->name); + + interact(current_pickup_item->object_id); + + neuz.show_message(str); + return; } - // Maybe some confirmation... - // send_motion_packet(0x01, *reinterpret_cast(&player.rotation.y)); - } - } else if(current_target == nullptr) { - if(neuz.player->pickup_things != 1) - return; + current_target = attack_next_target(start_position); - current_pickup_item = nullptr; - current_target = attack_next_target(start_position); + if(current_target) { + std::string str = "Attacking "; + str.append(current_target->name); - if(current_target) { - std::string str = "Attacking "; - str.append(current_target->name); + std::cout << str << std::endl; - neuz.show_message(str); - } else { - neuz.show_message("Unable to find target."); - } - } else if(current_target->is_dead()) { - current_target = nullptr; - - current_pickup_item = pickup_next_item(); - if(current_pickup_item != nullptr) { - neuz.show_message("Picking up"); + interact(current_target->object_id); + neuz.player->attack_target = current_target->object_id; + + neuz.show_message(str); + } else { + neuz.show_message("Unable to find target."); + } } } + + // static constexpr uint32_t PICKUP = flyff::Object::State::AtkAll | flyff::Object::State::Dead; + + // if((current_pickup_item != nullptr && + // !current_pickup_item->is_despawned) || + // (neuz.player->object_state & PICKUP) != 0) { + // // Wait + // std::cout << "ObjectSTate & Pickup = " << reinterpret_cast(neuz.player->object_state & PICKUP) << std::endl; + // } else if(current_target == nullptr) { + // current_pickup_item = pickup_next_item(); + // if(current_pickup_item != nullptr) { + // neuz.show_message("Picking up"); + // return; + // } + + // current_target = attack_next_target(start_position); + + // if(current_target) { + // std::string str = "Attacking "; + // str.append(current_target->name); + + // neuz.show_message(str); + // } else { + // neuz.show_message("Unable to find target."); + // } + // } else if(current_target->is_dead()) { + // current_target = nullptr; + + // current_pickup_item = pickup_next_item(); + // if(current_pickup_item != nullptr) { + // neuz.show_message("Picking up"); + // } + // } } else { // Reset current target is not running. current_target = nullptr; diff --git a/fugg-client/src/main.cpp b/fugg-client/src/main.cpp index 85f4a9d..7e8a6a4 100644 --- a/fugg-client/src/main.cpp +++ b/fugg-client/src/main.cpp @@ -4,6 +4,9 @@ #include #include +#include +#include + // #include "client.h" #define TRACE_ALLOC 0 @@ -57,6 +60,18 @@ void free (void *__ptr) { } } +void get_text(std::string text) { + const auto& neuz = flyff::Neuz::instance(); + + const auto& result = neuz.get_text(text); + + std::cout << text << " = \"" << result << "\"" << std::endl; +} + +EMSCRIPTEN_BINDINGS(fugg) { + emscripten::function("get_text", &get_text); +}; + int main() { using flyff::Neuz;