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