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::net::actions,
59 crate::particle::actions,
60 crate::player::actions,
61 crate::scoreboard::actions,
62 crate::sound::actions,
63 crate::tag::actions,
64 crate::ui::actions,
65 crate::world::actions,
66];
67
68macro_rules! services {
69 ($($ty:path => $address:expr, $reply:ty $(, key = $key:ident)?;)*) => {
70 $(impl Service for $ty {
71 const ADDRESS: &'static str = $address;
72 const KEY: Option<&'static str> = key!($($key)?);
73 type Reply = $reply;
74
75 fn key(&self) -> Option<&str> {
76 key_value!(self, $($key)?)
77 }
78
79 fn address(&self) -> crate::Address {
80 static AT: crate::Cached = crate::Cached::new();
81 crate::address::of(&AT, $address, self.key())
82 }
83 })*
84
85 fn listed() -> Vec<ServiceInfo> {
87 vec![$(ServiceInfo {
88 domain: branch($address, ids::service::PREFIX),
89 name: last_segment(stringify!($ty)),
90 address: $address,
91 key: key!($($key)?),
92 shape: <$ty as Schema>::shape(),
93 reply: <$reply as Schema>::shape(),
94 host: None,
95 }),*]
96 }
97 };
98}
99
100pub fn services() -> Vec<ServiceInfo> {
102 let mut all = listed();
103 for actions in ACTIONS {
104 all.extend(actions());
105 }
106 all
107}
108
109services! {
110 block::Insert => ids::service_block::INSERT, bool, key = block_id;
111 item::Text => ids::service_item::TEXT, Option<item::Shown>, key = item;
112 item::Picture => ids::service_item::PICTURE, Option<[f32; 2]>, key = item;
113 bus::Descriptor => ids::service_bus::DECLARE, bool;
114 bus::Describe => ids::service_bus::DESCRIBE, Option<bus::Descriptor>;
115 bus::List => ids::service_bus::LIST, Vec<String>;
116 bus::Find => ids::service_bus::FIND, Vec<String>;
117 content::Register => ids::service_content::REGISTER, bool;
118 command::CommandSpec => ids::service_command::DECLARE, bool;
119 command::Declared => ids::service_command::DECLARED, Vec<command::CommandSpec>;
120 menu::MenuEntry => ids::service_menu::DECLARE, bool;
121 menu::Declared => ids::service_menu::DECLARED, Vec<menu::MenuEntry>;
122 key_binding::KeyBindingSpec => ids::service_key_binding::DECLARE, bool;
123 key_binding::Declared => ids::service_key_binding::DECLARED, Vec<key_binding::CategorizedBinding>;
124 entity::Data => ids::service_entity::DATA, Option<entity::DataValue>;
125 entity::SetData => ids::service_entity::SET_DATA, bool;
126 entity::SetDimensions => ids::service_entity::SET_DIMENSIONS, bool;
127 client::EntityData => ids::service_client::ENTITY_DATA, Option<entity::DataValue>;
128 game::Mods => ids::service_game::MODS, Vec<game::ModInfo>;
129 game::ModLoaded => ids::service_game::MOD_LOADED, bool;
130 mirror::Declare => ids::service_mirror::DECLARE, mirror::Declared;
131 mirror::Release => ids::service_mirror::RELEASE, bool;
132 mirror::Provide => ids::service_mirror::PROVIDE, Option<yog_data::Diagnostic>;
133 mirror::Touch => ids::service_mirror::TOUCH, bool;
134 mirror::Keys => ids::service_mirror::KEYS, Vec<u32>;
135}