For some time now I wanted to have an easy way as developer to generate large factories for testing purposes.
For this I introduced Generator
s that make it easy for a developer (me) to create factories.
Generators
I introduced the generic Generator
trait
pub trait Generator {
fn size(&self) -> Size<i64>;
fn generate(&self, ..., anchor: PosAnchor<i64>, target: &mut StructContainer) -> AddResult;
}
To be easily composable, it should report its size.
generate()
can then be used to ‘write’ its Structure
s to the target container. There’s also an anchor position to set the generators origin in the target.
I then introduced multiple Generator
primitives.
Single
which places a single Structure
(part of ContainerElement
):
The dev_foo()
calls are more efficient due to lack of checks, but are only available in developer builds.
pub struct Single {
element: ContainerElement,
size: Size<i64>,
}
impl Single {
...
}
impl Generator for Single {
fn size(&self) -> Size<i64> {
self.size
}
fn generate(&self, ms: &MS, anchor: PosAnchor<i64>, target: &mut StructContainer) -> AddResult {
let mut element = self.element.clone();
element.pos.0 += anchor.0;
target.dev_mark_pos_tree_dirty();
target.dev_add_unchecked(ms, element)?;
Ok(())
}
}
Many
to do the same for multiple Structure
s:
pub struct Many {
elements: Vec<ContainerElement>,
size: Size<i64>,
}
...
A Repeater
to place the content of its inner Generator
many times:
pub enum GenDir {
Right,
Down,
}
...
pub struct Repeater<G>
where
G: Generator,
{
times: u64,
padding: u32,
dir: GenDir,
inner: G,
size: Size<i64>,
}
...
An Aligned
to place the content of multiple child Generator
s next to each other:
pub struct Aligned {
dir: GenDir,
size: Size<i64>,
generators: Vec<Box<dyn Generator>>,
}
I also added some helper functions such as:
pub fn row_of(ms: &MS, sm: StructureModule, rot: Rot, times: u64, padding: u32) -> impl Generator {
Repeater::new(times, padding, GenDir::Right, Single::new(ms, rot, sm))
}
pub fn column_of(
ms: &MS,
sm: StructureModule,
rot: Rot,
times: u64,
padding: u32,
) -> impl Generator {
Repeater::new(times, padding, GenDir::Down, Single::new(ms, rot, sm))
}
With above it becomes rather easy to generate large factories from code.
Below generates multiple rows of Belt
s being fed by a Source
with Coal
, which eventually end up in a Hole
to be deleted.
There’s also Starter
Structure
s to ensure there’s enough energy available and that everything is within Influence
range.
(Complicated padding/count math for Starter
to place as few as possible while still having full Influence
coverage)
...
let n_belts = 30_000;
let n_rows = 2;
Repeater::new(
n_rows,
5,
GenDir::Down,
Aligned::new(
GenDir::Down,
vec![
Box::new(Aligned::new(
GenDir::Right,
vec![
Box::new(Single::new(
&self.ms,
Rot::D0,
Source::new(Material::Coal.into()).into(),
)),
Box::new(Single::new(
&self.ms,
Rot::D0,
Arm::new(ArmMode::Normal).into(),
)),
Box::new(row_of(
&self.ms,
Belt::new(BeltMode::Normal).into(),
Rot::D0,
n_belts,
0,
)),
Box::new(Single::new(
&self.ms,
Rot::D0,
Arm::new(ArmMode::Normal).into(),
)),
Box::new(Single::new(&self.ms, Rot::D0, Hole::default().into())),
],
)),
Box::new(row_of(
&self.ms,
Starter::new(StarterMode::Normal).into(),
Rot::D0,
1 + n_belts / (2 * R_STARTER as u64 - 5),
2 * (R_STARTER as u32 - 5),
)),
],
),
)
.generate(
&self.ms,
PosAnchor(Pos { x: 0, y: 0 }),
self.planets[0].1.dev_structs_mut(),
)
.unwrap_dev();
...
The below image shows a small part of the generated Structure
s.
At a later point in time I’d like to add more helper functions to create specific sub-factories like for example coal_iron_furnace()
, gear_factory()
.