Added a shit ton
Added Constants for object state found in SourceFlyff
This commit is contained in:
parent
ee2608a460
commit
ce380a92f6
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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();
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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; //
|
||||
};
|
||||
};
|
||||
|
||||
};
|
||||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
Reference in New Issue