A26: слияние включённых моделей — у игрока 465 секвенций
Some checks are pending
CI / checks (push) Waiting to run

police.mdl включает models/m_anm.mdl (библиотека анимаций GMod). Включённая
модель грузится лёгким путём: Mdl::parse + секвенции, без геометрии и текстур —
у анимационной библиотеки их нет. Замеры: у m_anm.mdl numlocalseq=464,
numlocalanim=1563, 56 костей; после слияния у модели игрока 465 секвенций
(была одна «ragdoll»).

Находка по пути: у «единичных» (unified) моделей GMod запись секвенции длиннее,
чем у моделей карты, и мой первый набор кандидатов (184..208) не подошёл —
разбор молча возвращал ноль. Перебор расширен до 176..320 с обязательной
проверкой имён ВСЕХ секвенций: иначе шаг не принимается.

Все 23 сьюта зелёные; docs/PARITY.md A26 обновлён.
This commit is contained in:
Niko Marmeladkov 2026-10-17 11:32:37 +03:00
parent 50ab90debc
commit 3c0bef5169
3 changed files with 57 additions and 4 deletions

View file

@ -118,6 +118,46 @@ pub fn load_model(vfs: &VirtualFs, name: &str, budget: &mut usize) -> Result<Mod
// скиннинга (A26). Отсутствие данных не ошибка: часть моделей их не имеет.
model.bones = mdl.bones().unwrap_or_default();
model.sequences = mdl.sequences().unwrap_or_default();
// Включённые модели (`includemodel`): у игроков там лежат активности
// (у police.mdl своя секвенция всего одна — «ragdoll»). Замером смотрим,
// что именно включается, прежде чем сливать.
if let Ok(includes) = mdl.include_models() {
let mut merged = 0usize;
for include in &includes {
// Лёгкий разбор: у анимационной библиотеки (`m_anm.mdl`) нет ни
// геометрии, ни текстур — нужны только секвенции и скелет.
let path = if include.name.starts_with("models/") {
include.name.clone()
} else {
format!("models/{}", include.name)
};
let Ok(data) = vfs.read(&path) else {
tracing::warn!(name = %name, include = %path, "включённая модель не прочитана");
continue;
};
let Ok(included) = formats::Mdl::parse(&data) else {
tracing::warn!(name = %name, include = %path, "включённая модель не разобрана");
continue;
};
let sequences = included.sequences().unwrap_or_default();
tracing::info!(
include = %path,
numlocalseq = included.header.numlocalseq,
numlocalanim = included.header.numlocalanim,
bones = included.header.numbones,
includes = included.header.numincludemodels,
"включённая модель: что внутри"
);
merged += sequences.len();
model.sequences.extend(sequences);
tracing::info!(
name = %name,
include = %path,
added = merged,
"модель: секвенции включённой модели"
);
}
}
if !model.skins.is_empty() {
let skinned = model
.skins

View file

@ -467,7 +467,10 @@ impl<'a> Mdl<'a> {
}
let start = h.localseqindex.max(0) as usize;
let mut chosen: Option<(usize, Vec<Sequence>)> = None;
for stride in [184usize, 188, 192, 196, 200, 204, 208] {
// Перебор широкий: у «единичных» (unified) моделей GMod запись
// секвенции длиннее, чем у моделей карты, и угадывать нельзя — берём
// только тот шаг, при котором читаются имена ВСЕХ секвенций.
for stride in (176..=320).step_by(4) {
let mut out = Vec::with_capacity(count);
let mut ok = true;
for i in 0..count {

View file

@ -3192,9 +3192,19 @@ Sandbox.
GPU» работает целиком. Пока это не анимация: настоящие кадры из `.ani`
следующим шагом.
**Порядок работ:** (а) секвенции сделаны; дальше `.ani` (кадры) и слияние
включённых моделей; (б) привязка вершин сделана; (в) CPU-скиннинг сделан;
(г) проигрывание одной секвенции с циклом; (д) выбор по состоянию и блендинг.
**Сделано (слияние включённых моделей).** Разбор `include_models()` и лёгкая
загрузка включённой модели (без геометрии и текстур: `Mdl::parse` + секвенции).
Замеры: `police.mdl` включает `models/m_anm.mdl` — библиотеку анимаций GMod;
у неё `numlocalseq=464`, `numlocalanim=1563`, 56 костей. После слияния у модели
игрока **465 секвенций** (была одна «ragdoll»).
Важная находка: у «единичных» (unified) моделей GMod запись секвенции длиннее
176…208 байт, поэтому перебор шага расширен до 176…320 с обязательной проверкой
имён ВСЕХ секвенций — иначе разбор молча возвращал ноль.
**Порядок работ:** (а) секвенции и включённые модели сделаны; дальше `.ani`
(кадры); (б) привязка вершин сделана; (в) CPU-скиннинг сделан; (г) проигрывание
одной секвенции с циклом; (д) выбор по состоянию и блендинг.
**Приёмка:** модель игрока/оружия двигается в кадре, ходьба переходит в бег и
присед по скорости, прыжок показывается отдельной секвенцией.