Fixed bugs that arose when updating to 1.1.4

Refactored motion packet sending to use functions from the original client
This commit is contained in:
Knaapchen 2022-11-18 22:01:09 +01:00
parent 0037bcb3e1
commit cff2af6a0d
11 changed files with 286 additions and 105 deletions

View File

@ -6,7 +6,7 @@ add_library(
"include/flyff.h"
src/core.h
src/skill/SkillProperty.h
src/object/ObjectProperty.h src/item/ItemKind2.h src/item/ItemKind3.h src/item/Part.h src/item/InventoryItem.h src/object/mover/JobProperty.h src/object/mover/ParamID.h src/object/mover/MoverProperty.h src/object/mover/Rank.h src/object/mover/Element.h src/item/AttackRange.h)
src/object/ObjectProperty.h src/item/ItemKind2.h src/item/ItemKind3.h src/item/Part.h src/item/InventoryItem.h src/object/mover/JobProperty.h src/object/mover/ParamID.h src/object/mover/MoverProperty.h src/object/mover/Rank.h src/object/mover/Element.h src/item/AttackRange.h src/PacketHeader.h src/Action.h)
target_include_directories(flyff-api PUBLIC "include")
target_link_libraries(flyff-api PUBLIC flyff-client fugg-api)

View File

@ -12,6 +12,10 @@
#include "../src/skill/SkillID.h"
#include "../src/skill/SkillProperty.h"
#include "../src/object/mover/BuffType.h"
#include "../src/PacketHeader.h"
#include "../src/Action.h"
#include "../src/import.h"
#define FN_CAST(return_type, ...) return_type (*)(__VA_ARGS__)

113
flyff-api/src/Action.h Normal file
View File

@ -0,0 +1,113 @@
//
// Created by main on 18-11-22.
//
#ifndef FUGG_ACTION_H
#define FUGG_ACTION_H
#include <cstdint>
namespace flyff {
enum class Action : uint32_t {
Move,
StopMove,
Jump,
Emote,
Target,
Skill,
MoveForward,
MoveBackward,
TurnLeft,
TurnRight,
StopTurn,
LookDown,
LookUp,
StopLook,
StopMoveFly,
FlyFreeMove,
Follow,
Interact,
ToggleWalk = 0x14,
// Charged attacks from bows and wands.
ReleaseChargedAttack,
// Send when your are being blocked from moving.
Correction = 0x18,
};
static std::ostream &operator<<(std::ostream &os, const Action &action) {
switch(action) {
case Action::Move:
os << "Move";
break;
case Action::StopMove:
os << "StopMove";
break;
case Action::Jump:
os << "Jump";
break;
case Action::Emote:
os << "Emote";
break;
case Action::Target:
os << "Target";
break;
case Action::Skill:
os << "Skill";
break;
case Action::MoveForward:
os << "MoveForward";
break;
case Action::MoveBackward:
os << "MoveBackward";
break;
case Action::TurnLeft:
os << "TurnLeft";
break;
case Action::TurnRight:
os << "TurnRight";
break;
case Action::StopTurn:
os << "StopTurn";
break;
case Action::LookDown:
os << "LookDown";
break;
case Action::LookUp:
os << "LookUp";
break;
case Action::StopLook:
os << "StopLook";
break;
case Action::StopMoveFly:
os << "StopMoveFly";
break;
case Action::FlyFreeMove:
os << "FlyFreeMove";
break;
case Action::Follow:
os << "Follow";
break;
case Action::Interact:
os << "Interact";
break;
case Action::ToggleWalk:
os << "ToggleWalk";
break;
case Action::ReleaseChargedAttack:
os << "ReleaseChargedAttack";
break;
case Action::Correction:
os << "Correction";
break;
default:
os << "Action(" << static_cast<unsigned>(action) << ")";
break;
}
return os;
}
};
#endif //FUGG_ACTION_H

View File

