~starkingdoms/starkingdoms

ref: af4596b8b1b420a569b206cddbe2de664399218c starkingdoms/crates/unified/src/server/drill.rs -rw-r--r-- 5.0 KiB
af4596b8 — core feat(netcode-rewrite): begin reimplementing replication 28 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;
    }
}