// M2 T1 —— .msa 解析(照 EterGrnLib/Util.cpp CGrannyMotion::LoadMotionData 的字段)。 #include "msa.h" #include "textscript.h" #include namespace fmt { static void vec3(const std::vector* l, float* out) { if (!l) return; for (int k = 0; k < 3 && k + 1 < (int)l->size(); ++k) out[k] = float(std::atof((*l)[k + 1].c_str())); } static void loop_data(const Node& root, Msa& out) { if (const Node* loop = root.group("LoopData")) { out.has_loop_data = true; out.motion_loop_count = loop->inum("MotionLoopCount", -1); out.loop_cancel_enable = loop->inum("LoopCancelEnable", 0) != 0; out.loop_start_time = loop->num("LoopStartTime"); out.loop_end_time = loop->num("LoopEndTime"); } } bool parse_msa(const std::string& text, Msa& out, std::string* err) { Node root; if (!parse_textscript(text, root, err)) return false; out = Msa{}; out.motion_gr2 = root.str("MotionFileName"); out.duration = root.num("MotionDuration"); vec3(root.find("Accumulation"), out.accumulation); loop_data(root, out); if (const Node* med = root.group("MotionEventData")) { int count = med->inum("MotionEventDataCount", int(med->groups.size())); (void)count; for (const Node& ev : med->groups) { MotionEvent e; e.type = ev.inum("MotionEventType"); e.start_time = ev.num("StartingTime"); e.effect_file = ev.str("EffectFileName"); e.sound_file = ev.str("SoundFileName"); vec3(ev.find("EffectPosition"), e.position); out.events.push_back(std::move(e)); } } if (out.motion_gr2.empty()) { if (err) *err = "msa: 缺 MotionFileName"; return false; } return true; } bool parse_msa_file(const std::string& path, Msa& out, std::string* err) { Node root; if (!parse_textscript_file(path, root, err)) return false; // 复用上面逻辑:重解析文本更简单,这里直接从 root 走一遍 out = Msa{}; out.motion_gr2 = root.str("MotionFileName"); out.duration = root.num("MotionDuration"); vec3(root.find("Accumulation"), out.accumulation); loop_data(root, out); if (const Node* med = root.group("MotionEventData")) for (const Node& ev : med->groups) { MotionEvent e; e.type = ev.inum("MotionEventType"); e.start_time = ev.num("StartingTime"); e.effect_file = ev.str("EffectFileName"); e.sound_file = ev.str("SoundFileName"); vec3(ev.find("EffectPosition"), e.position); out.events.push_back(std::move(e)); } if (out.motion_gr2.empty()) { if (err) *err = "msa: 缺 MotionFileName (" + path + ")"; return false; } return true; } } // namespace fmt