use yog_data::{Schema, Shape};
use yog_ids as ids;
use crate::message::{Message, branch, last_segment};
use crate::{block, bus, client, command, content, entity, game, item, key_binding, menu};
pub trait Service: Message {
const ADDRESS: &'static str;
const KEY: Option<&'static str>;
type Reply: Schema;
fn key(&self) -> Option<&str>;
fn target(&self) -> String {
crate::message::target(Self::ADDRESS, self.key())
}
fn address(&self) -> crate::Address;
}
pub struct ServiceInfo {
pub domain: &'static str,
pub name: &'static str,
pub address: &'static str,
pub key: Option<&'static str>,
pub shape: Shape,
pub reply: Shape,
pub host: Option<&'static str>,
}
const ACTIONS: &[fn() -> Vec<ServiceInfo>] = &[
crate::advancement::actions,
crate::block::actions,
crate::bossbar::actions,
crate::chat::actions,
crate::client::actions,
crate::client::local::actions,
crate::client::control::actions,
crate::entity::actions,
crate::game::actions,
crate::item::actions,
crate::jvm::actions,
crate::net::actions,
crate::particle::actions,
crate::player::actions,
crate::scoreboard::actions,
crate::sound::actions,
crate::tag::actions,
crate::ui::actions,
crate::world::actions,
];
macro_rules! services {
($($ty:path => $address:expr, $reply:ty $(, key = $key:ident)?;)*) => {
$(impl Service for $ty {
const ADDRESS: &'static str = $address;
const KEY: Option<&'static str> = key!($($key)?);
type Reply = $reply;
fn key(&self) -> Option<&str> {
key_value!(self, $($key)?)
}
fn address(&self) -> crate::Address {
static AT: crate::Cached = crate::Cached::new();
crate::address::of(&AT, $address, self.key())
}
})*
fn listed() -> Vec<ServiceInfo> {
vec![$(ServiceInfo {
domain: branch($address, ids::service::PREFIX),
name: last_segment(stringify!($ty)),
address: $address,
key: key!($($key)?),
shape: <$ty as Schema>::shape(),
reply: <$reply as Schema>::shape(),
host: None,
}),*]
}
};
}
pub fn services() -> Vec<ServiceInfo> {
let mut all = listed();
for actions in ACTIONS {
all.extend(actions());
}
all
}
services! {
block::Insert => ids::service_block::INSERT, bool, key = block_id;
item::Text => ids::service_item::TEXT, Option<item::Shown>, key = item;
item::Picture => ids::service_item::PICTURE, Option<[f32; 2]>, key = item;
bus::Descriptor => ids::service_bus::DECLARE, bool;
bus::Describe => ids::service_bus::DESCRIBE, Option<bus::Descriptor>;
bus::List => ids::service_bus::LIST, Vec<String>;
bus::Find => ids::service_bus::FIND, Vec<String>;
content::Register => ids::service_content::REGISTER, bool;
command::CommandSpec => ids::service_command::DECLARE, bool;
command::Declared => ids::service_command::DECLARED, Vec<command::CommandSpec>;
menu::MenuEntry => ids::service_menu::DECLARE, bool;
menu::Declared => ids::service_menu::DECLARED, Vec<menu::MenuEntry>;
key_binding::KeyBindingSpec => ids::service_key_binding::DECLARE, bool;
key_binding::Declared => ids::service_key_binding::DECLARED, Vec<key_binding::CategorizedBinding>;
entity::Data => ids::service_entity::DATA, Option<entity::DataValue>;
entity::SetData => ids::service_entity::SET_DATA, bool;
entity::SetDimensions => ids::service_entity::SET_DIMENSIONS, bool;
client::EntityData => ids::service_client::ENTITY_DATA, Option<entity::DataValue>;
game::Mods => ids::service_game::MODS, Vec<game::ModInfo>;
game::ModLoaded => ids::service_game::MOD_LOADED, bool;
}