完善客户端功能并同步差距文档
This commit is contained in:
@@ -17,6 +17,9 @@
|
||||
#include <godot_cpp/classes/file_access.hpp>
|
||||
#include <godot_cpp/variant/array.hpp>
|
||||
#include <godot_cpp/variant/dictionary.hpp>
|
||||
#include <godot_cpp/variant/packed_int32_array.hpp>
|
||||
|
||||
#include <combo_table.h>
|
||||
|
||||
using namespace godot;
|
||||
|
||||
@@ -47,6 +50,11 @@ void Metin2AnimPlayer::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("get_accumulation"), &Metin2AnimPlayer::get_accumulation);
|
||||
ClassDB::bind_method(D_METHOD("get_events"), &Metin2AnimPlayer::get_events);
|
||||
ClassDB::bind_method(D_METHOD("get_loop_data"), &Metin2AnimPlayer::get_loop_data);
|
||||
ClassDB::bind_method(D_METHOD("get_motion_data"), &Metin2AnimPlayer::get_motion_data);
|
||||
ClassDB::bind_static_method("Metin2AnimPlayer",
|
||||
D_METHOD("parse_combo_tables", "py_path"), &Metin2AnimPlayer::parse_combo_tables);
|
||||
ClassDB::bind_static_method("Metin2AnimPlayer",
|
||||
D_METHOD("make_combo_key", "motion_mode", "combo_type"), &Metin2AnimPlayer::make_combo_key);
|
||||
|
||||
// Fired when playback time crosses a .msa MotionEventData entry.
|
||||
ADD_SIGNAL(MethodInfo("motion_event",
|
||||
@@ -187,6 +195,85 @@ Dictionary Metin2AnimPlayer::get_loop_data() const {
|
||||
return d;
|
||||
}
|
||||
|
||||
// CLIENT-GAP §3.3 / §3.5 — the currently-loaded .msa's ComboInputData / AttackingData.
|
||||
// `next_combo` is the reference普攻节奏 (CRaceMotionData::GetNextComboTime); when the
|
||||
// motion has no ComboInputData it falls back to MotionDuration * 0.9.
|
||||
Dictionary Metin2AnimPlayer::get_motion_data() const {
|
||||
const fmt::Msa &m = msa_metadata;
|
||||
Dictionary d;
|
||||
d["duration"] = duration > 0.0 ? duration : m.duration;
|
||||
d["has_combo_input"] = m.has_combo_input;
|
||||
d["pre_input_time"] = m.combo_pre_input_time;
|
||||
d["direct_input_time"] = m.combo_direct_input_time;
|
||||
d["input_limit_time"] = m.combo_input_limit_time;
|
||||
d["link_time"] = m.combo_link_time;
|
||||
const double dur = duration > 0.0 ? duration : m.duration;
|
||||
d["next_combo"] = m.has_combo_input && m.combo_direct_input_time > 0.0
|
||||
? (double)m.combo_direct_input_time
|
||||
: dur * 0.9;
|
||||
d["has_attacking_data"] = m.has_attacking_data;
|
||||
d["attacking_type"] = m.attacking_type;
|
||||
d["motion_type"] = m.motion_type;
|
||||
d["hitting_type"] = m.hitting_type;
|
||||
d["attack_start_time"] = m.attack_start_time;
|
||||
d["attack_end_time"] = m.attack_end_time;
|
||||
d["stiffen_time"] = m.stiffen_time;
|
||||
d["invisible_time"] = m.invisible_time;
|
||||
d["external_force"] = m.external_force;
|
||||
d["hit_limit_count"] = m.hit_limit_count;
|
||||
// CLIENT-GAP §3.5 修改 1 —— THitDataContainer 多命中窗(多段挥击 / 双持 = 多个窗)。
|
||||
// [{start_time, end_time, bone, weapon_length, samples:[{time, last_pos:Vector3, pos:Vector3}]}]
|
||||
Array windows;
|
||||
for (const fmt::Msa::HitWindow &w : m.hit_windows) {
|
||||
Dictionary wd;
|
||||
wd["start_time"] = w.start_time;
|
||||
wd["end_time"] = w.end_time;
|
||||
wd["bone"] = String::utf8(w.bone_name.c_str());
|
||||
wd["weapon_length"] = w.weapon_length;
|
||||
Array samples;
|
||||
for (const fmt::Msa::HitSample &s : w.samples) {
|
||||
Dictionary sd;
|
||||
sd["time"] = s.time;
|
||||
sd["last_pos"] = Vector3(s.last_pos[0], s.last_pos[1], s.last_pos[2]);
|
||||
sd["pos"] = Vector3(s.pos[0], s.pos[1], s.pos[2]);
|
||||
samples.push_back(sd);
|
||||
}
|
||||
wd["samples"] = samples;
|
||||
windows.push_back(wd);
|
||||
}
|
||||
d["hit_windows"] = windows;
|
||||
return d;
|
||||
}
|
||||
|
||||
int Metin2AnimPlayer::make_combo_key(int motion_mode, int combo_type) {
|
||||
return (int)fmt::make_combo_key((uint16_t)motion_mode, (uint16_t)combo_type);
|
||||
}
|
||||
|
||||
Dictionary Metin2AnimPlayer::parse_combo_tables(const String &py_path) {
|
||||
Dictionary out;
|
||||
fmt::PlayerComboTables tables;
|
||||
std::string err;
|
||||
if (!fmt::parse_player_combo_tables_file(
|
||||
std::string(py_path.utf8().get_data()), tables, &err)) {
|
||||
UtilityFunctions::push_warning(
|
||||
String("Metin2AnimPlayer.parse_combo_tables: ") + String(err.c_str()));
|
||||
return out;
|
||||
}
|
||||
for (int c = 0; c < fmt::COMBO_CLASS_COUNT; ++c) {
|
||||
Dictionary cls;
|
||||
for (const auto &kv : tables.klass(c).combos) {
|
||||
PackedInt32Array segs;
|
||||
segs.resize((int)kv.second.size());
|
||||
for (int i = 0; i < (int)kv.second.size(); ++i) {
|
||||
segs.set(i, (int)kv.second[i]);
|
||||
}
|
||||
cls[(int)kv.first] = segs;
|
||||
}
|
||||
out[c] = cls;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
void Metin2AnimPlayer::_ready() {
|
||||
set_process(true);
|
||||
reload();
|
||||
|
||||
Reference in New Issue
Block a user