Added a shit ton

Added Constants for object state found in SourceFlyff
This commit is contained in:
Knaapchen 2022-10-17 14:11:41 +02:00
parent ee2608a460
commit ce380a92f6
9 changed files with 528 additions and 165 deletions

View File

@ -7,50 +7,52 @@
#include <bitset>
#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<MovementFlags>(static_cast<uint32_t>(x) &
static_cast<uint32_t>(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>, 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<uintptr_t>, 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<InventoryItem>, inventory);
DEFINE_MEMBER(860, Vector<InventoryItem>, 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<FunctionPointer<int32_t, Pointer<Mover>>>(vtable->get_level);
// return fn(Pointer<Mover>(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<FunctionPointer<int32_t, Pointer<Mover>>>(vtable->get_gender);
// return fn(Pointer<Mover>(this));
// }
// bool prevents_pickup_emote() const {
// DEFINE_MEMBER(1806, uint16_t, pickup_flags);
// // Returns true if in attack animation

View File

@ -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<MoverMap>(raw::MOVER_MAP)),
player(make_ref<Pointer<Mover>>(raw::PLAYER)),
messages_ui(make_ref<Pointer<uintptr_t>>(raw::MESSAGES_UI)),
announcements_ui(make_ref<Pointer<uintptr_t>>(raw::ANNOUNCEMENTS_UI)),
player_object_id(make_ref<MoverID>(raw::PLAYER_OBJECT_ID)) {}
Neuz& Neuz::instance() {
@ -100,4 +107,25 @@ void Neuz::show_message(const std::string& message,
fugg::RuntimePointer<flyff::Color>(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<fugg::String>(message);
auto color_ = std::make_unique<flyff::Color>(color);
raw::show_announcement(
static_cast<uintptr_t>(announcements_ui),
fugg::RuntimePointer<fugg::String>(message_.get()).as_raw(),
fugg::RuntimePointer<flyff::Color>(color_.get()).as_raw());
}
bool Neuz::is_valid_attack(const Pointer<Mover>& attacker,
const Pointer<Mover>& defender) const {
auto result = raw::w2c_f514(static_cast<uintptr_t>(attacker),
static_cast<uintptr_t>(defender));
return result != 0;
}
} // namespace flyff

View File

@ -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<uintptr_t>& messages_ui;
const Pointer<uintptr_t>& announcements_ui;
public:
static Neuz& instance();
@ -41,10 +42,17 @@ class Neuz {
int main() const;
const Pointer<Mover> 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<Mover>& attacker, const Pointer<Mover>& defender) const;
// Easy to implement: Just send a EmscriptenKeyboardEvent* to the registered
// function. void send_keydown(); void send_keyup(); void send_keypress();
};

136
flyff-api/src/Object.h Normal file
View File

@ -0,0 +1,136 @@
#pragma once
#include <cstdint>
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; //
};
};
};

View File

@ -5,6 +5,9 @@
#include <string>
#include <vector>
template<typename ReturnType, typename... Args>
using FunctionPointer = ReturnType(*)(Args...);
template <const size_t kSize>
class MinimumSize {
unsigned char __padding[kSize];
@ -31,10 +34,12 @@ class Memory {
return reinterpret_cast<uintptr_t>((*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<uintptr_t>(&(*memory)->data[offset]);
return offset != NULL ? reinterpret_cast<uintptr_t>(&(*memory)->data[offset]) : NULL;
}
template <typename T>
@ -65,9 +70,10 @@ class __attribute__((packed)) Pointer {
return reinterpret_cast<T*>(kMemory.to_outside(offset));
}
public:
Pointer() : offset(0) { }
Pointer(T* ptr) : offset(kMemory.to_inside(reinterpret_cast<uintptr_t>(ptr))) { }
public:
Pointer(T* ptr) : offset(ptr == nullptr ? 0 : kMemory.to_inside(reinterpret_cast<uintptr_t>(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<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);
os << reinterpret_cast<void*>(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<T*>(begin_);
}
T* end() {
return end_;
T* end() const {
return static_cast<T*>(end_);
}
// friend std::ostream& operator<<(std::ostream& os, const String& str) {

View File

@ -2,24 +2,59 @@
#include "core.h"
#include <iostream>
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<ItemProperty>, item);
DEFINE_MEMBER(36, Pointer<ItemProperty>, property);
DEFINE_MEMBER(60, uint32_t, index);
DEFINE_MEMBER(60, int32_t, index);
DEFINE_MEMBER(64, uint32_t, quantity);
const MinimumSize<96> __size;
};
};

View File

@ -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;

View File

@ -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<const MotionParam*>(&x),
*reinterpret_cast<const MotionParam*>(&y),
*reinterpret_cast<const MotionParam*>(&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<const MotionParam*>(&x),
// *reinterpret_cast<const MotionParam*>(&y),
// *reinterpret_cast<const MotionParam*>(&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<flyff::Mover>(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<flyff::ItemProperty*>(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<flyff::Mover> 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<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 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<flyff::Mover> 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<flyff::Mover> 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<flyff::Mover> 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<MoverHolderMap>(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<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) {
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<MoverHolderMap>(0x00033460);
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;
// neuz.player->move_toward_target = id;
interact_target(1);
}
flyff::Pointer<flyff::Mover> current_target;
flyff::Pointer<flyff::Mover> 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<uintptr_t*>(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<const MotionParam*>(&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<void*>(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;

View File

@ -4,6 +4,9 @@
#include <fugg.h>
#include <flyff.h>
#include <emscripten.h>
#include <emscripten/bind.h>
// #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;