-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathrules.rs
executable file
·129 lines (112 loc) · 4.02 KB
/
rules.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
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<CustomRules> 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<P: EventProcessor<CustomRules>>(
processor: &mut P,
name: String,
) -> MakePizzaTrigger<P> {
MakePizzaTrigger { processor, name }
}
}
impl Event<CustomRules> for MakePizza {
fn verify(&self, _battle: &Battle<CustomRules>) -> 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<CustomRules>,
_event_queue: &mut Option<EventQueue<CustomRules>>,
) {
// 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<dyn Event<CustomRules> + 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<CustomRules>,
{
processor: &'a mut P,
name: String,
}
impl<'a, P> EventTrigger<'a, CustomRules, P> for MakePizzaTrigger<'a, P>
where
P: EventProcessor<CustomRules>,
{
fn processor(&'a mut self) -> &'a mut P {
self.processor
}
/// Returns a `MakePizza` event.
fn event(&self) -> Box<dyn Event<CustomRules> + 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<CustomRules> for EventPackage {
/// In this method we extract an event trait object out of a packaged user event.
fn boxed(self) -> WeaselResult<Box<dyn Event<CustomRules> + Send>, CustomRules> {
let event = match self {
Self::MakePizza(event) => Box::new(event) as Box<dyn Event<CustomRules> + Send>,
};
Ok(event)
}
/// This method packages a boxed user event into an instance of EventPackage.
fn flattened(event: Box<dyn Event<CustomRules> + Send>) -> WeaselResult<Self, CustomRules> {
match event.as_any().downcast_ref::<MakePizza>() {
Some(event) => Ok(Self::MakePizza(event.clone())),
None => Err(WeaselError::UserEventPackingError(
event.clone(),
"bad cast".into(),
)),
}
}
}