konnektoren_core/controller/
challenge_finish_plugin.rs

1use super::GameControllerTrait;
2use super::{ControllerPlugin, ControllerPluginError};
3use crate::challenges::{Challenge, ChallengeResult};
4use crate::commands::{ChallengeCommand, Command, CommandType};
5use crate::controller::ControllerError;
6use std::sync::Arc;
7
8pub struct ChallengeFinishPlugin;
9
10impl ChallengeFinishPlugin {
11    fn handle_challenge_finish(
12        game_controller: Arc<dyn GameControllerTrait>,
13        challenge: &Challenge,
14        result: &ChallengeResult,
15    ) -> Result<(), ControllerError> {
16        {
17            let mut game_state = game_controller
18                .game_state()
19                .lock()
20                .map_err(|_| ControllerError::StateLock)?;
21
22            if game_state.challenge.challenge_config.id != challenge.challenge_config.id {
23                return Ok(());
24            }
25
26            game_state.challenge.challenge_result = result.clone();
27            game_state
28                .game
29                .challenge_history
30                .add_challenge(challenge.clone());
31        }
32
33        game_controller.save_game_state()?;
34        Ok(())
35    }
36}
37
38impl ControllerPlugin for ChallengeFinishPlugin {
39    fn name(&self) -> &str {
40        "ChallengeFinishPlugin"
41    }
42
43    fn init(&self) -> Result<(), ControllerPluginError> {
44        Ok(())
45    }
46
47    fn load(
48        &self,
49        game_controller: Arc<dyn GameControllerTrait>,
50    ) -> Result<(), ControllerPluginError> {
51        let game_controller_clone = game_controller.clone();
52        game_controller
53            .command_bus()
54            .subscribe(CommandType::Challenge, move |command| {
55                if let Command::Challenge(ChallengeCommand::Finish(Some(result))) = command {
56                    let challenge = match game_controller_clone.game_state().lock() {
57                        Ok(state) => state.challenge.clone(),
58                        Err(_) => {
59                            log::error!("Failed to lock game state in ChallengeFinishPlugin");
60                            return;
61                        }
62                    };
63
64                    if let Err(e) = Self::handle_challenge_finish(
65                        game_controller_clone.clone(),
66                        &challenge,
67                        &result,
68                    ) {
69                        log::error!("Error in challenge finish handler: {:?}", e);
70                    }
71                }
72            });
73
74        Ok(())
75    }
76
77    fn unload(
78        &self,
79        _game_controller: Arc<dyn GameControllerTrait>,
80    ) -> Result<(), ControllerPluginError> {
81        Ok(())
82    }
83}
84
85#[cfg(test)]
86mod tests {
87    use super::*;
88    use crate::challenges::{Challenge, ChallengeConfig, ChallengeResult, ChallengeType};
89    use crate::controller::game_controller::MockGameControllerTrait;
90    use std::sync::{Arc, Mutex};
91
92    #[test]
93    fn test_handle_challenge_finish_updates_state_and_saves() {
94        let mut mock_controller = MockGameControllerTrait::new();
95
96        // Setup a challenge and result
97        let challenge = Challenge::new(&ChallengeType::default(), &ChallengeConfig::default());
98        let result = ChallengeResult::default();
99
100        // Setup game state
101        let game_state = Mutex::new(crate::game::GameState {
102            challenge: challenge.clone(),
103            ..Default::default()
104        });
105        mock_controller
106            .expect_game_state()
107            .return_const(Arc::new(game_state));
108        mock_controller
109            .expect_save_game_state()
110            .returning(|| Ok(()));
111
112        // Should update state and call save_game_state
113        let res = ChallengeFinishPlugin::handle_challenge_finish(
114            Arc::new(mock_controller),
115            &challenge,
116            &result,
117        );
118        assert!(res.is_ok());
119    }
120}