~starkingdoms/starkingdoms

ref: 11ed44a250017a0508927b34f18a597d1db1ed7d starkingdoms/crates/unified/src/server/drill.rs -rw-r--r-- 5.0 KiB
11ed44a2ghostly_zsh feat: serverbound messages implemented but untested 9 days ago
                                                                                
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
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
use crate::server::components::PlanetSensor;
use crate::prelude::*;
use crate::shared::attachment::{PartInShip, Parts};
use crate::shared::config::planet::{Planet, PlanetResource};
use crate::shared::ecs::{Drill, Part, Player, SingleStorage, ToggleDrillEvent, VariableStorage};

pub fn drill_plugin(app: &mut App) {
    app.add_systems(Update, (toggle_drill, drill_on_planet, do_drilling));
}

fn toggle_drill(
    mut toggle_drill_reader: MessageReader<ToggleDrillEvent>,
    mut drills: Query<&mut Drill>,
) {
    for toggle_drill_event in toggle_drill_reader.read() {
        // this getting of the drill also serves to check whether or not
        // the entity is a drill
        let Ok(mut drill) = drills.get_mut(toggle_drill_event.drill_entity) else { return };
        drill.drilling = !drill.drilling;
    }
}

fn drill_on_planet(
    mut collision_start: MessageReader<CollisionStart>,
    mut collision_end: MessageReader<CollisionEnd>,
    planet_sensors: Query<&PlanetSensor>,
    mut drills: Query<&mut Drill>,
) {
    for event in collision_start.read() {
        let (planet_sensor, mut drill) = if let (Ok(planet_sensor), Ok(drill)) = (planet_sensors.get(event.collider1), drills.get_mut(event.collider2)) {
            (planet_sensor, drill)
        } else if let (Ok(drill), Ok(planet_sensor)) = (drills.get_mut(event.collider1), planet_sensors.get(event.collider2)) {
            (planet_sensor, drill)
        } else {
            continue
        };
        drill.on_planet = Some(planet_sensor.0.clone());
    }
    for event in collision_end.read() {
        let (_, mut drill) = if let (Ok(planet_sensor), Ok(drill)) = (planet_sensors.get(event.collider1), drills.get_mut(event.collider2)) {
            (planet_sensor, drill)
        } else if let (Ok(drill), Ok(planet_sensor)) = (drills.get_mut(event.collider1), planet_sensors.get(event.collider2)) {
            (planet_sensor, drill)
        } else {
            continue
        };
        drill.drilling = false;
        drill.on_planet = None;
    }
}

fn do_drilling(
    drills: Query<(&Drill, &PartInShip)>,
    hearty_drills: Query<(Entity, &Drill), With<Player>>,
    parts_query: Query<&Parts>,
    mut single_storage_part_query: Query<&mut SingleStorage, With<Part>>,
    mut variable_storage_part_query: Query<&mut VariableStorage, With<Part>>,
    planet_query: Query<&Planet>,
    time: Res<Time>,
) {
    for (entity, drill) in hearty_drills {
        let Some(planet_resource) = find_drill_resource(drill, &planet_query) else { continue };
        drill_into_parts(entity, drill, planet_resource, &parts_query, &mut single_storage_part_query, &time);
        if let Ok(mut storage) = variable_storage_part_query.get_mut(entity) {
            let to_add = planet_resource.mining_speed * drill.resource_multiplier * time.delta_secs();
            add_to_variable_storage(&mut storage, to_add, &planet_resource.name);
        }
    }
    for (drill, part_in_ship) in drills {
        let Some(planet_resource) = find_drill_resource(drill, &planet_query) else { continue };
        drill_into_parts(part_in_ship.0, drill, planet_resource, &parts_query, &mut single_storage_part_query, &time);
    }
}

fn find_drill_resource<'a>(drill: &Drill, planet_query: &'a Query<&Planet>) -> Option<&'a PlanetResource> {
    if !drill.drilling { return None; }
    let planet_name = drill.on_planet.as_ref()?;
    planet_query.iter()
        .find(|p| p.name == *planet_name)
        .expect("In do_drilling, a planet name didn't match a planet")
        .planet_resource.as_ref()
}

fn drill_into_parts(
    ship_entity: Entity,
    drill: &Drill,
    planet_resource: &PlanetResource,
    parts_query: &Query<&Parts>,
    single_storage_query: &mut Query<&mut SingleStorage, With<Part>>,
    time: &Time,
) {
    let Ok(parts_list) = parts_query.get(ship_entity) else { return };
    for part_entity in parts_list.iter() {
        let Ok(mut storage) = single_storage_query.get_mut(part_entity) else { continue };
        let to_add = planet_resource.mining_speed * drill.resource_multiplier * time.delta_secs();
        add_to_single_storage(&mut storage, to_add, &planet_resource.name);
    }
}

fn add_to_variable_storage(
    storage: &mut VariableStorage,
    to_add: f32,
    resource_name: &String
) {
    let total_stored = storage.resources.iter().fold(0.0, |acc, (_, resource)| *resource + acc);
    if to_add + total_stored > storage.capacity {
        return;
    }
    if let Some(amount) = storage.resources.get_mut(resource_name) {
        *amount += to_add;
    } else {
        storage.resources.insert(resource_name.clone(), to_add);
    }
}

fn add_to_single_storage(
    storage: &mut SingleStorage,
    to_add: f32,
    resource_name: &String
) {
    if storage.resource_name.is_empty() {
        storage.resource_name = resource_name.clone();
    }
    // now that the name isn't empty, this will trigger
    if storage.resource_name == *resource_name {
        storage.stored += to_add;
        storage.stored = storage.stored.min(storage.capacity);
        return;
    }
}