~starkingdoms/starkingdoms

ref: 086b9dd63882d67e66ae92c36ac6e7b31d076743 starkingdoms/crates/unified/src/server/part.rs -rw-r--r-- 5.0 KiB
086b9dd6 — core fix: parts 5 months 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
131
132
use bevy::asset::Handle;
use bevy::prelude::*;
use bevy_rapier2d::prelude::{AdditionalMassProperties, Collider};
use bevy_replicon::prelude::Replicated;
use crate::attachment::{Joint, JointId, JointOf, JointSnapFor, JointSnaps, Joints};
use crate::config::part::{JointOffset, PartConfig};
use crate::ecs::Part;

pub fn part_config_plugin(app: &mut App) {
    app.add_systems(PreUpdate, handle_spawn_part_requests)
        .add_systems(Update, update_part_requests);
}

#[derive(Component, Debug)]
pub struct SpawnPart(pub String);
#[derive(Component)]
struct LoadingPart(Handle<PartConfig>);
#[derive(Component, Debug)]
struct PartType(AssetId<PartConfig>);
#[derive(Component)]
/// STOP DELETING MY ASSET BEVY
struct LiveConfigHandle(Handle<PartConfig>);

// watch for new SpawnPart components and start loading their config files
fn handle_spawn_part_requests(new_parts: Query<(Entity, &SpawnPart), Added<SpawnPart>>, mut commands: Commands, asset_server: Res<AssetServer>, assets: Res<Assets<PartConfig>>, parts: Query<(&Joints, &JointSnaps), With<Part>>,) {
    for (new_part, request) in &new_parts {
        trace!(?new_part, ?request, "answering part request");

        let hdl: Handle<PartConfig> = asset_server.load(request.0.clone());

        commands.entity(new_part)
            .remove::<SpawnPart>()
            .insert(LiveConfigHandle(hdl.clone()));

        if let Some(cfg) = assets.get(&hdl) {
            spawn_part(commands.reborrow(), new_part, cfg, &hdl.id(), parts, false);
        } else {
            commands.entity(new_part)
                .insert(LoadingPart(hdl.clone()));
        }
    }
}
fn update_part_requests(
    mut ev_config: EventReader<AssetEvent<PartConfig>>,
    loading_parts: Query<(Entity, &LoadingPart)>,
    existing_parts: Query<(Entity, &PartType)>,
    mut assets: ResMut<Assets<PartConfig>>,
    mut commands: Commands,
    parts: Query<(&Joints, &JointSnaps), With<Part>>,
) {
    for ev in ev_config.read() {
        match ev {
            AssetEvent::Added { id } => {
                trace!(?id, "asset added");
                for (loading_part, req) in &loading_parts {
                    if req.0.id() == *id {
                        let Some(asset) = assets.get(*id) else { continue; };

                        spawn_part(commands.reborrow(), loading_part, asset, id, parts, false);
                    }
                }
            },
            AssetEvent::Modified { id } => {
                trace!(?id, "updating part");
                for (existing_part, ptype) in &existing_parts {
                    if ptype.0 == *id {
                        let Some(asset) = assets.get(ptype.0) else { continue; };
                        spawn_part(commands.reborrow(), existing_part, asset, id, parts, true);
                    }
                }
            }
            _ => {}
        }
    }
}

fn spawn_part(mut commands: Commands, entity: Entity, part: &PartConfig, id: &AssetId<PartConfig>, parts: Query<(&Joints, &JointSnaps), With<Part>>, is_update: bool) {
    commands.entity(entity)
        .remove::<LoadingPart>()
        .insert(Part {
            sprite: part.part.sprite_disconnected.clone(),
            width: part.physics.width,
            height: part.physics.height,
            mass: part.physics.mass,
        })
        .insert(Collider::cuboid(part.physics.width / 2.0, part.physics.height / 2.0))
        .insert(AdditionalMassProperties::Mass(part.physics.mass))
        .insert(PartType(*id))
        .insert(Replicated);

    for joint in &part.joints {
        if is_update {
            // find all entities
            for (joints, snaps) in &parts {
                for joint_entity in joints.iter() {
                    commands.entity(joint_entity).insert((
                        ChildOf(entity),
                        Joint {
                            id: JointId::from_part_and_joint_id(part.part.name.clone(), joint.id.clone()),
                            transform: joint.target.into()
                        },
                        <JointOffset as Into<Transform>>::into(joint.target),
                        JointOf(entity),
                        Replicated,
                    ));
                }
                for snap_entity in snaps.iter() {
                    commands.entity(snap_entity).insert((
                        <JointOffset as Into<Transform>>::into(joint.snap),
                    ));
                }
            }
        } else {
            let e = commands.spawn((
                ChildOf(entity),
                Joint {
                    id: JointId::from_part_and_joint_id(part.part.name.clone(), joint.id.clone()),
                    transform: joint.target.into()
                },
                <JointOffset as Into<Transform>>::into(joint.target),
                JointOf(entity),
                Replicated,
            )).id();
            commands.spawn((
                ChildOf(entity),
                JointSnapFor(e),
                <JointOffset as Into<Transform>>::into(joint.snap),
                Replicated,
            ));
        }
    }
}