2V3-a: walk with the keyboard through the ported player chain

PythonPlayer, PythonPlayerInput{,Keyboard,Mouse}, PythonPlayerEventHandler,
PythonPlayerSkill, PythonPlayerModule and GameType are verbatim copies; the
`player` stub module and the pending PythonPlayer/GameType stand-ins are gone.
Unported callees (CPythonSkill, CItemData, CItemManager, CPythonItem, ...) are
pending stubs. 64-bit fixes: emotion icon handles use Py_BuildPointer, and
PyDict_Next takes Py_ssize_t.

The actor did not move because GrannyUpdateModelMatrix passed the model matrix
through. Walk/run motions use constant root-motion extraction
(AccumulationFlags=AccumulationExtracted, LoopTranslation e.g. (0,-300,0) for
the warrior run, same as the .msa Accumulation). libgr2 now reads both fields
from TrackGroups[0], and the runtime moves by LoopTranslation over each
control's local-clock span, blended by control weight. VDA extraction is not
implemented.

port.login_flow presses DIK_UP; the actor walks more than 100 cm, and the fake
server parses CG packets and sees CG_MOVE FUNC_MOVE, then FUNC_WAIT at the new
position. port.login_live against the real server walked 132 cm.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
shenlei
2026-09-23 23:41:31 +09:00
co-authored by Claude Opus 5.5
parent 157f7c3bb4
commit ff0983d3c8
39 changed files with 10170 additions and 2039 deletions
+11
View File
@@ -109,6 +109,17 @@ bool File::Impl::extract_animation(Ref anim_obj, Ref anim_type, const Skeleton*
out.track_group_count = int32_t(groups.size());
const auto& tgms = parse_type(mTG->ref_type);
// TrackGroups[0].AccumulationFlags (Int32) + LoopTranslation (Real32[3])
if (!groups.empty() && groups[0].valid()) {
if (const TypeMember* m = find_member(tgms, "AccumulationFlags"))
out.accumulation_flags = rd_i32(member_slot(groups[0], *m));
if (const TypeMember* m = find_member(tgms, "LoopTranslation")) {
Ref r = member_slot(groups[0], *m);
for (int i = 0; i < 3; ++i)
out.loop_translation[i] = rd_f32(Ref{r.section, r.offset + uint32_t(i) * 4u});
}
}
// TrackGroups[0].TextTracks: RefToArray text_track{String Name; RefToArray Entries(
// text_track_entry{Real32 TimeStamp; String Text})}(motion event 用)
if (!groups.empty() && groups[0].valid())