scroll.server/crates/logic/src/commands/manager.rs

45 lines
2 KiB
Rust

use crate::commands::command::{CommandRegistryEntry, LogicCommand};
use std::collections::HashMap;
use std::sync::{Arc, OnceLock};
use titan::{ByteStreamReader, ByteStreamWriter, Error, Payload, Result};
static REGISTRY: OnceLock<Arc<HashMap<i32, CommandRegistryEntry>>> = OnceLock::new();
pub struct LogicCommandManager;
impl LogicCommandManager {
pub fn registry() -> Arc<HashMap<i32, CommandRegistryEntry>> {
Arc::clone(REGISTRY.get_or_init(|| {
let mut entries = HashMap::new();
for entry in titan::inventory::iter::<CommandRegistryEntry> {
if let Some(previous) = entries.insert(entry.command_type, *entry) {
tracing::warn!(
command_type = entry.command_type,
previous = previous.name,
replacement = entry.name,
"two commands declare the same type"
);
}
}
tracing::debug!(commands = entries.len(), "command registry collected");
Arc::new(entries)
}))
}
pub fn lookup(command_type: i32) -> Option<CommandRegistryEntry> {
Self::registry().get(&command_type).copied()
}
pub fn decode_command(reader: &mut ByteStreamReader<'_>) -> Result<Box<dyn LogicCommand>> {
let command_type = reader.read_vint()?;
let entry = Self::lookup(command_type).ok_or(Error::UnknownCommandType(command_type))?;
entry.decode(reader)
}
pub fn encode_command(writer: &mut ByteStreamWriter, command: &dyn LogicCommand) -> Result<()> {
writer.write_vint(command.command_type());
command.encode_body(writer)
}
}
impl Payload for Box<dyn LogicCommand> {
fn encode(&self, writer: &mut ByteStreamWriter) -> Result<()> {
LogicCommandManager::encode_command(writer, self.as_ref())
}
fn decode(reader: &mut ByteStreamReader<'_>) -> Result<Self> {
LogicCommandManager::decode_command(reader)
}
}