use crate::abi::Header;
use super::table;
use super::{FakeHost, Installed};
#[expect(
clippy::unused_self,
reason = "the fake's state is process-wide; `self` proves it is installed"
)]
impl Installed {
#[must_use]
pub fn draw_frame(&self) -> Vec<Drawn> {
let frames = table::with(Vec::new(), |s| s.frames.clone());
let mut drawn = Vec::new();
for (token, (callback, user)) in (1u64..).zip(frames) {
table::with((), |s| s.frame = Some((token, false, Vec::new())));
let frame = crate::abi::UiFrame {
header: Header::of::<crate::abi::UiFrame>(),
token,
screen: crate::abi::UiFrame::IN_GAME,
reserved: 0,
};
unsafe {
callback(
&raw const frame,
core::ptr::with_exposed_provenance_mut(user),
);
};
if let Some((_, _, list)) = table::with(None, |s| s.frame.take()) {
drawn.extend(list);
}
}
drawn
}
#[must_use]
pub fn draw_hud(&self) -> Vec<(u32, Drawn)> {
let huds = table::with(Vec::new(), |s| s.huds.clone());
let mut drawn = Vec::new();
for (token, (callback, user)) in (1u64..).zip(huds) {
table::with((), |s| s.hud = Some((token, Vec::new())));
let frame = crate::abi::UiFrame {
header: Header::of::<crate::abi::UiFrame>(),
token,
screen: crate::abi::UiFrame::IN_GAME,
reserved: 0,
};
unsafe {
callback(
&raw const frame,
core::ptr::with_exposed_provenance_mut(user),
);
}
if let Some((_, list)) = table::with(None, |s| s.hud.take()) {
drawn.extend(list);
}
}
drawn
}
#[must_use]
pub fn markers(&self) -> Vec<FakeMarker> {
table::with(Vec::new(), |s| s.markers.clone())
}
pub fn input(&self, text: &str, input: Input) {
table::with((), |s| s.inputs.push((text.to_owned(), input)));
}
#[must_use]
pub fn dialogs(&self) -> Vec<ShownDialog> {
table::with(Vec::new(), |s| {
s.dialogs.iter().map(|(d, _, _)| d.clone()).collect()
})
}
pub fn answer(&self, answer: Option<crate::ui::Response>) -> bool {
let first = table::with(None, |s| {
(!s.dialogs.is_empty()).then(|| s.dialogs.remove(0))
});
let Some((_, callback, user)) = first else {
return false;
};
let raw = answer.map_or(crate::abi::UiDialog::CLOSED, crate::ui::Response::to_raw);
unsafe { callback(raw, core::ptr::with_exposed_provenance_mut(user)) };
true
}
}
#[derive(Clone, Debug, PartialEq)]
#[non_exhaustive]
pub enum Drawn {
Window {
id: String,
title: String,
},
End,
Label {
text: String,
style: u32,
},
Button {
text: String,
enabled: bool,
},
Toggle {
label: String,
on: bool,
read_only: bool,
},
Slider {
label: String,
value: f32,
min: f32,
max: f32,
steps: u32,
read_only: bool,
},
Dropdown {
label: String,
options: Vec<String>,
index: usize,
read_only: bool,
},
Progress {
fraction: f32,
},
Sound(u32),
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct FakeMarker {
pub position: [i64; 3],
pub label: String,
pub color: u32,
}
#[derive(Clone, Copy, Debug, PartialEq)]
#[non_exhaustive]
pub enum Input {
Click,
Toggle(bool),
Value(f32),
Pick(usize),
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct ShownDialog {
pub title: String,
pub message: String,
pub detail: String,
pub buttons: u32,
}
impl FakeHost {
#[must_use]
pub fn fog(mut self, info: crate::abi::FogInfo, pixels: Vec<u8>) -> Self {
assert_eq!(
pixels.len(),
info.width as usize * info.height as usize,
"the pixels of the image the info describes"
);
self.fog = Some((info, pixels));
self
}
}
#[expect(
clippy::unused_self,
reason = "the fake's state is process-wide; `self` proves it is installed"
)]
impl Installed {
pub fn set_fog(&self, info: crate::abi::FogInfo, pixels: Vec<u8>) {
assert_eq!(pixels.len(), info.width as usize * info.height as usize);
table::with((), |s| s.host.fog = Some((info, pixels)));
}
}