mod groups;
mod resources;
#[cfg(test)]
mod tests;
use crate::hooks::{HookRegistry, OnAddHook, OnRemoveHook};
use crate::resource::{Resource, ResourceTrait};
use crate::scheduler::{ScheduleError, ScheduleStage, SimpleScheduler, SystemConfig, SystemGroup};
use crate::simple_world::SimpleWorld;
use crate::system::{AppSystem, SystemContext};
use alloc::vec::Vec;
use soroban_sdk::{Env, Symbol};
pub trait Plugin {
fn name(&self) -> &'static str;
fn build(&self, app: &mut GameApp);
}
pub trait PluginGroup {
fn build(self, app: &mut GameApp);
}
pub struct GameApp {
world: SimpleWorld,
scheduler: SimpleScheduler,
hooks: HookRegistry,
resources: Vec<Resource>,
plugins_registered: Vec<&'static str>,
startup_ran: bool,
}
impl GameApp {
pub fn new(env: &Env) -> Self {
Self {
world: SimpleWorld::new(env),
scheduler: SimpleScheduler::new(),
hooks: HookRegistry::new(),
resources: Vec::new(),
plugins_registered: Vec::new(),
startup_ran: false,
}
}
pub fn with_world(world: SimpleWorld) -> Self {
Self {
world,
scheduler: SimpleScheduler::new(),
hooks: HookRegistry::new(),
resources: Vec::new(),
plugins_registered: Vec::new(),
startup_ran: false,
}
}
pub fn add_plugin<P: Plugin>(&mut self, plugin: P) -> &mut Self {
let name = Plugin::name(&plugin);
if !self.has_plugin(name) {
self.plugins_registered.push(name);
Plugin::build(&plugin, self);
}
self
}
pub fn add_plugins<G: PluginGroup>(&mut self, group: G) -> &mut Self {
group.build(self);
self
}
pub fn add_system<F>(&mut self, name: &'static str, system: F) -> &mut Self
where
F: FnMut(&mut SimpleWorld, &Env) + 'static,
{
self.scheduler.add_system(name, system);
self
}
pub fn add_system_with_config<F>(
&mut self,
name: &'static str,
system: F,
config: SystemConfig,
) -> &mut Self
where
F: FnMut(&mut SimpleWorld, &Env) + 'static,
{
self.scheduler.add_system_with_config(name, system, config);
self
}
pub fn add_system_in_stage<F>(
&mut self,
stage: ScheduleStage,
name: &'static str,
system: F,
) -> &mut Self
where
F: FnMut(&mut SimpleWorld, &Env) + 'static,
{
self.scheduler.add_system_in_stage(stage, name, system);
self
}
pub fn add_context_system<F>(&mut self, name: &'static str, system: F) -> &mut Self
where
F: for<'w, 'e, 'c> FnMut(&mut SystemContext<'w, 'e, 'c>) + 'static,
{
self.scheduler.add_context_system(name, system);
self
}
pub fn add_context_system_with_config<F>(
&mut self,
name: &'static str,
system: F,
config: SystemConfig,
) -> &mut Self
where
F: for<'w, 'e, 'c> FnMut(&mut SystemContext<'w, 'e, 'c>) + 'static,
{
self.scheduler
.add_context_system_with_config(name, system, config);
self
}
pub fn add_context_system_in_stage<F>(
&mut self,
stage: ScheduleStage,
name: &'static str,
system: F,
) -> &mut Self
where
F: for<'w, 'e, 'c> FnMut(&mut SystemContext<'w, 'e, 'c>) + 'static,
{
self.scheduler
.add_context_system_in_stage(stage, name, system);
self
}
pub fn add_simple_system<S>(&mut self, name: &'static str, system: S) -> &mut Self
where
S: AppSystem + 'static,
{
self.scheduler.add_simple_system(name, system);
self
}
pub fn add_simple_system_with_config<S>(
&mut self,
name: &'static str,
system: S,
config: SystemConfig,
) -> &mut Self
where
S: AppSystem + 'static,
{
self.scheduler
.add_simple_system_with_config(name, system, config);
self
}
pub fn add_simple_system_in_stage<S>(
&mut self,
stage: ScheduleStage,
name: &'static str,
system: S,
) -> &mut Self
where
S: AppSystem + 'static,
{
self.scheduler
.add_simple_system_in_stage(stage, name, system);
self
}
pub fn add_systems<G>(&mut self, systems: G) -> &mut Self
where
G: SystemGroup,
{
self.scheduler.add_systems(systems);
self
}
pub fn add_systems_in_stage<G>(&mut self, stage: ScheduleStage, systems: G) -> &mut Self
where
G: SystemGroup,
{
self.scheduler.add_systems_in_stage(stage, systems);
self
}
pub fn add_startup_system<F>(&mut self, name: &'static str, system: F) -> &mut Self
where
F: FnMut(&mut SimpleWorld, &Env) + 'static,
{
self.add_system_with_config(
name,
system,
SystemConfig::new().in_stage(ScheduleStage::Startup),
)
}
pub fn add_hook_on_add(&mut self, component_type: Symbol, hook: OnAddHook) -> &mut Self {
self.hooks.on_add(component_type, hook);
self
}
pub fn add_hook_on_remove(&mut self, component_type: Symbol, hook: OnRemoveHook) -> &mut Self {
self.hooks.on_remove(component_type, hook);
self
}
pub fn insert_resource<R: ResourceTrait>(&mut self, env: &Env, resource: &R) -> &mut Self {
resources::insert_resource(&mut self.resources, env, resource);
self
}
pub fn get_resource<R: ResourceTrait>(&self, env: &Env) -> Option<R> {
resources::get_resource(&self.resources, env)
}
pub fn remove_resource<R: ResourceTrait>(&mut self) -> Option<Resource> {
resources::remove_resource::<R>(&mut self.resources)
}
pub fn world(&self) -> &SimpleWorld {
&self.world
}
pub fn world_mut(&mut self) -> &mut SimpleWorld {
&mut self.world
}
pub fn scheduler(&self) -> &SimpleScheduler {
&self.scheduler
}
pub fn hooks(&self) -> &HookRegistry {
&self.hooks
}
pub fn resources(&self) -> &Vec<Resource> {
&self.resources
}
pub fn run_startup(&mut self, env: &Env) -> Result<(), ScheduleError> {
if !self.startup_ran {
self.scheduler
.run_stage(ScheduleStage::Startup, &mut self.world, env)?;
self.startup_ran = true;
}
Ok(())
}
pub fn run(&mut self, env: &Env) -> Result<(), ScheduleError> {
self.run_startup(env)?;
self.scheduler
.run_stage(ScheduleStage::PreUpdate, &mut self.world, env)?;
self.scheduler
.run_stage(ScheduleStage::Update, &mut self.world, env)?;
self.scheduler
.run_stage(ScheduleStage::PostUpdate, &mut self.world, env)?;
self.scheduler
.run_stage(ScheduleStage::Cleanup, &mut self.world, env)?;
Ok(())
}
pub fn run_stage(&mut self, stage: ScheduleStage, env: &Env) -> Result<(), ScheduleError> {
if stage == ScheduleStage::Startup {
return self.run_startup(env);
}
self.scheduler.run_stage(stage, &mut self.world, env)
}
pub fn configure_system(
&mut self,
name: &str,
config: SystemConfig,
) -> Result<&mut Self, ScheduleError> {
self.scheduler.configure_system(name, config)?;
Ok(self)
}
pub fn into_world(self) -> SimpleWorld {
self.world
}
pub fn plugin_count(&self) -> usize {
self.plugins_registered.len()
}
pub fn has_plugin(&self, name: &str) -> bool {
self.plugins_registered.contains(&name)
}
pub fn system_count(&self) -> usize {
self.scheduler.system_count()
}
}