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