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
//! Service system for ISSUN
//!
//! Services provide reusable game systems and utilities
use crate::context::Context;
use async_trait::async_trait;
use std::any::Any;
/// Service trait for game systems
///
/// Services are reusable systems that provide functionality to the game.
/// Examples: DamageCalculator, PathFinder, DialogueSystem, QuestManager
#[async_trait]
pub trait Service: Send + Sync + 'static {
/// Service name (must be unique)
fn name(&self) -> &'static str;
/// Clone this service as a boxed trait object
///
/// Services are expected to be lightweight and typically `Clone`.
/// This enables the builder to duplicate services across contexts.
fn clone_box(&self) -> Box<dyn Service>;
/// Initialize service (called once at startup)
async fn initialize(&mut self, _ctx: &mut Context) {}
/// Optional: Called each frame if service needs to update
async fn update(&mut self, _ctx: &mut Context) {}
/// Optional: Shutdown cleanup
async fn shutdown(&mut self, _ctx: &mut Context) {}
/// Downcast to Any for type-safe access
fn as_any(&self) -> &dyn Any;
/// Downcast to Any for type-safe mutable access
fn as_any_mut(&mut self) -> &mut dyn Any;
}
/// Example: Damage calculation service
#[cfg(test)]
mod tests {
use super::*;
#[derive(Clone)]
struct DamageCalculatorService {
critical_multiplier: f32,
}
impl DamageCalculatorService {
fn new() -> Self {
Self {
critical_multiplier: 2.0,
}
}
fn calculate_damage(&self, base_damage: i32, is_critical: bool) -> i32 {
if is_critical {
(base_damage as f32 * self.critical_multiplier) as i32
} else {
base_damage
}
}
}
#[async_trait]
impl Service for DamageCalculatorService {
fn name(&self) -> &'static str {
"damage_calculator"
}
fn clone_box(&self) -> Box<dyn Service> {
Box::new(self.clone())
}
async fn initialize(&mut self, _ctx: &mut Context) {
// Load configuration, etc.
}
fn as_any(&self) -> &dyn Any {
self
}
fn as_any_mut(&mut self) -> &mut dyn Any {
self
}
}
#[tokio::test]
async fn test_service_creation() {
let service = DamageCalculatorService::new();
assert_eq!(service.name(), "damage_calculator");
}
#[tokio::test]
async fn test_service_damage_calculation() {
let service = DamageCalculatorService::new();
assert_eq!(service.calculate_damage(100, false), 100);
assert_eq!(service.calculate_damage(100, true), 200);
}
#[tokio::test]
async fn test_service_initialize() {
let mut service = DamageCalculatorService::new();
let mut ctx = Context::new();
service.initialize(&mut ctx).await;
// Initialize should complete without error
}
}