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
//! Management of gas in buildings

use derive_new::new;
use legion::world::SubWorld;
use legion::Entity;
use smallvec::SmallVec;
use typed_builder::TypedBuilder;

use crate::clock::{SimulationEvent, SIMULATION_PERIOD};
use crate::def::gas;
use crate::time::Instant;
use crate::units::{self, GasVolume};
use crate::{util, SetupEcs};

/// A component attached to entities that house gas.
#[derive(new, getset::Getters)]
pub struct StorageList {
    /// The list of gases stored in the entity.
    #[getset(get = "pub")]
    storages: SmallVec<[(gas::Id, Entity); 4]>,
}

/// A component attached to nodes to inidcate cargo capacity of the node.
#[derive(Debug, Clone, Copy, new, getset::CopyGetters)]
pub struct StorageCapacity {
    /// The maximum total cargo size.
    #[getset(get_copy = "pub")]
    total: GasVolume,
}

/// A component attached to storage entities.
#[derive(new, getset::CopyGetters)]
pub struct Storage {
    /// The type of gas.
    #[getset(get_copy = "pub")]
    gas: gas::Id,
}

/// The size of a gas storage in the current simulation frame.
#[derive(new, getset::CopyGetters)]
pub struct StorageSize {
    /// The gas size
    #[getset(get_copy = "pub")]
    size: GasVolume,
}

/// The size of a gas storage in the next simulation frame.
#[derive(new, getset::CopyGetters, getset::MutGetters)]
pub struct NextStorageSize {
    /// The gas size
    #[getset(get_copy = "pub")]
    #[getset(get_mut = "pub")]
    size: GasVolume,
}

codegen::component_depends! {
    Storage = (
        Storage,
        StorageSize,
        NextStorageSize,
    ) + ?()
}

/// Interpolates the current graphical size of a storage.
pub fn lerp(current: &StorageSize, next: &NextStorageSize, time: Instant) -> GasVolume {
    GasVolume(util::lerp(
        current.size.value(),
        next.size.value(),
        (time.since_epoch() % SIMULATION_PERIOD).as_secs() / SIMULATION_PERIOD.as_secs(),
    ))
}

/// A component applied on a node that drives gas.
#[derive(TypedBuilder, getset::CopyGetters)]
pub struct Pump {
    /// The force provided by the pump.
    #[getset(get_copy = "pub")]
    force: units::FanForce,
}

#[codegen::system(PreSimulate)]
#[write_component(StorageSize)]
#[read_component(NextStorageSize)]
fn update_storage(
    world: &mut SubWorld,
    #[subscriber] sim_sub: impl Iterator<Item = SimulationEvent>,
) {
    use legion::IntoQuery;

    if sim_sub.next().is_none() {
        return;
    }

    for (current, next) in <(&mut StorageSize, &NextStorageSize)>::query().iter_mut(world) {
        current.size = next.size;
    }
}

/// Initializes ECS
pub fn setup_ecs(setup: SetupEcs) -> SetupEcs { setup.uses(update_storage_setup) }