@ -1,3 +1,11 @@
#include <cassert>
#include <emscripten/html5.h>
#include <string>
#include <vector>
#include <sstream>
#include <memory>
#include <iostream>
#include <flyff.h>
#include "Neuz.h"
#include <client.h>
@ -35,6 +43,8 @@ namespace flyff {
extern u32 w2c_f516(u32, u32);
// CProject::GetSkillProp()
extern u32 w2c_f441(u32, u32);
// send_motion_packet
extern u32 w2c_f272(u32, u32, u64, u64, u64, u64);
};
static const auto &get_mover_node = w2c_f207;
@ -43,6 +53,7 @@ namespace flyff {
static const auto &show_announcement = w2c_f606;
static const auto &can_attack_target = w2c_f516;
static const auto &get_skill_prop = w2c_f441;
static const auto &send_motion_packet = w2c_f272;
}; // namespace raw
// Emscripten runtime:
@ -135,7 +146,7 @@ namespace flyff {
}
bool Neuz::is_valid_attack(const Pointer<Mover> &attacker,
const Pointer<Mover> &defender) const {
const Pointer<Mover> &defender) {
auto result = raw::can_attack_target(static_cast<u32>(attacker),
static_cast<u32>(defender));
@ -146,4 +157,11 @@ namespace flyff {
Pointer<SkillProperty> Neuz::get_skill_property(const SkillID &id) {
return Pointer<SkillProperty>(raw::get_skill_prop(static_cast<uint32_t>(id), 1));
}
uint32_t
Neuz::send_motion_packet(const Pointer<Mover> &mover, Action action, unsigned long long arg0,
unsigned long long arg1,
unsigned long long arg2, unsigned long long arg3) {
return raw::send_motion_packet(static_cast<u32>(mover), static_cast<u32>(action), arg0, arg1, arg2, arg3);
}
} // namespace flyff

View File

@ -3,12 +3,18 @@
#include <client.h>
#include <cstdint>
#include <fugg.h>
#include <flyff.h>
#include <vector>
#include "skill/SkillID.h"
#include "skill/SkillProperty.h"
#include "object/mover/Mover.h"
#include "PacketHeader.h"
#include "Action.h"
namespace flyff {
// Find this in send_packet. The hash that is applied to game packet headers.
const uint32_t PACKET_HEADER_HASH = 0x644aac00;
@ -58,10 +64,13 @@ namespace flyff {
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;
static bool is_valid_attack(const Pointer<Mover> &attacker, const Pointer<Mover> &defender) ;
static Pointer<SkillProperty> get_skill_property(const SkillID& id) ;
static Pointer<SkillProperty> get_skill_property(const SkillID &id);
static uint32_t send_motion_packet(const Pointer<Mover> &mover, Action action, unsigned long long arg0,
unsigned long long arg1,
unsigned long long arg2, unsigned long long arg3);
// Easy to implement: Just send a EmscriptenKeyboardEvent* to the registered
// function. void send_keydown(); void send_keyup(); void send_keypress();
};

View File

@ -0,0 +1,26 @@
//
// Created by main on 18-11-22.
//
#ifndef FUGG_PACKETHEADER_H
#define FUGG_PACKETHEADER_H
#include <cstdint>
namespace flyff {
enum class PacketHeader : uint32_t {
Logout = 0x403,
Motion = 0x404,
InventoryUseItem = 0x410,
NpcOpenDialog = 0x413,
InventorySellItem = 0x419,
OpenBank = 0x437,
ChangeChannel = 0x45b,
ChatMessage = 0x2000,
InventoryMoveItem = 0x2001,
OpenGuildWarehouse = 0x201b,
};
};
#endif //FUGG_PACKETHEADER_H

View File

@ -190,9 +190,10 @@ namespace flyff {
DEFINE_MEMBER(3248, const Timestamp, last_refresher_time);
DEFINE_MEMBER(3256, const Timestamp, last_vitaldrink_time);
DEFINE_MEMBER(3424, Vector<Skill>, skills);
DEFINE_MEMBER(3416, Vector<Skill>, skills);
DEFINE_MEMBER(3548, int, pickup_pet_inventory_index);
DEFINE_MEMBER(3528, int, pickup_pet_object_id);
DEFINE_MEMBER(3540, int, pickup_pet_inventory_index);
const MinimumSize<4096> size;
};
@ -259,7 +260,7 @@ namespace flyff {
src_speed = src_speed + (src_speed * (static_cast<float>(adj_value) / 100.0f));
}
return src_speed <= 0. ? 0. : src_speed;
return src_speed <= 0 ? 0 : src_speed;
}
uint32_t get_max_hp() const {
@ -267,7 +268,7 @@ namespace flyff {
auto result = get_param(ParamID::MaxHitPoint, get_max_origin_hp());
auto percent = get_param(ParamID::MaxHitPointScaling, 0);
factor += (float) percent / (float) 100;
factor += static_cast<float>(percent) / 100.f;
result = static_cast<float>(result) * factor;
return result;

View File

@ -511,7 +511,7 @@ static u32 w2c_f268(u32);
static u32 w2c_f269(u32);
static void w2c_f270(u32, u32);
static void w2c_f271(u32, u32);
static u32 w2c_f272(u32, u32, u64, u64, u64, u64);
u32 w2c_f272(u32, u32, u64, u64, u64, u64);
static u32 w2c_f273(u32);
static u32 w2c_f274(u32, u32, u32);
static void w2c_f275(u32);
@ -44427,7 +44427,7 @@ static void w2c_f271(u32 w2c_p0, u32 w2c_p1) {
FUNC_EPILOGUE;
}
static u32 w2c_f272(u32 w2c_p0, u32 w2c_p1, u64 w2c_p2, u64 w2c_p3, u64 w2c_p4, u64 w2c_p5) {
u32 w2c_f272(u32 w2c_p0, u32 w2c_p1, u64 w2c_p2, u64 w2c_p3, u64 w2c_p4, u64 w2c_p5) {
u32 w2c_l6 = 0, w2c_l7 = 0, w2c_l8 = 0, w2c_l9 = 0, w2c_l10 = 0, w2c_l11 = 0, w2c_l12 = 0, w2c_l13 = 0,
w2c_l14 = 0, w2c_l15 = 0, w2c_l16 = 0, w2c_l17 = 0, w2c_l18 = 0, w2c_l19 = 0, w2c_l20 = 0;
u64 w2c_l24 = 0;
@ -1031848,9 +1031848,24 @@ void w2c_f2286(u32 w2c_p0) {
w2c_i0 = w2c_p0;
w2c_i0 = i32_load((&w2c_memory), (u64)(w2c_i0) + 4u);
w2c_l4 = w2c_i0;
const uintptr_t end = w2c_l4;
w2c_i1 = w2c_p0;
w2c_i1 = i32_load((&w2c_memory), (u64)(w2c_i1));
w2c_l2 = w2c_i1;
const uintptr_t begin = w2c_l2;
const size_t length = end - begin;
const unsigned char* data = &(&w2c_memory)->data[begin];
printf("Finalizing packet of length %zd: ", length);
for(int i = 0; i < length; i++) {
printf("%02X ", data[i]);
}
printf("\n");
w2c_i0 -= w2c_i1;
w2c_l7 = w2c_i0;
w2c_i0 = 9u;

View File

@ -1,5 +1,4 @@
#include "Client.h"
#include "BuffType.h"
#include <flyff.h>
@ -7,6 +6,13 @@
#include <memory>
#include <sstream>
#include <vector>
#include <string>
#include <emscripten/html5.h>
#include <cassert>
template<typename T>
void packet_push(std::vector<uint8_t> &packet, const T &value, std::vector<uint8_t>::iterator offset) {
union ToBytes {
@ -36,10 +42,15 @@ namespace fugg {
return instance;
}
void Client::send_packet(const uint32_t &id, std::vector<uint8_t> payload) const {
const uint32_t header = id < 0x400 ? id : id ^ flyff::PACKET_HEADER_HASH;
void Client::send_packet(const flyff::PacketHeader &header, std::vector<uint8_t> payload) {
// constexpr auto npc_interact = flyff::PACKET_HEADER_HASH ^ 0x644a8c23;
// constexpr auto npc_dialog = flyff::PACKET_HEADER_HASH ^ 0x644aa813;
// constexpr auto open_guild_bank = flyff::PACKET_HEADER_HASH ^ 0x644a8c1b;
// constexpr auto change_channel = flyff::PACKET_HEADER_HASH ^ 0x644aa85b;
// constexpr auto open_bank = flyff::PACKET_HEADER_HASH ^ 0x644aa837;
const auto id = static_cast<unsigned>(header);
// Add header
packet_push(payload, header, std::begin(payload));
packet_push<uint32_t>(payload, id < 0x400 ? id : id ^ flyff::PACKET_HEADER_HASH, std::begin(payload));
struct Vector {
uintptr_t begin;
@ -66,7 +77,7 @@ namespace fugg {
}
void Client::send_logout() const {
send_packet(0x403, {});
send_packet(flyff::PacketHeader::Logout, {});
}
void Client::send_move_item_in_inventory(const uint32_t &from_slot, const uint32_t &to_slot) const {
@ -75,7 +86,7 @@ namespace fugg {
packet_push<uint32_t>(packet, from_slot);
packet_push<uint32_t>(packet, to_slot);
send_packet(0x2001, packet);
send_packet(flyff::PacketHeader::InventoryMoveItem, packet);
}
void Client::send_use_item_in_inventory(const uint32_t &slot) const {
@ -85,61 +96,63 @@ namespace fugg {
// Unknown yet
packet_push<uint32_t>(packet, 0);
send_packet(0x410, packet);
send_packet(flyff::PacketHeader::InventoryUseItem, packet);
}
void Client::send_motion_packet(const uint32_t &action, unsigned long long param0, unsigned long long param1,
void Client::send_motion_packet(const flyff::Action &action, unsigned long long param0, unsigned long long param1,
unsigned long long param2, unsigned long long param3) const {
const int32_t motion_packet_id = 0x404;
const auto &neuz = flyff::Neuz::instance();
const auto &client = fugg::Client::instance();
if (!neuz.player) return;
if (!client.player) return;
auto result = flyff::Neuz::send_motion_packet(client.player, action, param0, param1, param2, param3);
std::vector<uint8_t> packet;
std::cout << "Result from action " << action << " is " << result << std::endl;
uint8_t param_flags = 0;
if (param0 != 0) param_flags |= 1;
if (param1 != 0) param_flags |= 2;
if (param2 != 0) param_flags |= 4;
if (param3 != 0) param_flags |= 8;
packet_push<flyff::Vector3>(packet, neuz.player->position);
packet_push<uint8_t>(packet, action);
packet_push<uint8_t>(packet, param_flags);
packet_push(packet, neuz.player->server_tick);
if (param0 != 0) packet_push<unsigned long long>(packet, param0);
if (param1 != 0) packet_push<unsigned long long>(packet, param1);
if (param2 != 0) packet_push<unsigned long long>(packet, param2);
if (param3 != 0) packet_push<unsigned long long>(packet, param3);
send_packet(motion_packet_id, packet);
// std::vector<uint8_t> packet;
//
// uint8_t param_flags = 0;
// if (param0 != 0) param_flags |= 1;
// if (param1 != 0) param_flags |= 2;
// if (param2 != 0) param_flags |= 4;
// if (param3 != 0) param_flags |= 8;
//
// packet_push<flyff::Vector3>(packet, client.player->position);
// packet_push<uint8_t>(packet, static_cast<uint8_t>(action));
// packet_push<uint8_t>(packet, param_flags);
// packet_push(packet, client.player->server_tick);
//
// if (param0 != 0) packet_push<unsigned long long>(packet, param0);
// if (param1 != 0) packet_push<unsigned long long>(packet, param1);
// if (param2 != 0) packet_push<unsigned long long>(packet, param2);
// if (param3 != 0) packet_push<unsigned long long>(packet, param3);
//
// send_packet(flyff::PacketHeader::Motion, packet);
}
void Client::send_set_target(const unsigned long long &id) const {
send_motion_packet(0x04, id);
send_motion_packet(flyff::Action::Target, id);
}
void Client::send_clear_target() const {
send_motion_packet(0x04, {});
send_motion_packet(flyff::Action::Target, 0);
}
void Client::send_interact_target(const unsigned long long &index) const {
send_motion_packet(0x11, index);
send_motion_packet(flyff::Action::Interact, index);
}
void Client::send_use_skill(const flyff::SkillID &id, unsigned long long unknown) const {
send_motion_packet(0x5, static_cast<unsigned long long>(id), unknown);
send_motion_packet(flyff::Action::Skill, static_cast<unsigned long long>(id), unknown);
}
void Client::send_follow_target(const unsigned long long &id) const {
send_motion_packet(0x10, id);
send_motion_packet(flyff::Action::Follow, id);
}
void Client::send_move_to(const double &x, const double &y, const double &z) const {
// Mouse click
send_motion_packet(
0,
flyff::Action::Move,
*reinterpret_cast<const unsigned long long *>(&x),
*reinterpret_cast<const unsigned long long *>(&y),
*reinterpret_cast<const unsigned long long *>(&z)
@ -147,10 +160,10 @@ namespace fugg {
}
void Client::send_correction(const double &speed) const {
send_motion_packet(0x18, *reinterpret_cast<const unsigned long long *>(&speed));
send_motion_packet(flyff::Action::Correction, *reinterpret_cast<const unsigned long long *>(&speed));
}
void Client::send_chat_message(const std::string &message) const {
void Client::send_chat_message(const std::string &message) {
std::vector<uint8_t> packet;
// Message length
packet_push<uint32_t>(packet, message.length());
@ -163,33 +176,20 @@ namespace fugg {
// Unknown 2
packet_push<uint32_t>(packet, 0);
send_packet(0x2000, packet);
send_packet(flyff::PacketHeader::ChatMessage, packet);
}
}
#include <unordered_set>
#include <unordered_map>
#include <vector>
#include <string>
#include <memory>
#include <emscripten/html5.h>
#include <cstddef>
#include <cassert>
flyff::Pointer<flyff::Mover::Buff>
find_skill_buff(const flyff::Pointer<flyff::Mover> &mover, const flyff::SkillID &skill_index) {
const auto &client = fugg::Client::instance();
for (const auto &buff: mover->buffs) {
if (buff->get_type() == flyff::BuffType::Skill) {
auto skill_property = reinterpret_cast<const flyff::SkillProperty *>(
static_cast<const flyff::ObjectProperty *>(buff->property)
);
auto skill_id = static_cast<flyff::SkillID>(buff->get_id());
if (!buff->is_removed && skill_property->id == skill_index)
if (!buff->is_removed && skill_id == skill_index)
return buff;
}
}
@ -221,13 +221,17 @@ check_rebuff(const flyff::Pointer<flyff::Mover> &buffer, const flyff::Pointer<fl
static_cast<const flyff::ObjectProperty *>(buff->property)
);
std::cout << "Current skill level: " << current_skill_level << ", Player skill level: " << player_skill_level << std::endl;
std::cout << "Current skill level: " << current_skill_level << ", Player skill level: "
<< player_skill_level << std::endl;
if (player_skill_level > current_skill_level) {
std::cout << neuz.get_text(buff_property->name) << " has to be applied because it is lower level than what " << buffer->name << " has." << std::endl;
std::cout << neuz.get_text(buff_property->name)
<< " has to be applied because it is lower level than what " << buffer->name << " has."
<< std::endl;
// Always apply a higher buff.
result.push_back(skill_index);
} else if (buff->get_time_remaining() < 30 * 1000 && player_skill_level >= current_skill_level) {
std::cout << neuz.get_text(buff_property->name) << " has to be applied because the buff is running out." << std::endl;
std::cout << neuz.get_text(buff_property->name) << " has to be applied because the buff is running out."
<< std::endl;
// Refresh the buff.
result.push_back(skill_index);
}
@ -571,10 +575,10 @@ void pickup_target(flyff::MoverID id, uint32_t action) {
if (!client.player)
return;
if (client.player->selected_target != id) {
client.player->selected_target = id;
// if (client.player->selected_target != id) {
// client.player->selected_target = id;
client.send_set_target(id);
}
// }
client.send_interact_target(action);
}
@ -586,35 +590,17 @@ void attack_target(flyff::MoverID id) {
const auto &target = client.get_mover(id);
assert(target);
if (client.player->selected_target != id) {
client.player->selected_target = id;
client.send_set_target(id);
client.send_set_target(id);
client.send_interact_target(1);
auto item = client.player->get_equipped_item(flyff::Part::MainHand);
assert(item);
// Maybe Wand too...
if (item->item_kind3 == flyff::ItemKind3::Bow) {
// Release the 'charged' shot immediatly.
client.send_motion_packet(flyff::Action::ReleaseChargedAttack);
}
if (client.player->attack_target != id) {
auto item = client.player->get_equipped_item(flyff::Part::MainHand);
assert(item);
auto range = client.player->get_attack_range(item->attack_range);
auto result = client.player->is_object_in_range(target, range);
client.show_message("Range=" + std::to_string(range) + ", result=" + std::to_string(result));
if (result == 0) {
client.player->move_toward_target = id;
client.player->arrival_range = range;
}
client.player->attack_target = id;
client.send_interact_target(1);
// Maybe Wand too...
if (item->item_kind3 == flyff::ItemKind3::Bow) {
// Release the 'charged' shot immediatly.
client.send_motion_packet(0x15);
}
}
}
flyff::MoverID current_target = 0;
@ -809,7 +795,6 @@ void attacker_script() {
} else if (monster && !monster->is_dead() && neuz.player->attack_target == 0) {
// Attack
attack_target(monster->object_id);
// neuz.player->attack_target = monster->object_id;
} else if ((!item || item->is_despawned) &&
(!monster || monster->is_dead())) {
std::cout << "No item, no target. Searching..." << std::endl;
@ -831,7 +816,7 @@ void attacker_script() {
}
}
// Only pickup if player has no pickup pet spawned.
if (client.player->pickup_pet_inventory_index == -1) {
if (client.player->pickup_pet_object_id == 0) {
// No item target and no attack target
current_pickup_item = find_next_item();
item = neuz.get_mover(current_pickup_item);

View File

@ -17,7 +17,7 @@ namespace fugg {
void operator=(Client const &) = delete;
void send_packet(const uint32_t &id, std::vector<uint8_t> payload) const;
static void send_packet(const flyff::PacketHeader &header, std::__2::vector<uint8_t> payload);
void send_logout() const;
@ -25,7 +25,7 @@ namespace fugg {
void send_use_item_in_inventory(const uint32_t &slot) const;
void send_motion_packet(const uint32_t &action, unsigned long long param0 = 0, unsigned long long param1 = 0,
void send_motion_packet(const flyff::Action &action, unsigned long long param0 = 0, unsigned long long param1 = 0,
unsigned long long param2 = 0, unsigned long long param3 = 0) const;
void send_set_target(const unsigned long long &id) const;
@ -41,7 +41,7 @@ namespace fugg {
void send_correction(const double& speed) const;
void send_move_to(const double &x, const double &y, const double &z) const;
void send_chat_message(const std::string &message) const;
static void send_chat_message(const std::string &message) ;
};

View File

@ -7,7 +7,7 @@
#include <emscripten.h>
#include <emscripten/bind.h>
// #include "client.h"
#include "Client.h"
#define TRACE_ALLOC 0
@ -67,13 +67,23 @@ void get_text(const std::string& text) {
std::cout << text << " = \"" << result << "\"" << std::endl;
}
uintptr_t to_outside(uint32_t ptr) {
uintptr_t to_outside(uintptr_t ptr) {
return fugg::wasm::kMemory.address_of(ptr);
}
void send_packet(uint32_t header, uintptr_t ptr, intptr_t length) {
const auto& bytes = reinterpret_cast<uint8_t*>(ptr);
std::vector<uint8_t> payload;
std::copy(&bytes[0], &bytes[length], std::back_inserter(payload));
fugg::Client::send_packet(static_cast<flyff::PacketHeader>(header), payload);
}
EMSCRIPTEN_BINDINGS(fugg) {
emscripten::function("get_text", &get_text);
emscripten::function("to_outside", &to_outside);
emscripten::function("send_packet", &send_packet);
};
int main() {