common_game/protocols/orchestrator_planet.rs
1//! # Orchestrator and Planet protocol messages
2//!
3//! Defines the types of messages exchanged of the full duplex communication channel
4//! between the Orchestrator and the Planets
5//! For a more detailed view of the interactions between these two entities, visit the communications [diagrams](https://github.com/unitn-ap-2025/common/blob/main/MESSAGE_DIAGRAMS.md)
6
7use crate::components::asteroid::Asteroid;
8use crate::components::planet::DummyPlanetState;
9use crate::components::rocket::Rocket;
10use crate::components::sunray::Sunray;
11use crate::protocols::planet_explorer::PlanetToExplorer;
12use crate::utils::ID;
13use crossbeam_channel::Sender;
14use enum_as_inner::EnumAsInner;
15use strum_macros::EnumDiscriminants;
16
17#[cfg(doc)]
18use {crate::components::energy_cell::EnergyCell, crate::components::planet::Planet};
19
20/// This enum describes all possible messages from the Orchestrator to a Planet
21#[derive(Debug, EnumAsInner, EnumDiscriminants)]
22#[strum_discriminants(name(OrchestratorToPlanetKind))]
23#[strum_discriminants(derive(Hash))]
24pub enum OrchestratorToPlanet {
25 /// This variant is used to send a [Sunray] to a planet
26 ///
27 /// **Expected Response**: [`PlanetToOrchestrator::SunrayAck`]
28 ///
29 /// **Use Case**: sending a [Sunray] to charge [`EnergyCell`]
30 Sunray(Sunray),
31 /// This variant is used to send an [Asteroid] to a planet
32 ///
33 /// **Expected Response**: [`PlanetToOrchestrator::AsteroidAck`]
34 ///
35 /// **Use Case**: sending an [Asteroid] to attack a [Planet]
36 Asteroid(Asteroid),
37 /// This variant is used to start a Planet AI and restart it if it is stopped
38 ///
39 /// **Expected Response**: [`PlanetToOrchestrator::StartPlanetAIResult`]
40 ///
41 /// **Use Case**: Starting the Planet AI at game start or restart the AI in case it is stopped
42 StartPlanetAI,
43 /// This variant is used to pause the planet Ai
44 ///
45 /// **Expected Response**: [`PlanetToOrchestrator::StopPlanetAIResult`]
46 ///
47 /// **Use Case**: Freezing Planet ability to respond to every message,
48 /// a planet in this state will only answer with [`PlanetToOrchestrator::Stopped`]
49 StopPlanetAI,
50 /// This variant is used to kill (or destroy) the planet
51 ///
52 /// **Expected Response**: [`PlanetToOrchestrator::KillPlanetResult`]
53 ///
54 /// **Use Case**: Instantly kill a Planet
55 KillPlanet,
56 /// This variant is used to obtain a Planet Internal State
57 ///
58 /// **Expected Response**: [`PlanetToOrchestrator::InternalStateResponse`]
59 ///
60 /// **Use Case**: The GUI can use this message to obtain the relevant info of the planet to be shown
61 InternalStateRequest,
62 /// This variant is used to advertise an incoming explorer to a planet
63 ///
64 /// **Expected Response**: [`PlanetToOrchestrator::IncomingExplorerResponse`]
65 ///
66 /// **Use Case**: Moving an explorer to this planet
67 IncomingExplorerRequest {
68 ///The incoming explorer's id
69 explorer_id: ID,
70 ///The new sender half of the [`crossbeam_channel`] for the planet to communicate with the incoming explorer
71 new_sender: Sender<PlanetToExplorer>,
72 },
73 /// This variant is used to advertise an outgoing explorer to a planet
74 ///
75 /// **Expected Response**: [`PlanetToOrchestrator::OutgoingExplorerResponse`]
76 ///
77 /// **Use Case**: Asking the planet to delete the [Sender] to the outgoing explorer
78 OutgoingExplorerRequest {
79 ///The outgoing explorer's id
80 explorer_id: ID,
81 },
82}
83
84/// This enum describes all possible messages from a Planet to the Orchestrator
85#[derive(Debug, EnumAsInner, EnumDiscriminants)]
86#[strum_discriminants(name(PlanetToOrchestratorKind))]
87#[strum_discriminants(derive(Hash))]
88pub enum PlanetToOrchestrator {
89 /// This variant is used to acknowledge the obtained [Sunray]
90 ///
91 /// **Response to**: [`OrchestratorToPlanet::Sunray`]
92 SunrayAck {
93 ///ID of the planet sending the message
94 planet_id: ID,
95 },
96 /// This variant is used to acknowledge the obtained [Asteroid] and notify the orchestrator
97 /// if the planet has a rocket to defend itself
98 ///
99 /// **Response to**: [`OrchestratorToPlanet::Asteroid`]
100 AsteroidAck {
101 ///ID of the planet sending the message
102 planet_id: ID,
103 ///Optional rocket returned to the Orchestrator to decide if planet can deflect the asteroid
104 rocket: Option<Rocket>,
105 },
106 /// This variant is used to acknowledge the starting of the Planet Ai
107 ///
108 /// **Response to**: [`OrchestratorToPlanet::StartPlanetAI`]
109 StartPlanetAIResult {
110 ///ID of the planet sending the message
111 planet_id: ID,
112 },
113 /// This variant is used to acknowledge the stopping of the Planet Ai, in this state a planet will only respond
114 /// to incoming messages with a [`PlanetToOrchestrator::Stopped`]
115 ///
116 /// **Response to**: [`OrchestratorToPlanet::StopPlanetAI`]
117 StopPlanetAIResult {
118 ///ID of the planet sending the message
119 planet_id: ID,
120 },
121 /// This variant is used to acknowledge the killing of a planet, in this case the planet thread will be terminated
122 /// and the planet will be deleted from the galaxy
123 ///
124 /// **Response to**: [`OrchestratorToPlanet::KillPlanet`]
125 KillPlanetResult { planet_id: ID },
126 /// This variant is used to send back the Planet State
127 ///
128 /// **Response to** [`OrchestratorToPlanet::InternalStateRequest`]
129 InternalStateResponse {
130 ///ID of the planet sending the message
131 planet_id: ID,
132 ///A struct containing the relevant information of a Planet to be shown by the GUI
133 planet_state: DummyPlanetState,
134 },
135 /// This variant is used to acknowledge the incoming explorer reception
136 ///
137 /// **Response to** [`OrchestratorToPlanet::IncomingExplorerRequest`]
138 IncomingExplorerResponse {
139 ///ID of the planet sending the message
140 planet_id: ID,
141 ///Incoming explorer's ID
142 explorer_id: ID,
143 ///Result of the operation:
144 ///
145 /// [Ok] if the [Sender] to the incoming explorer has been correctly set up
146 ///
147 /// [Err(String)] if an error occurred
148 res: Result<(), String>,
149 },
150 /// This variant is used to acknowledge that an explorer is leaving the planet
151 ///
152 /// **Response to**: [`OrchestratorToPlanet::OutgoingExplorerRequest`]
153 OutgoingExplorerResponse {
154 ///ID of the planet sending the message
155 planet_id: ID,
156 ///Incoming explorer's ID
157 explorer_id: ID,
158 ///Result of the operation:
159 ///
160 /// [Ok] if the [Sender] to the outgoing explorer has been correctly deleted
161 ///
162 /// [Err(String)] if an error occurred
163 res: Result<(), String>,
164 },
165 /// This variant is used by planets that are currently in a *stopped* state
166 /// to acknowledge any message coming from the Orchestrator (except for [`OrchestratorToPlanet::StartPlanetAI`])
167 Stopped {
168 ///ID of the planet sending the message
169 planet_id: ID,
170 },
171}
172impl PlanetToOrchestrator {
173 /// Helper method to extract the `planet_id` field from any message variant
174 /// without needing to match a specific one.
175 #[must_use]
176 pub fn planet_id(&self) -> ID {
177 match self {
178 PlanetToOrchestrator::SunrayAck { planet_id, .. }
179 | PlanetToOrchestrator::AsteroidAck { planet_id, .. }
180 | PlanetToOrchestrator::StartPlanetAIResult { planet_id, .. }
181 | PlanetToOrchestrator::StopPlanetAIResult { planet_id, .. }
182 | PlanetToOrchestrator::KillPlanetResult { planet_id, .. }
183 | PlanetToOrchestrator::InternalStateResponse { planet_id, .. }
184 | PlanetToOrchestrator::IncomingExplorerResponse { planet_id, .. }
185 | PlanetToOrchestrator::OutgoingExplorerResponse { planet_id, .. }
186 | PlanetToOrchestrator::Stopped { planet_id, .. } => *planet_id,
187 }
188 }
189}