common_game/protocols/orchestrator_explorer.rs
1//! # Orchestrator and Explorer protocol messages
2//!
3//! Defines the types of messages exchanged of the full duplex communication channel
4//! between the Orchestrator and the Explorers
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)
6use crate::components::resource::{BasicResourceType, ComplexResourceType};
7use crate::protocols::planet_explorer::ExplorerToPlanet;
8use crate::utils::ID;
9use crossbeam_channel::Sender;
10use enum_as_inner::EnumAsInner;
11use std::collections::HashSet;
12use strum_macros::EnumDiscriminants;
13
14#[cfg(doc)]
15use crate::components::resource::{BasicResource, ComplexResource};
16
17/// This enum describes all possible messages from the Orchestrator to an Explorer
18#[derive(Debug, EnumAsInner, EnumDiscriminants)]
19#[strum_discriminants(name(OrchestratorToExplorerKind))]
20#[strum_discriminants(derive(Hash))]
21pub enum OrchestratorToExplorer {
22 /// This variant is used to start an Explorer AI
23 ///
24 /// **Expected Response**: [`ExplorerToOrchestrator::StartExplorerAIResult`]
25 ///
26 /// **Use Case**: Starting the Explorer AI at game start
27 StartExplorerAI,
28 /// This variant is used to reset the Explorer AI and restart it if it is in manual mode
29 ///
30 /// **Expected Response**: [`ExplorerToOrchestrator::ResetExplorerAIResult`]
31 ///
32 /// **Use Case**: Reset the Explorer knowledge or restart the AI if it is in manual mode
33 ResetExplorerAI,
34 /// This variant is used to kill an Explorer
35 ///
36 /// **Expected Response**: [`ExplorerToOrchestrator::KillExplorerResult`]
37 ///
38 /// **Use Case**: Killing the explorer instantly
39 KillExplorer,
40 ///This variant is used to stop the Explorer AI from autonomous decision-making
41 ///
42 /// **Expected Response**: [`ExplorerToOrchestrator::StopExplorerAIResult`]
43 ///
44 /// **Use Case**: Stopping the autonomous decision-making and entering the manual mode
45 StopExplorerAI,
46 /// This variant is used to tell the Explorer to move to a different planet
47 ///
48 /// **Expected Response**: [`ExplorerToOrchestrator::MovedToPlanetResult`]
49 ///
50 /// **Use Case**
51 ///
52 /// When in manual mode, the orchestrator moves the explorer to a new planet and gives the new [Sender]
53 ///
54 /// When in normal mode, this is the response to [`ExplorerToOrchestrator::TravelToPlanetRequest`], in this case
55 /// the orchestrator checks that the explorer can move to the planet specified in the request and sends the optional new sender
56 MoveToPlanet {
57 ///The optional [Sender] to the new planet, [None] if explorer cannot move to the specified planet
58 sender_to_new_planet: Option<Sender<ExplorerToPlanet>>,
59 ///The ID of the planet to which the explorer will possibly move
60 planet_id: ID,
61 },
62 /// This variant is used to ask the ID of the Planet in which the Explorer is currently located
63 ///
64 /// **Expected Response**: [`ExplorerToOrchestrator::CurrentPlanetResult`]
65 CurrentPlanetRequest,
66 /// This variant is used to enforce the Explorer to ask the supported Resources on the Planet
67 ///
68 /// **Expected Response**: [`ExplorerToOrchestrator::SupportedResourceResult`]
69 ///
70 /// **Use Case**: In manual mode, ask the explorer to send a [`ExplorerToPlanet::SupportedResourceRequest`] to know the available [`BasicResourceType`] on its current planet
71 SupportedResourceRequest,
72 /// This variant is used to enforce the Explorer to ask the supported Combinations on the Planet
73 ///
74 /// **Expected Response**: [`ExplorerToOrchestrator::SupportedCombinationResult`]
75 ///
76 /// **Use Case**: In manual mode, ask the explorer to send a [`ExplorerToPlanet::SupportedCombinationRequest`] to know the available [`ComplexResourceType`] on its current planet
77 SupportedCombinationRequest,
78 /// This variant is used to enforce the Explorer to ask the Planet to Generate a [`BasicResource`]
79 ///
80 /// **Expected Response**: [`ExplorerToOrchestrator::GenerateResourceResponse`]
81 ///
82 /// **Use Case**: In manual mode, ask the explorer to send a [`ExplorerToPlanet::GenerateResourceRequest`] craft a [`BasicResource`]
83 GenerateResourceRequest {
84 ///The type of basic resource to craft
85 to_generate: BasicResourceType,
86 },
87 /// This variant is used to enforce the Explorer to ask the Planet to Generate a [`ComplexResource`] provided by [`ComplexResourceType`]
88 ///
89 /// **Expected Response**: [`ExplorerToOrchestrator::CombineResourceResponse`]
90 ///
91 /// **Use Case**: In manual mode, ask the explorer to send a [`ExplorerToPlanet::CombineResourceRequest`] to craft a [`ComplexResource`]
92 CombineResourceRequest {
93 ///The type of complex resource to generate
94 to_generate: ComplexResourceType,
95 },
96 /// This variant is used to ask the content of the Explorer Bag
97 ///
98 /// **Expected Response**: [`ExplorerToOrchestrator::BagContentResponse`]
99 ///
100 /// **Use Case**: Message used by the GUI to get information on the Explorer bag content to be shown
101 BagContentRequest,
102 /// This variant is used to send to the Explorer the IDs of the planets to which it can be moved
103 ///
104 /// **Response To**: [`ExplorerToOrchestrator::NeighborsRequest`]
105 NeighborsResponse {
106 ///The list of IDs of the planets to which it can be moved
107 neighbors: Vec<ID>,
108 },
109}
110/// This enum describes all possible messages from an Explorer to the Orchestrator
111#[derive(Debug, EnumAsInner, EnumDiscriminants)]
112#[strum_discriminants(name(ExplorerToOrchestratorKind))]
113#[strum_discriminants(derive(Hash))]
114pub enum ExplorerToOrchestrator<T> {
115 /// This variant is used to acknowledge the starting of the Explorer AI
116 ///
117 /// **Response To**: [`OrchestratorToExplorer::StartExplorerAI`]
118 StartExplorerAIResult {
119 ///The ID of the Explorer sending the message
120 explorer_id: ID,
121 },
122 /// This variant is used to acknowledge the killing of an Explorer
123 ///
124 /// **Response To**: [`OrchestratorToExplorer::KillExplorer`]
125 KillExplorerResult {
126 ///The ID of the Explorer sending the message
127 explorer_id: ID,
128 },
129 /// This variant is used to acknowledge the reset of the Explorer AI
130 ///
131 /// **Response To**: [`OrchestratorToExplorer::ResetExplorerAI`]
132 ResetExplorerAIResult {
133 ///The ID of the Explorer sending the message
134 explorer_id: ID,
135 },
136 /// This variant is used to acknowledge the stopping of the Explorer AI
137 ///
138 /// **Response To**: [`OrchestratorToExplorer::StopExplorerAI`]
139 StopExplorerAIResult {
140 ///The ID of the Explorer sending the message
141 explorer_id: ID,
142 },
143 /// This variant is used to acknowledge the transfer of an Explorer to a new Planet
144 ///
145 /// **Response To**: [`OrchestratorToExplorer::MoveToPlanet`]
146 MovedToPlanetResult {
147 ///The ID of the Explorer sending the message
148 explorer_id: ID,
149 ///The ID of the planet to which the explorer possibly moved
150 planet_id: ID,
151 },
152 /// This variant is used to send the ID of the current planet on which the Explorer is located
153 ///
154 /// **Response To**: [`OrchestratorToExplorer::CurrentPlanetRequest`]
155 CurrentPlanetResult {
156 ///The ID of the explorer sending the message
157 explorer_id: ID,
158 ///The ID of the planet it currently lives on
159 planet_id: ID,
160 },
161 /// This variant is used to send the list of the available [`BasicResourceType`] in the Explorer's current planet
162 ///
163 /// **Response To**: [`OrchestratorToExplorer::SupportedResourceRequest`]
164 SupportedResourceResult {
165 ///The ID of the explorer sending the message
166 explorer_id: ID,
167 ///The Set of [`BasicResourceType`] available in the Explorer's current planet
168 supported_resources: HashSet<BasicResourceType>,
169 },
170 /// This variant is used to send the list of the available [`ComplexResourceType`] in the Explorer's current planet
171 ///
172 /// **Response To**: [`OrchestratorToExplorer::SupportedCombinationRequest`]
173 SupportedCombinationResult {
174 ///The ID of the explorer sending the message
175 explorer_id: ID,
176 ///The Set of [`ComplexResourceType`] available in the Explorer's current planet
177 combination_list: HashSet<ComplexResourceType>,
178 },
179 /// This variant is used to send the generated Basic Resource asked by the Orchestrator
180 ///
181 /// **Response To**: [`OrchestratorToExplorer::GenerateResourceRequest`]
182 GenerateResourceResponse {
183 ///The ID of the Explorer sending the message
184 explorer_id: ID,
185 ///A Result consisting of: [Ok] if the requested resource has been generated and added to the Explorer Bag
186 ///
187 ///An [Err] String if the requested resource has not been generated
188 generated: Result<(), String>,
189 },
190 /// This variant is used to send the generated [`ComplexResource`] asked by the Orchestrator
191 ///
192 /// **Response To**: [`OrchestratorToExplorer::CombineResourceRequest`]
193 CombineResourceResponse {
194 ///The ID of the Explorer sending the message
195 explorer_id: ID,
196 ///A Result consisting of: [Ok] if the requested resource has been generated and added to the Explorer Bag
197 ///
198 ///An [Err] String if the requested resource has not been generated
199 generated: Result<(), String>,
200 },
201 /// This message is for passing around the bag content and has been implemented with a generic type to let the group the freedom to implement the methods on it
202 ///
203 /// **Response To**: [`OrchestratorToExplorer::BagContentRequest`]
204 BagContentResponse {
205 ///The ID of the explorer sending the message
206 explorer_id: ID,
207 ///The generic `bag_content` type
208 bag_content: T,
209 },
210 /// This variant asks the Orchestrator for the list of neighbors Planets to travel to
211 ///
212 /// **Expected Response**: [`OrchestratorToExplorer::NeighborsResponse`]
213 ///
214 /// **Use Case**: Knowing reachable planets from current planet
215 NeighborsRequest {
216 ///The ID of the Explorer sending the message
217 explorer_id: ID,
218 ///The ID of the current planet the Explorer lives on
219 current_planet_id: ID,
220 },
221 /// This variant asks the Orchestrator to be sent to the specified Planet
222 ///
223 /// **Expected Response**: [`OrchestratorToExplorer::MoveToPlanet`]
224 ///
225 /// **Use Case**: Autonomously asking to travel to a planet
226 TravelToPlanetRequest {
227 ///The ID of the Explorer sending the message
228 explorer_id: ID,
229 ///The ID of the current planet the Explorer lives on
230 current_planet_id: ID,
231 ///The ID of the planet the Explorer wants to travel to
232 dst_planet_id: ID,
233 },
234}
235
236impl<T> ExplorerToOrchestrator<T> {
237 /// Helper method to extract the `explorer_id` field from any message variant
238 /// without needing to match a specific one.
239 pub fn explorer_id(&self) -> ID {
240 match self {
241 Self::StartExplorerAIResult { explorer_id, .. }
242 | Self::KillExplorerResult { explorer_id, .. }
243 | Self::ResetExplorerAIResult { explorer_id, .. }
244 | Self::MovedToPlanetResult { explorer_id, .. }
245 | Self::CurrentPlanetResult { explorer_id, .. }
246 | Self::SupportedResourceResult { explorer_id, .. }
247 | Self::SupportedCombinationResult { explorer_id, .. }
248 | Self::GenerateResourceResponse { explorer_id, .. }
249 | Self::CombineResourceResponse { explorer_id, .. }
250 | Self::BagContentResponse { explorer_id, .. }
251 | Self::NeighborsRequest { explorer_id, .. }
252 | Self::TravelToPlanetRequest { explorer_id, .. }
253 | Self::StopExplorerAIResult { explorer_id, .. } => *explorer_id,
254 }
255 }
256}