1use yog_data::{Schema, Shape};
5use yog_ids as ids;
6
7use crate::message::{Message, branch, last_segment};
8use crate::{block, bus, client, command, content, entity, game, item, key_binding, menu, mirror};
9
10pub trait Service: Message {
12 const ADDRESS: &'static str;
14 const KEY: Option<&'static str>;
17 type Reply: Schema;
19
20 fn key(&self) -> Option<&str>;
22
23 fn target(&self) -> String {
25 crate::message::target(Self::ADDRESS, self.key())
26 }
27
28 fn address(&self) -> crate::Address;
30}
31
32pub struct ServiceInfo {
34 pub domain: &'static str,
36 pub name: &'static str,
37 pub address: &'static str,
38 pub key: Option<&'static str>,
39 pub shape: Shape,
40 pub reply: Shape,
41 pub host: Option<&'static str>,
43}
44
45const ACTIONS: &[fn() -> Vec<ServiceInfo>] = &[
47 crate::advancement::actions,
48 crate::block::actions,
49 crate::bossbar::actions,
50 crate::chat::actions,
51 crate::client::actions,
52 crate::client::local::actions,
53 crate::client::control::actions,
54 crate::entity::actions,
55 crate::game::actions,
56 crate::item::actions,
57 crate::jvm::actions,
58 crate::nanite::actions,
59 crate::net::actions,
60 crate::particle::actions,
61 crate::player::actions,
62 crate::scoreboard::actions,
63 crate::sound::actions,
64 crate::tag::actions,
65 crate::ui::actions,
66 crate::world::actions,
67];
68
69macro_rules! services {
70 ($($ty:path => $address:expr, $reply:ty $(, key = $key:ident)?;)*) => {
71 $(impl Service for $ty {
72 const ADDRESS: &'static str = $address;
73 const KEY: Option<&'static str> = key!($($key)?);
74 type Reply = $reply;
75
76 fn key(&self) -> Option<&str> {
77 key_value!(self, $($key)?)
78 }
79
80 fn address(&self) -> crate::Address {
81 static AT: crate::Cached = crate::Cached::new();
82 crate::address::of(&AT, $address, self.key())
83 }
84 })*
85
86 fn listed() -> Vec<ServiceInfo> {
88 vec![$(ServiceInfo {
89 domain: branch($address, ids::service::PREFIX),
90 name: last_segment(stringify!($ty)),
91 address: $address,
92 key: key!($($key)?),
93 shape: <$ty as Schema>::shape(),
94 reply: <$reply as Schema>::shape(),
95 host: None,
96 }),*]
97 }
98 };
99}
100
101pub fn services() -> Vec<ServiceInfo> {
103 let mut all = listed();
104 for actions in ACTIONS {
105 all.extend(actions());
106 }
107 all
108}
109
110services! {
111 block::Insert => ids::service_block::INSERT, bool, key = block_id;
112 item::Text => ids::service_item::TEXT, Option<item::Shown>, key = item;
113 item::Picture => ids::service_item::PICTURE, Option<[f32; 2]>, key = item;
114 bus::Descriptor => ids::service_bus::DECLARE, bool;
115 bus::Describe => ids::service_bus::DESCRIBE, Option<bus::Descriptor>;
116 bus::List => ids::service_bus::LIST, Vec<String>;
117 bus::Find => ids::service_bus::FIND, Vec<String>;
118 content::Register => ids::service_content::REGISTER, bool;
119 command::CommandSpec => ids::service_command::DECLARE, bool;
120 command::Declared => ids::service_command::DECLARED, Vec<command::CommandSpec>;
121 menu::MenuEntry => ids::service_menu::DECLARE, bool;
122 menu::Declared => ids::service_menu::DECLARED, Vec<menu::MenuEntry>;
123 key_binding::KeyBindingSpec => ids::service_key_binding::DECLARE, bool;
124 key_binding::Declared => ids::service_key_binding::DECLARED, Vec<key_binding::CategorizedBinding>;
125 entity::Data => ids::service_entity::DATA, Option<entity::DataValue>;
126 entity::SetData => ids::service_entity::SET_DATA, bool;
127 entity::SetDimensions => ids::service_entity::SET_DIMENSIONS, bool;
128 client::EntityData => ids::service_client::ENTITY_DATA, Option<entity::DataValue>;
129 game::Mods => ids::service_game::MODS, Vec<game::ModInfo>;
130 game::ModLoaded => ids::service_game::MOD_LOADED, bool;
131 mirror::Declare => ids::service_mirror::DECLARE, mirror::Declared;
132 mirror::Release => ids::service_mirror::RELEASE, bool;
133 mirror::Provide => ids::service_mirror::PROVIDE, Option<yog_data::Diagnostic>;
134 mirror::Touch => ids::service_mirror::TOUCH, bool;
135 mirror::Keys => ids::service_mirror::KEYS, Vec<u32>;
136}