use serde::{Deserialize, Serialize}; use std::any::Any; use weasel::{ battle_rules, battle_rules_with_user, rules::empty::*, Battle, BattleRules, Event, EventKind, EventProcessor, EventQueue, EventTrigger, UserEventPacker, UserRules, WeaselError, WeaselResult, }; pub(crate) const PIZZAS_CREATED_METRIC: &str = "pizzas_created"; // It's not a real game so we can use generic no-op battle rules. // We still want to override the UserRules to define how to serialize our custom event and to // add custom metrics. battle_rules_with_user! { CustomUserRules } // Define our own user rules in order to have custom metrics and custom events. #[derive(Default)] pub struct CustomUserRules {} impl UserRules for CustomUserRules { // For our metrics we'll use a String id. type UserMetricId = String; // The type we will use to serialize and deserialize all user events. type UserEventPackage = EventPackage; } /// An user defined event. #[derive(Clone, Debug, Serialize, Deserialize)] pub struct MakePizza { // A simple data field containing the pizza's name. name: String, } impl MakePizza { /// Returns a trigger for this event. /// Triggers are not strictly required, but they offer a convenient way to fire events. pub(crate) fn trigger>( processor: &mut P, name: String, ) -> MakePizzaTrigger

{ MakePizzaTrigger { processor, name } } } impl Event for MakePizza { fn verify(&self, _battle: &Battle) -> WeaselResult<(), CustomRules> { // You should put here all the logic needed to verify if the event can be applied or not. // For the sake of the example the event is always accepted. Ok(()) } fn apply( &self, battle: &mut Battle, _event_queue: &mut Option>, ) { // In this method you can modify the battle state or even fire other events. // In this example the event does nothing except increasing a metric. let mut writer = battle.metrics_mut(); writer .add_user_u64(PIZZAS_CREATED_METRIC.to_string(), 1) .unwrap(); } fn kind(&self) -> EventKind { // This user event has id 0. If you add a second user event, it should have another id. EventKind::UserEvent(0) } fn box_clone(&self) -> Box + Send> { Box::new(self.clone()) } fn as_any(&self) -> &dyn Any { self } } /// Trigger to build and fire a `MakePizza` event. pub(crate) struct MakePizzaTrigger<'a, P> where P: EventProcessor, { processor: &'a mut P, name: String, } impl<'a, P> EventTrigger<'a, CustomRules, P> for MakePizzaTrigger<'a, P> where P: EventProcessor, { fn processor(&'a mut self) -> &'a mut P { self.processor } /// Returns a `MakePizza` event. fn event(&self) -> Box + Send> { Box::new(MakePizza { name: self.name.clone(), }) } } /// Type to serialize and deserialize user event. #[derive(Serialize, Deserialize)] pub(crate) enum EventPackage { MakePizza(MakePizza), } impl UserEventPacker for EventPackage { /// In this method we extract an event trait object out of a packaged user event. fn boxed(self) -> WeaselResult + Send>, CustomRules> { let event = match self { Self::MakePizza(event) => Box::new(event) as Box + Send>, }; Ok(event) } /// This method packages a boxed user event into an instance of EventPackage. fn flattened(event: Box + Send>) -> WeaselResult { match event.as_any().downcast_ref::() { Some(event) => Ok(Self::MakePizza(event.clone())), None => Err(WeaselError::UserEventPackingError( event.clone(), "bad cast".into(), )), } } }