910f02ca92
build / mod (push) Failing after 19s
Pin API27, diagnose prepared states, gate capture ownership and keep far-sound fallback until acoustics is prepared. Retain engine changes in build provenance and cancel invalid return reservations after cell loss. Co-authored-by: Codex <codex@openai.com>
148 lines
4.7 KiB
Rust
148 lines
4.7 KiB
Rust
//! Host milestones, not promises of audible output or completed GPU/file work.
|
|
use horizon_mod_sdk::render::{self, CapabilityReason, CapabilityState};
|
|
|
|
pub fn ready(s: &CapabilityState) -> bool {
|
|
s.generation != 0
|
|
&& s.available
|
|
&& s.enabled
|
|
&& s.request_accepted
|
|
&& s.prepared
|
|
&& s.reason == CapabilityReason::Ready
|
|
}
|
|
|
|
pub fn capture_problem(s: &CapabilityState) -> Option<&'static str> {
|
|
if !s.available {
|
|
Some("Движок не поддерживает подтверждение захвата")
|
|
} else if !s.enabled || s.generation == 0 {
|
|
Some("Захват недоступен без текущего мира")
|
|
} else if !s.request_accepted {
|
|
Some("Захват больше не принадлежит этой сессии мода")
|
|
} else if s.reason == CapabilityReason::Failed {
|
|
Some("Ошибка пути захвата движка")
|
|
} else {
|
|
None
|
|
}
|
|
}
|
|
|
|
/// Adopt the existing global preference once in this world, without switching it.
|
|
/// A configured request and actual backend preparation are still separate milestones.
|
|
pub fn acoustics() -> CapabilityState {
|
|
let s = render::acoustics_status();
|
|
if s.available && s.generation != 0 && !s.request_accepted {
|
|
render::set_acoustics(s.enabled);
|
|
render::acoustics_status()
|
|
} else {
|
|
s
|
|
}
|
|
}
|
|
|
|
fn reason(r: CapabilityReason) -> &'static str {
|
|
match r {
|
|
CapabilityReason::AwaitingWorld => "awaiting-world",
|
|
CapabilityReason::Disabled => "disabled",
|
|
CapabilityReason::NotRequested => "not-requested",
|
|
CapabilityReason::AwaitingBackend => "awaiting-backend",
|
|
CapabilityReason::Failed => "failed",
|
|
CapabilityReason::Ready => "ready",
|
|
}
|
|
}
|
|
|
|
fn line(
|
|
name: &str,
|
|
generation: u64,
|
|
available: bool,
|
|
enabled: bool,
|
|
accepted: bool,
|
|
prepared: bool,
|
|
why: &str,
|
|
) -> String {
|
|
format!("{name}: API={available}, включено={enabled}, запрос={accepted}, подготовлено={prepared}, поколение={generation}, {why}")
|
|
}
|
|
|
|
pub fn diagnostics() -> String {
|
|
let smoke = render::smoke_status();
|
|
let acoustic = acoustics();
|
|
let capture = render::capture_owner_status();
|
|
let smoke_reason = match smoke.reason {
|
|
render::SmokeReason::AwaitingFrame => "awaiting-frame",
|
|
render::SmokeReason::Disabled => "disabled",
|
|
render::SmokeReason::PathUnavailable => "path-unavailable",
|
|
render::SmokeReason::Ready => "ready",
|
|
};
|
|
[
|
|
"Возможности движка (API 27; подготовка не означает готовый GPU-кадр или файл):".into(),
|
|
line(
|
|
"Дым",
|
|
smoke.generation,
|
|
smoke.available,
|
|
smoke.enabled,
|
|
smoke.request_accepted,
|
|
smoke.backend_ready,
|
|
smoke_reason,
|
|
),
|
|
line(
|
|
"Акустика",
|
|
acoustic.generation,
|
|
acoustic.available,
|
|
acoustic.enabled,
|
|
acoustic.request_accepted,
|
|
acoustic.prepared,
|
|
reason(acoustic.reason),
|
|
),
|
|
line(
|
|
"Захват этого мода",
|
|
capture.generation,
|
|
capture.available,
|
|
capture.enabled,
|
|
capture.request_accepted,
|
|
capture.prepared,
|
|
reason(capture.reason),
|
|
),
|
|
]
|
|
.join("\n")
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
fn state() -> CapabilityState {
|
|
CapabilityState {
|
|
generation: 5,
|
|
available: true,
|
|
enabled: true,
|
|
request_accepted: true,
|
|
prepared: true,
|
|
reason: CapabilityReason::Ready,
|
|
}
|
|
}
|
|
#[test]
|
|
fn acceptance_alone_never_disables_the_working_fallback() {
|
|
assert!(ready(&state()));
|
|
for missing in 0..6 {
|
|
let mut s = state();
|
|
match missing {
|
|
0 => s.generation = 0,
|
|
1 => s.available = false,
|
|
2 => s.enabled = false,
|
|
3 => s.request_accepted = false,
|
|
4 => s.prepared = false,
|
|
_ => s.reason = CapabilityReason::AwaitingBackend,
|
|
}
|
|
assert!(!ready(&s));
|
|
}
|
|
}
|
|
#[test]
|
|
fn a_foreign_capture_is_not_success_and_preparing_is_not_failure() {
|
|
let mut s = state();
|
|
s.request_accepted = false;
|
|
assert!(capture_problem(&s).is_some());
|
|
s = state();
|
|
s.prepared = false;
|
|
s.reason = CapabilityReason::AwaitingBackend;
|
|
assert!(capture_problem(&s).is_none());
|
|
assert!(!ready(&s));
|
|
s.reason = CapabilityReason::Failed;
|
|
assert!(capture_problem(&s).is_some());
|
|
}
|
|
}
|