use super::types::{ItemId, MarketData, MarketEvent, PriceChange};
#[async_trait::async_trait]
pub trait MarketHook: Send + Sync {
async fn adjust_price(
&self,
_item_id: &ItemId,
calculated_price: f32,
_data: &MarketData,
) -> Option<f32> {
Some(calculated_price) }
async fn on_prices_updated(&self, _changes: &[PriceChange]) {
}
async fn on_event_applied(&self, _event: &MarketEvent, _affected_items: &[ItemId]) {
}
async fn calculate_demand(&self, _item_id: &ItemId, _current_demand: f32) -> Option<f32> {
None }
async fn calculate_supply(&self, _item_id: &ItemId, _current_supply: f32) -> Option<f32> {
None }
async fn can_trade_item(&self, _item_id: &ItemId) -> bool {
true }
async fn get_event_impact_multiplier(
&self,
_event: &MarketEvent,
_item_id: &ItemId,
) -> Option<f32> {
None }
}
#[derive(Clone, Copy, Debug, Default)]
pub struct DefaultMarketHook;
#[async_trait::async_trait]
impl MarketHook for DefaultMarketHook {}
#[cfg(test)]
mod tests {
use super::*;
use crate::plugin::market::{MarketData, MarketEvent, PriceChange};
#[tokio::test]
async fn test_default_hook_adjust_price() {
let hook = DefaultMarketHook;
let data = MarketData::new("test", 100.0);
let adjusted = hook.adjust_price(&"test".to_string(), 150.0, &data).await;
assert_eq!(adjusted, Some(150.0)); }
#[tokio::test]
async fn test_default_hook_on_prices_updated() {
let hook = DefaultMarketHook;
let changes = vec![PriceChange::new("test".to_string(), 100.0, 150.0)];
hook.on_prices_updated(&changes).await;
}
#[tokio::test]
async fn test_default_hook_on_event_applied() {
let hook = DefaultMarketHook;
let event = MarketEvent::demand_shock(vec!["test".to_string()], 0.5);
hook.on_event_applied(&event, &["test".to_string()]).await;
}
#[tokio::test]
async fn test_default_hook_calculate_demand() {
let hook = DefaultMarketHook;
let demand = hook.calculate_demand(&"test".to_string(), 0.5).await;
assert_eq!(demand, None); }
#[tokio::test]
async fn test_default_hook_calculate_supply() {
let hook = DefaultMarketHook;
let supply = hook.calculate_supply(&"test".to_string(), 0.5).await;
assert_eq!(supply, None); }
#[tokio::test]
async fn test_default_hook_can_trade_item() {
let hook = DefaultMarketHook;
let can_trade = hook.can_trade_item(&"test".to_string()).await;
assert!(can_trade); }
#[tokio::test]
async fn test_default_hook_get_event_impact_multiplier() {
let hook = DefaultMarketHook;
let event = MarketEvent::demand_shock(vec!["test".to_string()], 0.5);
let multiplier = hook
.get_event_impact_multiplier(&event, &"test".to_string())
.await;
assert_eq!(multiplier, None); }
#[tokio::test]
async fn test_custom_hook() {
#[derive(Clone, Copy)]
struct CustomHook;
#[async_trait::async_trait]
impl MarketHook for CustomHook {
async fn adjust_price(
&self,
item_id: &ItemId,
calculated_price: f32,
_data: &MarketData,
) -> Option<f32> {
if item_id == "food" && calculated_price > 50.0 {
Some(50.0)
} else {
Some(calculated_price)
}
}
async fn can_trade_item(&self, item_id: &ItemId) -> bool {
item_id != "contraband"
}
}
let hook = CustomHook;
let data = MarketData::new("food", 100.0);
let price = hook.adjust_price(&"food".to_string(), 80.0, &data).await;
assert_eq!(price, Some(50.0));
let price = hook.adjust_price(&"water".to_string(), 80.0, &data).await;
assert_eq!(price, Some(80.0));
assert!(hook.can_trade_item(&"food".to_string()).await);
assert!(!hook.can_trade_item(&"contraband".to_string()).await);
}
}