use std::marker::PhantomData;
use bevy_ecs::component::Component;
use bevy_ecs::resource::Resource;
use brink_runtime::Context;
#[derive(Resource)]
pub struct BrinkGlobals<M: Send + Sync + 'static = ()> {
pub inner: Context,
_marker: PhantomData<fn() -> M>,
}
impl<M: Send + Sync + 'static> BrinkGlobals<M> {
#[must_use]
pub fn new(context: Context) -> Self {
Self {
inner: context,
_marker: PhantomData,
}
}
pub fn commit_from(&mut self, flow_ctx: &Context) {
self.inner = flow_ctx.clone();
}
pub fn commit_progress(&mut self, flow_ctx: &Context) {
self.inner.globals.clone_from(&flow_ctx.globals);
for (id, count) in &flow_ctx.visit_counts {
let entry = self.inner.visit_counts.entry(*id).or_insert(0);
*entry = (*entry).max(*count);
}
for (id, turn) in &flow_ctx.turn_counts {
let entry = self.inner.turn_counts.entry(*id).or_insert(0);
*entry = (*entry).max(*turn);
}
self.inner.turn_index = self.inner.turn_index.max(flow_ctx.turn_index);
self.inner.rng_seed = flow_ctx.rng_seed;
self.inner.previous_random = flow_ctx.previous_random;
}
pub fn commit_globals_only(&mut self, flow_ctx: &Context) {
self.inner.globals.clone_from(&flow_ctx.globals);
}
}
#[derive(Component)]
pub struct BrinkContext<M: Send + Sync + 'static = ()> {
pub inner: Context,
_marker: PhantomData<fn() -> M>,
}
impl<M: Send + Sync + 'static> BrinkContext<M> {
#[must_use]
pub fn new(context: Context) -> Self {
Self {
inner: context,
_marker: PhantomData,
}
}
}
#[cfg(test)]
mod commit_tests {
use super::*;
use brink_format::{DefinitionId, DefinitionTag, Value};
use brink_runtime::Context;
use std::collections::HashMap;
fn ctx_with(globals: Vec<Value>, visits: &[(u64, u32)], turn_index: u32) -> Context {
let mut visit_counts = HashMap::new();
for (id, count) in visits {
visit_counts.insert(DefinitionId::new(DefinitionTag::Address, *id), *count);
}
Context {
globals,
visit_counts,
turn_counts: HashMap::new(),
turn_index,
rng_seed: 0,
previous_random: 0,
}
}
#[test]
fn commit_from_replaces_wholesale() {
let mut globals =
BrinkGlobals::<()>::new(ctx_with(vec![Value::Int(1), Value::Int(2)], &[(0, 5)], 10));
let flow_ctx = ctx_with(vec![Value::Int(99), Value::Int(100)], &[(0, 1)], 3);
globals.commit_from(&flow_ctx);
assert!(matches!(globals.inner.globals[0], Value::Int(99)));
assert_eq!(
globals.inner.visit_counts[&DefinitionId::new(DefinitionTag::Address, 0)],
1
);
assert_eq!(globals.inner.turn_index, 3);
}
#[test]
fn commit_progress_takes_max_of_counts() {
let mut globals =
BrinkGlobals::<()>::new(ctx_with(vec![Value::Int(1)], &[(0, 5), (1, 2)], 10));
let flow_ctx = ctx_with(vec![Value::Int(99)], &[(0, 3), (2, 7)], 4);
globals.commit_progress(&flow_ctx);
assert!(matches!(globals.inner.globals[0], Value::Int(99)));
assert_eq!(
globals.inner.visit_counts[&DefinitionId::new(DefinitionTag::Address, 0)],
5
);
assert_eq!(
globals.inner.visit_counts[&DefinitionId::new(DefinitionTag::Address, 1)],
2
);
assert_eq!(
globals.inner.visit_counts[&DefinitionId::new(DefinitionTag::Address, 2)],
7
);
assert_eq!(globals.inner.turn_index, 10);
}
#[test]
fn commit_globals_only_leaves_counts_alone() {
let mut globals = BrinkGlobals::<()>::new(ctx_with(vec![Value::Int(1)], &[(0, 5)], 10));
let flow_ctx = ctx_with(vec![Value::Int(99)], &[(0, 99)], 99);
globals.commit_globals_only(&flow_ctx);
assert!(matches!(globals.inner.globals[0], Value::Int(99)));
assert_eq!(
globals.inner.visit_counts[&DefinitionId::new(DefinitionTag::Address, 0)],
5
);
assert_eq!(globals.inner.turn_index, 10);
}
}