~starkingdoms/starkingdoms

ref: 8c951740367d5a236bfa4115017155da9257cf49 starkingdoms/crates/unified/src/server/part.rs -rw-r--r-- 3.4 KiB
8c951740 — core fix: attachment joint child entities causing `GlobalTransform` to be reset after a frame 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
use bevy::ecs::spawn::SpawnRelatedBundle;
use bevy::prelude::Component;
use bevy::prelude::*;
use bevy_rapier2d::prelude::{AdditionalMassProperties, Collider};
use bevy_replicon::prelude::Replicated;
use crate::attachment::{Joint, JointId, JointOf, SnapOf, SnapOfJoint};
use crate::config::part::{JointConfig, PartConfig};
use crate::ecs::{Part, PartHandle};

pub fn part_management_plugin(app: &mut App) {
    app.add_systems(PreUpdate, (handle_ready_parts, handle_part_reloading));
}

#[derive(Bundle)]
pub struct SpawnPartBundle {
    pub req: SpawnPartRequest,
    pub transform: Transform,
}

#[derive(Component)]
pub struct SpawnPartRequest(pub Handle<PartConfig>);

// wait for parts assets to be ready, then spawn the full part
fn handle_ready_parts(loading_parts: Query<(Entity, &SpawnPartRequest)>, mut commands: Commands, assets: Res<Assets<PartConfig>>) {
    for (entity, loading_part) in &loading_parts {
        if let Some(strong_config) = assets.get(&loading_part.0) {
            // config is strong; spawn 'er in!
            commands.entity(entity)
                .insert(calculate_bundle(strong_config, &loading_part.0))
                .remove::<SpawnPartRequest>();
            spawn_joints(strong_config, entity, commands.reborrow());
        }
    }
}
fn handle_part_reloading(existing_parts: Query<(Entity, &PartHandle)>, assets: Res<Assets<PartConfig>>, mut asset_events: EventReader<AssetEvent<PartConfig>>, mut commands: Commands) {
    for event in asset_events.read() {
        match event {
            AssetEvent::Modified { id } => {
                let config = assets.get(*id).unwrap();
                for existing_part in existing_parts.iter() {
                    if existing_part.1.0.id() == *id {
                        commands.entity(existing_part.0)
                            .insert(calculate_bundle(config, &existing_part.1.0));
                    }
                }
            },
            _ => {}
        }
    }
}

fn calculate_bundle(config: &PartConfig, handle: &Handle<PartConfig>) -> impl Bundle {
    let part = Part {
        strong_config: config.clone(),
    };
    let part_handle = PartHandle(handle.clone());
    let collider = Collider::cuboid(config.physics.width / 2.0, config.physics.height / 2.0);
    let additional_mass_properties = AdditionalMassProperties::Mass(config.physics.mass);

    (
        part,
        part_handle,
        collider,
        additional_mass_properties,
        Replicated
    )
}
fn spawn_joint_bundle(joint: &JointConfig, part: &PartConfig, parent: &Entity) -> impl Bundle {
    let j_comp = Joint {
        id: JointId::from_part_and_joint_id(part.part.name.clone(), joint.id.clone()),
        transform: joint.target.into(),
    };
    let joint_transform: Transform = j_comp.transform;
    let joint_of = JointOf(*parent);

    (
        j_comp,
        joint_transform,
        joint_of,
        Replicated
    )
}
fn spawn_snap_bundle(joint: &JointConfig, parent: &Entity, p_joint: &Entity) -> impl Bundle {
    let snap_transform: Transform = joint.snap.into();
    let snap_for = SnapOf(*parent);
    let snap_of = SnapOfJoint(*p_joint);

    (
        snap_transform,
        snap_for,
        snap_of,
        Replicated
    )
}
fn spawn_joints(config: &PartConfig, parent: Entity, mut commands: Commands) {
    for joint in &config.joints {
        let joint_id = commands.spawn(spawn_joint_bundle(joint, config, &parent)).id();
        commands.spawn(spawn_snap_bundle(joint, &parent, &joint_id));
    }
}