#[cfg(test)]
#[path = "tests/precache.rs"]
mod tests;
use crate::interfaces::network_string_tables::MODEL_PRECACHE;
use crate::{InterfaceError, Server};
use sdk_raw::vcall;
use std::ffi::CStr;
pub const DECAL_PRECACHE: &CStr = c"decalprecache";
pub const GENERIC_PRECACHE: &CStr = c"genericprecache";
#[derive(Debug, Clone, Copy)]
enum Kind {
Decal,
Generic,
Model,
}
impl Kind {
const fn table(self) -> &'static CStr {
match self {
Self::Decal => DECAL_PRECACHE,
Self::Generic => GENERIC_PRECACHE,
Self::Model => MODEL_PRECACHE,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
pub enum PrecacheError {
#[error("the name is empty, or starts with a character the engine refuses")]
InvalidName,
#[error(transparent)]
Interface(#[from] InterfaceError),
#[error("no level is loaded, so the precache table is missing")]
NoTable,
#[error("the engine precached nothing")]
Refused,
#[error("the precache table is full")]
TableFull,
}
impl<'s> Server<'s> {
fn precache(&self, kind: Kind, name: &CStr, preload: bool) -> Result<usize, PrecacheError> {
if !matches!(name.to_bytes().first(), Some(0x21..=0x7f)) {
return Err(PrecacheError::InvalidName);
}
let engine = self.valve_engine()?.as_ptr();
let table = self
.network_string_tables()?
.find(kind.table())
.ok_or(PrecacheError::NoTable)?;
if table.find(name).is_none() && table.len() >= table.max_len() {
return Err(PrecacheError::TableFull);
}
let name = name.as_ptr();
let index = unsafe {
match kind {
Kind::Decal => vcall!(engine => IVEngineServer_PrecacheDecal(name, preload)),
Kind::Generic => vcall!(engine => IVEngineServer_PrecacheGeneric(name, preload)),
Kind::Model => vcall!(engine => IVEngineServer_PrecacheModel(name, preload)),
}
};
usize::try_from(index).map_err(|_| PrecacheError::Refused)
}
#[doc(alias("PrecacheDecal"))]
pub fn precache_decal(&self, decal: &CStr, preload: bool) -> Result<usize, PrecacheError> {
self.precache(Kind::Decal, decal, preload)
}
#[doc(alias("PrecacheGeneric"))]
pub fn precache_generic(&self, path: &CStr, preload: bool) -> Result<usize, PrecacheError> {
self.precache(Kind::Generic, path, preload)
}
#[doc(alias("PrecacheModel"))]
pub fn precache_model(&self, model: &CStr, preload: bool) -> Result<usize, PrecacheError> {
self.precache(Kind::Model, model, preload)
}
}