From cc22ec58714ca566adf5777f14a46cc76be185d5 Mon Sep 17 00:00:00 2001 From: Zicklag Date: Mon, 28 Nov 2022 14:37:28 -0600 Subject: [PATCH 1/6] Disable Secure Mode in Mimalloc --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 5359f06d9e..3e8bf0b5f5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -68,7 +68,7 @@ sys-locale = "0.2.1" thiserror = "1.0.31" unic-langid = "0.9.0" turborand = { version = "0.8.0", features = ["atomic", "serialize"] } -mimalloc = "0.1.32" +mimalloc = { version = "0.1.32", default-features = false } [dependencies.bevy] version = "0.8" From fed1096d416f36a81a18edf33cdbdd0ce45ebf52 Mon Sep 17 00:00:00 2001 From: Zicklag Date: Mon, 28 Nov 2022 17:44:45 -0600 Subject: [PATCH 2/6] Make Camera Re-position Faster --- src/camera.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/camera.rs b/src/camera.rs index cdfecf9ed7..fde0c76d2a 100644 --- a/src/camera.rs +++ b/src/camera.rs @@ -97,7 +97,7 @@ fn camera_controller( game: Res, ) { const CAMERA_PADDING: f32 = 300.0; - const MOVE_LERP_FACTOR: f32 = 0.05; + const MOVE_LERP_FACTOR: f32 = 0.1; const ZOOM_IN_LERP_FACTOR: f32 = 0.04; const ZOOM_OUT_LERP_FACTOR: f32 = 0.1; const MIN_BOUND: f32 = 350.0; From 40d1d18e0821f394acdd02de5998d74da46048c0 Mon Sep 17 00:00:00 2001 From: Zicklag Date: Mon, 28 Nov 2022 17:45:27 -0600 Subject: [PATCH 3/6] Add Ability to Execute Command on Lifetime Despawn Didn't end up being used, but could still be useful later. --- src/lifetime.rs | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/src/lifetime.rs b/src/lifetime.rs index 18a300c893..1e20188506 100644 --- a/src/lifetime.rs +++ b/src/lifetime.rs @@ -21,7 +21,7 @@ impl Plugin for LifetimePlugin { /// > later, after it was spawned. /// > /// > Also, the age and lifetime are public, subject to other system's modification. -#[derive(Reflect, Debug, Clone, Component, Default)] +#[derive(Reflect, Component, Default)] #[reflect(Component, Default)] pub struct Lifetime { /// How long the entity should be allowed to live in seconds. @@ -32,6 +32,24 @@ pub struct Lifetime { /// /// By default this is set to false and will despawn the entity recursively. pub non_recursive_despawn: bool, + #[reflect(ignore)] + /// An optional [`Command`] that should be run when the entity is despawned. + pub despawn_command: Option>, +} + +impl Clone for Lifetime { + fn clone(&self) -> Self { + if self.despawn_command.is_some() { + panic!("Cannot clone a `Lifetime` component with a non-None despawn command"); + } + + Self { + lifetime: self.lifetime, + age: self.age, + non_recursive_despawn: self.non_recursive_despawn, + despawn_command: None, + } + } } impl Lifetime { @@ -53,6 +71,10 @@ fn lifetime_system(mut commands: Commands, mut entities: Query<(Entity, &mut Lif } else { commands.entity(entity).despawn_recursive(); } + + if let Some(despawn_command) = lifetime.despawn_command.take() { + commands.add(despawn_command); + } } } } From 001226b63461bdb5908050cf96ef9345a2c51802 Mon Sep 17 00:00:00 2001 From: Zicklag Date: Mon, 28 Nov 2022 17:51:19 -0600 Subject: [PATCH 4/6] Fix Grabbing Items While Walking --- src/player/state/states/walk.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/player/state/states/walk.rs b/src/player/state/states/walk.rs index 5970474a50..5e71a5c1b6 100644 --- a/src/player/state/states/walk.rs +++ b/src/player/state/states/walk.rs @@ -76,6 +76,11 @@ pub fn handle_player_state( // Sort the items to provide deterministic item selection if we hare touching multiples colliders.sort_by_key(|(_, (_, rollback))| rollback.id()); + // Grab the first item we are touching + if let Some((item, _)) = colliders.get(0) { + commands.add(PlayerSetInventoryCommand::new(player_ent, Some(*item))); + } + // If we are already carrying an item } else { // Drop it From fde526ddc28d2ec3371efb2410bfc77cb1049cc0 Mon Sep 17 00:00:00 2001 From: Zicklag Date: Mon, 28 Nov 2022 18:04:31 -0600 Subject: [PATCH 5/6] Implement Grenades TODO: Using grenade doesn't rollback properly. --- Cargo.lock | 2 +- assets/default.game.yaml | 2 +- .../item/grenade/explosion.atlas.yaml | 4 + .../map/elements/item/grenade/explosion.png | Bin 0 -> 17898 bytes .../elements/item/grenade/grenade.atlas.yaml | 4 + .../item/grenade/grenade.element.yaml | 17 + assets/map/elements/item/grenade/grenade.png | Bin 0 -> 1580 bytes .../item/grenades/grenades.element.yaml | 4 - .../map/elements/item/grenades/sproinger.ts | 1 - assets/map/levels/lev02.map.json | 2392 ++-- assets/map/levels/lev03.map.json | 9649 ++++++----------- assets/map/levels/lev05.map.json | 2752 ++--- assets/map/levels/lev07.map.json | 3545 +++--- assets/map/levels/level1.map.yaml | 4 +- assets/map/levels/level3.map.yaml | 4 +- assets/map/levels/test_level.map.json | 2913 ++--- assets/map/levels/zyrafa01.map.json | 1916 ++-- assets/map/levels/zyrafa04.map.json | 4688 +++----- assets/map/levels/zyrafa05.map.json | 1742 ++- src/assets.rs | 16 + src/map.rs | 8 +- src/map/elements.rs | 10 + src/map/elements/decoration.rs | 9 +- src/map/elements/grenade.rs | 301 + src/map/elements/player_spawner.rs | 7 +- src/map/elements/sproinger.rs | 9 +- src/map/elements/sword.rs | 16 +- src/metadata/map.rs | 23 + src/scripting.rs | 113 +- 29 files changed, 11337 insertions(+), 18814 deletions(-) create mode 100644 assets/map/elements/item/grenade/explosion.atlas.yaml create mode 100644 assets/map/elements/item/grenade/explosion.png create mode 100644 assets/map/elements/item/grenade/grenade.atlas.yaml create mode 100644 assets/map/elements/item/grenade/grenade.element.yaml create mode 100644 assets/map/elements/item/grenade/grenade.png delete mode 100644 assets/map/elements/item/grenades/grenades.element.yaml delete mode 100644 assets/map/elements/item/grenades/sproinger.ts create mode 100644 src/map/elements/grenade.rs diff --git a/Cargo.lock b/Cargo.lock index 7064bdfdba..690ed39f53 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2293,7 +2293,7 @@ dependencies = [ [[package]] name = "ggrs" version = "0.9.2" -source = "git+https://github.com/gschup/ggrs#99f8a139d599d94db7397e65c33d6fabe45c4acf" +source = "git+https://github.com/gschup/ggrs#3d4adea97ed5268d376cc44663e43c3a32359dbe" dependencies = [ "bincode", "bitfield-rle", diff --git a/assets/default.game.yaml b/assets/default.game.yaml index 8dc4834105..9c669ac0dd 100644 --- a/assets/default.game.yaml +++ b/assets/default.game.yaml @@ -2,7 +2,7 @@ camera_height: 448 clear_color: 27233B physics: terminal_velocity: 30 - friction_lerp: 0.96 + friction_lerp: 0.85 stop_threshold: 1.0 players: diff --git a/assets/map/elements/item/grenade/explosion.atlas.yaml b/assets/map/elements/item/grenade/explosion.atlas.yaml new file mode 100644 index 0000000000..703175da65 --- /dev/null +++ b/assets/map/elements/item/grenade/explosion.atlas.yaml @@ -0,0 +1,4 @@ +image: ./explosion.png +tile_size: [144, 112] +rows: 1 +columns: 11 diff --git a/assets/map/elements/item/grenade/explosion.png b/assets/map/elements/item/grenade/explosion.png new file mode 100644 index 0000000000000000000000000000000000000000..787407869e695af1e850b684d62c1a936710c215 GIT binary patch literal 17898 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%0A@Opai@-NimD}Hdw^9i%ttU2`a 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 Oq{P$J&t;ucLK6V^plqA~ literal 0 HcmV?d00001 diff --git a/assets/map/elements/item/grenade/grenade.atlas.yaml b/assets/map/elements/item/grenade/grenade.atlas.yaml new file mode 100644 index 0000000000..1563986c4f --- /dev/null +++ b/assets/map/elements/item/grenade/grenade.atlas.yaml @@ -0,0 +1,4 @@ +image: ./grenade.png +tile_size: [25, 52] +rows: 2 +columns: 3 diff --git a/assets/map/elements/item/grenade/grenade.element.yaml b/assets/map/elements/item/grenade/grenade.element.yaml new file mode 100644 index 0000000000..a09fccc9a2 --- /dev/null +++ b/assets/map/elements/item/grenade/grenade.element.yaml @@ -0,0 +1,17 @@ +name: Grenades +category: Weapons +builtin: !Grenades + atlas: ./grenade.atlas.yaml + explosion_atlas: ./explosion.atlas.yaml + fuse_time: 1.0 + throw_velocity: [7, 5] + damage_region_size: [60, 60] + damage_region_lifetime: 0.6 + explosion_lifetime: 1.0 + explosion_frames: 12 + explosion_fps: 8 + + body_size: [18, 18] + grab_offset: [-7, -6] + body_offset: [0, 2] + can_rotate: false diff --git a/assets/map/elements/item/grenade/grenade.png b/assets/map/elements/item/grenade/grenade.png new file mode 100644 index 0000000000000000000000000000000000000000..09cffff5538dace7abfafd7e7fa1bbbc4eff953f GIT binary patch literal 1580 zcmV+{2GjY8P)003wR1^@s6xpob50004RX+uL$X=7sm z04R}lkvmHRK@^2QqY^O@3l&8KQ$(>a5ER5xW059Ehzdq+lFduVW7$oRU@O>I1S~`w zUxoibTftUA5EMbg#y{Yzk+9xzg#<}vnY|xp=3HjZfFqREa%P(!a`~bW2?jjN(G`#L zl}`F`(Z_I1GxgbUI7HL&bx(_`cRtmt`M!q3l}MTzv~&nhX}VDqo)Hdh6m`Wr!o6B1 zmJmJ?9yjEG!q-ZV+x((9ZS#j>V=*!Z4%O3>uH$$eYZ)UaJSObTWlP%MdDKnZ$^6oS z)Ipg;m_!H?z(br8>tre7lbV;z8vFdezIh7b(d4gF#t=uEjCjXIElJm;)RgE+`LdK% z?*H>NQRcXt5VpDpWs1f082tytFgv1L_Hp!EqZ^EH1#a+>}Wy;9S>htRzR=T|i? zz6TfEFz~3yjM%T#D$|il!P^;hMWN>wI#=zi{?<8tfW=LDq8r#hfKl1sz4im!ENA)n z{c(r@00ekRL_t(|ob8;uP8&fKhX0Myq>ALq4(o!(B2r|f0n$N1i;&0zxb`zpr^pky zrlJZ`l-31wK!qYC5Df*kLuHAIa#N65kH>R4GdoKb@A;$%WADzn%sI2O&i()l!!QiP zFbu;m3=>E*?PSfgll^Z$UXnMyC&)=U>aC+r347~va5L>>N4<4iUO(aU$9K5Aek#ka zO5&9)0JywrJZE&+h&5{Gm5~MO5HvnMiE6lnnl@q1=U0`d|Wnv*&a#i`#Z?7)(j^6ur zr_NZDrLIw?HLEUYuZF{MBVUIo2@(tZ&dL;n`-t9E46imcE%0^0xOH%CMg^j(faTvh zSnmzx_A-4|CyZ4fs*B39R~10KH?*;{GR4=k$E8mc;PI`4oHWsvU(X%^@V5>N@RxrK z!!QiPFbu;m48t%C!!XP%A)9Vj;$ahhFyu9Iez;$W>ajttEK@L5X^~KT{4dmoMH3~T zzu7x3<-gTpPNr9~%4iiem@2np;RQZvoFo7}NclK%ZYbGwJ9AZz%?7pVgq?+CsX^Oj zzG$%O7&hCc&q91KO|0qtq;ZlYjgv%MS-O*4YYKJE(H*CoVe#Ji;eMv`M+9KAWvlj( z_FqVr8ceG@(GKh?VM>dr$IIi3*Lw$7TED2sW9j^9btm~T!iLFjZDmnsUwv3aBq*D1 zXOx+j9R`4n-RayBbwqVuRFdG&?+@N% zy6mX_%kRk-EY&xX19BoRel@hl@&P@A5)SPhT;+*TX>}(HljgI)3mZ1Sf#=v{)D9zU z9YmYh47R$Hy#IanN|d!omqed7r`Tw9Cv#P;JI7o0t1|)sKfiq1P zJbz!N=u`F;p!-X%EYoMPf>GtgWyp$+T5sZ{ke*gHsV!p7{!7^quS2!o&gbBD20{$k zZ0Pijvb?xx!eVK?oeB%8ekUXts=T;}te7$xvK^ZZ?E-HSlbehb6_xAc#p?JWS|QtH zn52RIwmA-~>^I$7%l}agQDwg&^5RfgaV)L3aR*N|KsEHzl%e&WOI8sBE<-k6i@dn- z?M^JpOwj1`hV=I-Tr9MqSV(*zIPcYgR-^Qq2n)H z9&P(8^^z_K)k#w~iy>oE$M>;gT(fi~Y1%9nMQ1Cf20ND4+p50zC3J^Pu@!o|6I1IQ zMNnQ;CvCG8LxUYl>rJ|m))|Vela_6jp}~%!^{&kKSvp%~eDTLxZ-!wQhG7_nVHk#C e7=~e(BK!qMFgZ-Xi&{tk0000 { + for (atlas, atlas_handle) in [ + (atlas, atlas_handle), + (explosion_atlas, explosion_atlas_handle), + ] { + let (path, handle) = get_relative_asset(load_context, self_path, atlas); + *atlas_handle = AssetHandle::new(path.clone(), handle.typed()); + dependencies.push(path); + } + } } // Load preloaded assets diff --git a/src/map.rs b/src/map.rs index 4e141729b6..1f3cd288ee 100644 --- a/src/map.rs +++ b/src/map.rs @@ -23,7 +23,11 @@ impl Plugin for MapPlugin { app.add_plugin(TilemapPlugin) .init_resource::() .add_system(hydrate_maps) - .extend_rollback_plugin(|plugin| plugin.register_rollback_type::()) + .extend_rollback_plugin(|plugin| { + plugin + .register_rollback_type::() + .register_rollback_type::>() + }) .add_plugin(elements::MapElementsPlugin); } } @@ -233,7 +237,7 @@ pub fn hydrate_maps( default(), )); }) - .insert(element_meta) + .insert(element.element_handle.inner.clone()) .insert(Rollback::new(rids.next_id())) .id(); map_children.push(entity) diff --git a/src/map/elements.rs b/src/map/elements.rs index 07a9660829..25bc063b37 100644 --- a/src/map/elements.rs +++ b/src/map/elements.rs @@ -1,15 +1,24 @@ use crate::{ animation::AnimatedSprite, + damage::{DamageRegion, DamageRegionOwner}, + item::{Item, ItemDropped, ItemUsed}, + lifetime::Lifetime, map::MapElementHydrated, metadata::{BuiltinElementKind, MapElementMeta}, + name::EntityName, physics::{collisions::CollisionWorld, KinematicBody}, player::{input::PlayerInputs, PlayerIdx, MAX_PLAYERS}, prelude::*, + utils::Sort, }; +// Meta/environment elements pub mod decoration; pub mod player_spawner; pub mod sproinger; + +// Items +pub mod grenade; pub mod sword; pub struct MapElementsPlugin; @@ -17,6 +26,7 @@ pub struct MapElementsPlugin; impl Plugin for MapElementsPlugin { fn build(&self, app: &mut App) { app.add_plugin(decoration::DecorationPlugin) + .add_plugin(grenade::GrenadePlugin) .add_plugin(player_spawner::PlayerSpawnerPlugin) .add_plugin(sproinger::SproingerPlugin) .add_plugin(sword::SwordPlugin); diff --git a/src/map/elements/decoration.rs b/src/map/elements/decoration.rs index 413c13da57..c7f93b83eb 100644 --- a/src/map/elements/decoration.rs +++ b/src/map/elements/decoration.rs @@ -12,10 +12,15 @@ impl Plugin for DecorationPlugin { fn hydrate_decorations( mut commands: Commands, - non_hydrated_map_elements: Query<(Entity, &MapElementMeta), Without>, + non_hydrated_map_elements: Query< + (Entity, &Handle), + Without, + >, + element_assets: Res>, ) { // Hydrate any newly-spawned decorations - for (entity, map_element) in &non_hydrated_map_elements { + for (entity, map_element_handle) in &non_hydrated_map_elements { + let map_element = element_assets.get(map_element_handle).unwrap(); if let BuiltinElementKind::AnimatedDecoration { atlas_handle, start_frame, diff --git a/src/map/elements/grenade.rs b/src/map/elements/grenade.rs new file mode 100644 index 0000000000..3b11760d50 --- /dev/null +++ b/src/map/elements/grenade.rs @@ -0,0 +1,301 @@ +use super::*; + +pub struct GrenadePlugin; + +#[derive(Reflect, Component, Clone, Debug)] +#[reflect(Component)] +pub struct IdleGrenade { + /// The entity ID of the map element that spawned the grenade + spawner: Entity, +} + +impl Default for IdleGrenade { + fn default() -> Self { + Self { + spawner: crate::utils::invalid_entity(), + } + } +} + +#[derive(Reflect, Component, Clone, Debug)] +#[reflect(Component, Default)] +pub struct LitGrenade { + /// The entity ID of the map element that spawned the grenade + spawner: Entity, + age: f32, +} + +impl Default for LitGrenade { + fn default() -> Self { + Self { + spawner: crate::utils::invalid_entity(), + age: 0.0, + } + } +} + +impl Plugin for GrenadePlugin { + fn build(&self, app: &mut App) { + app.extend_rollback_schedule(|schedule| { + schedule + .add_system_to_stage(RollbackStage::PreUpdateInGame, pre_update_in_game) + .add_system_to_stage( + RollbackStage::UpdateInGame, + update_lit_grenades.before(update_idle_grenades), + ) + .add_system_to_stage(RollbackStage::UpdateInGame, update_idle_grenades); + }) + .extend_rollback_plugin(|plugin| plugin.register_rollback_type::()); + } +} + +fn pre_update_in_game( + mut commands: Commands, + non_hydrated_map_elements: Query< + (Entity, &Sort, &Handle, &Transform), + Without, + >, + mut ridp: ResMut, + element_assets: ResMut>, +) { + // Hydrate any newly-spawned grenades + let mut elements = non_hydrated_map_elements.iter().collect::>(); + elements.sort_by_key(|x| x.1); + for (entity, _sort, map_element_handle, transform) in elements { + let map_element = element_assets.get(map_element_handle).unwrap(); + if let BuiltinElementKind::Grenades { + body_size, + body_offset, + atlas_handle, + can_rotate, + .. + } = &map_element.builtin + { + commands.entity(entity).insert(MapElementHydrated); + + commands + .spawn() + .insert(Rollback::new(ridp.next_id())) + .insert(Item { + script: "core:grenade".into(), + }) + .insert(IdleGrenade { spawner: entity }) + .insert(EntityName("Item: Grenade".into())) + .insert(AnimatedSprite { + start: 0, + end: 0, + atlas: atlas_handle.inner.clone(), + repeat: false, + ..default() + }) + .insert(map_element_handle.clone()) + .insert_bundle(VisibilityBundle::default()) + .insert_bundle(TransformBundle { + local: *transform, + ..default() + }) + .insert(KinematicBody { + size: *body_size, + offset: *body_offset, + gravity: 1.0, + has_mass: true, + has_friction: true, + can_rotate: *can_rotate, + ..default() + }); + } + } +} + +fn update_idle_grenades( + mut commands: Commands, + players: Query<(&AnimatedSprite, &Transform, &KinematicBody), With>, + mut grenades: Query< + ( + &Rollback, + Entity, + &IdleGrenade, + &mut Transform, + &mut AnimatedSprite, + &mut KinematicBody, + &Handle, + Option<&Parent>, + Option<&ItemUsed>, + Option<&ItemDropped>, + ), + Without, + >, + mut ridp: ResMut, + element_assets: ResMut>, +) { + let mut items = grenades.iter_mut().collect::>(); + items.sort_by_key(|x| x.0.id()); + for ( + _, + item_ent, + grenade, + mut transform, + mut sprite, + mut body, + meta_handle, + parent, + used, + dropped, + ) in items + { + let meta = element_assets.get(meta_handle).unwrap(); + let BuiltinElementKind::Grenades { grab_offset, atlas_handle, throw_velocity, .. } = &meta.builtin else { + unreachable!(); + }; + + // If the item is being held + if let Some(parent) = parent { + let (player_sprite, player_transform, player_body) = + players.get(parent.get()).expect("Parent is not player"); + + // Deactivate items while held + body.is_deactivated = true; + + // Flip the sprite to match the player orientation + let flip = player_sprite.flip_x; + sprite.flip_x = flip; + let flip_factor = if flip { -1.0 } else { 1.0 }; + let horizontal_flip_factor = Vec2::new(flip_factor, 1.0); + transform.translation.x = grab_offset.x * flip_factor; + transform.translation.y = grab_offset.y; + transform.translation.z = 0.0; + + // If the item is being used + if used.is_some() { + // Despawn the item from the player's hand + commands.entity(item_ent).despawn(); + + // Spawn a new, lit grenade + commands + .spawn() + .insert(Rollback::new(ridp.next_id())) + .insert(Name::new("Grenade ( Lit )")) + .insert(Transform::from_translation( + player_transform.translation + + (*grab_offset * horizontal_flip_factor).extend(0.0), + )) + .insert(GlobalTransform::default()) + .insert(Visibility::default()) + .insert(ComputedVisibility::default()) + .insert(AnimatedSprite { + start: 3, + end: 5, + repeat: true, + fps: 8.0, + atlas: atlas_handle.inner.clone(), + ..default() + }) + .insert(meta_handle.clone()) + .insert(body.clone()) + .insert(LitGrenade { + spawner: grenade.spawner, + ..default() + }) + .insert(KinematicBody { + velocity: *throw_velocity * horizontal_flip_factor + player_body.velocity, + is_deactivated: false, + ..body.clone() + }); + } + } + + // If the item is dropped + if let Some(dropped) = dropped { + commands.entity(item_ent).remove::(); + let (.., player_transform, player_body) = + players.get(dropped.player).expect("Parent is not a player"); + + // Re-activate physics + body.is_deactivated = false; + + // Put sword in rest position + sprite.start = 0; + sprite.end = 0; + body.velocity = player_body.velocity; + body.is_spawning = true; + + // Drop item at player position + transform.translation = player_transform.translation + grab_offset.extend(0.0); + } + } +} + +fn update_lit_grenades( + mut commands: Commands, + mut grenades: Query< + ( + &Rollback, + Entity, + &mut LitGrenade, + &Transform, + &Handle, + ), + Without, + >, + mut ridp: ResMut, + element_assets: ResMut>, +) { + let mut items = grenades.iter_mut().collect::>(); + items.sort_by_key(|x| x.0.id()); + for (_, item_ent, mut grenade, transform, meta_handle) in items { + let meta = element_assets.get(meta_handle).unwrap(); + let BuiltinElementKind::Grenades { + fuse_time, + damage_region_size, + damage_region_lifetime, + explosion_atlas_handle, + explosion_lifetime, + explosion_fps, + explosion_frames, + .. + } = &meta.builtin else { + unreachable!(); + }; + + grenade.age += 1.0 / crate::FPS as f32; + + if grenade.age >= *fuse_time { + // Despawn the grenade + commands.entity(item_ent).despawn(); + // Cause the item to re-spawn by re-triggering spawner hydration + commands + .entity(grenade.spawner) + .remove::(); + + // Spawn the damage region entity + commands + .spawn() + .insert(Rollback::new(ridp.next_id())) + .insert(*transform) + .insert(GlobalTransform::default()) + .insert(Visibility::default()) + .insert(ComputedVisibility::default()) + .insert(DamageRegion { + size: *damage_region_size, + }) + .insert(Lifetime::new(*damage_region_lifetime)); + // Spawn the explosion sprite entity + commands + .spawn() + .insert(Rollback::new(ridp.next_id())) + .insert(*transform) + .insert(GlobalTransform::default()) + .insert(Visibility::default()) + .insert(ComputedVisibility::default()) + .insert(AnimatedSprite { + start: 0, + end: *explosion_frames, + atlas: explosion_atlas_handle.inner.clone(), + repeat: false, + fps: *explosion_fps, + ..default() + }) + .insert(Lifetime::new(*explosion_lifetime)); + } + } +} diff --git a/src/map/elements/player_spawner.rs b/src/map/elements/player_spawner.rs index 4a72ef5d8c..daafaff020 100644 --- a/src/map/elements/player_spawner.rs +++ b/src/map/elements/player_spawner.rs @@ -32,16 +32,17 @@ fn pre_update_in_game( players: Query<&PlayerIdx>, player_spawners: Query<(&Sort, &Transform), With>, non_hydrated_map_elements: Query< - (Entity, &Sort, &Transform, &MapElementMeta), + (Entity, &Sort, &Transform, &Handle), Without, >, mut ridp: ResMut, mut current_spawner: ResMut, + element_assets: Res>, ) { let mut spawn_points = player_spawners.iter().collect::>(); // Hydrate any newly-spawned spawn points - for (entity, sort, transform, map_element) in &non_hydrated_map_elements { - // TODO: Better way to tie the behavior to the map element? + for (entity, sort, transform, map_element_handle) in &non_hydrated_map_elements { + let map_element = element_assets.get(map_element_handle).unwrap(); if matches!(map_element.builtin, BuiltinElementKind::PlayerSpawner) { commands .entity(entity) diff --git a/src/map/elements/sproinger.rs b/src/map/elements/sproinger.rs index 88927ee09f..aa52ac4e86 100644 --- a/src/map/elements/sproinger.rs +++ b/src/map/elements/sproinger.rs @@ -25,10 +25,15 @@ pub struct Sproinger { fn pre_update_in_game( mut commands: Commands, - non_hydrated_map_elements: Query<(Entity, &MapElementMeta), Without>, + non_hydrated_map_elements: Query< + (Entity, &Handle), + Without, + >, + element_assets: Res>, ) { // Hydrate any newly-spawned sproingers - for (entity, map_element) in &non_hydrated_map_elements { + for (entity, map_element_handle) in &non_hydrated_map_elements { + let map_element = element_assets.get(map_element_handle).unwrap(); if let BuiltinElementKind::Sproinger { atlas_handle, .. } = &map_element.builtin { commands .entity(entity) diff --git a/src/map/elements/sword.rs b/src/map/elements/sword.rs index 8702a03027..60466a0e25 100644 --- a/src/map/elements/sword.rs +++ b/src/map/elements/sword.rs @@ -1,11 +1,3 @@ -use crate::{ - damage::{DamageRegion, DamageRegionOwner}, - item::{Item, ItemDropped, ItemUsed}, - lifetime::Lifetime, - name::EntityName, - utils::Sort, -}; - use super::*; pub struct SwordPlugin; @@ -39,15 +31,18 @@ const ATTACK_FPS: f32 = 10.0; fn pre_update_in_game( mut commands: Commands, non_hydrated_map_elements: Query< - (Entity, &Sort, &MapElementMeta, &Transform), + (Entity, &Sort, &Handle, &Transform), Without, >, mut ridp: ResMut, + element_assets: Res>, ) { // Hydrate any newly-spawned swords let mut elements = non_hydrated_map_elements.iter().collect::>(); elements.sort_by_key(|x| x.1); - for (entity, _sort, map_element, transform) in elements { + for (entity, _sort, map_element_handle, transform) in elements { + let map_element = element_assets.get(map_element_handle).unwrap(); + if let BuiltinElementKind::Sword { atlas_handle, .. } = &map_element.builtin { commands.entity(entity).insert(MapElementHydrated); @@ -72,6 +67,7 @@ fn pre_update_in_game( local: *transform, ..default() }) + .insert(map_element_handle.clone()) .insert(KinematicBody { size: Vec2::new(64.0, 16.0), offset: Vec2::new(0.0, 38.0), diff --git a/src/metadata/map.rs b/src/metadata/map.rs index 5d891351b6..de7a59787c 100644 --- a/src/metadata/map.rs +++ b/src/metadata/map.rs @@ -207,6 +207,29 @@ pub enum BuiltinElementKind { None, /// Player spawner PlayerSpawner, + /// Grenades item + Grenades { + body_size: Vec2, + body_offset: Vec2, + grab_offset: Vec2, + damage_region_size: Vec2, + damage_region_lifetime: f32, + throw_velocity: Vec2, + explosion_lifetime: f32, + explosion_frames: usize, + explosion_fps: f32, + /// The time in seconds before a grenade explodes + fuse_time: f32, + #[serde(default)] + can_rotate: bool, + /// The grenade atlas + atlas: String, + #[serde(skip)] + atlas_handle: AssetHandle, + explosion_atlas: String, + #[serde(skip)] + explosion_atlas_handle: AssetHandle, + }, /// An animated decoration such as seaweed or anemones AnimatedDecoration { start_frame: usize, diff --git a/src/scripting.rs b/src/scripting.rs index d13627f1fb..3479893077 100644 --- a/src/scripting.rs +++ b/src/scripting.rs @@ -4,13 +4,12 @@ use std::{ }; use crate::prelude::*; -use bevy::{asset::HandleId, ecs::entity::EntityMap, reflect::TypeRegistryArc}; -use bevy_ggrs::{ggrs::Frame, RollbackEventHook}; +use bevy::{asset::HandleId, reflect::TypeRegistryArc}; use bevy_mod_js_scripting::{ bevy_reflect_fns::{ PassMode, ReflectArg, ReflectFunction, ReflectFunctionError, ReflectMethods, }, - serde_json, JsRuntime, JsRuntimeApi, JsRuntimeConfig, JsScriptingPlugin, + JsRuntimeConfig, JsScriptingPlugin, }; pub mod ops; @@ -62,58 +61,58 @@ impl From for Entity { } } -struct ScriptingRollbackHooks; - -impl RollbackEventHook for ScriptingRollbackHooks { - fn pre_save(&mut self, frame: Frame, max_snapshots: usize, world: &mut World) { - let runtime = world.remove_non_send_resource::().unwrap(); - - // We use extremely brief keys here to avoid encoding more string across the FFI - let args = serde_json::json!({ - "f": frame, - "m": max_snapshots, - }); - if let Err(e) = runtime.eval(&format!("globalThis.saveSnapshot({})", args), world) { - error!("Error running JS save snapshot hook: {e:?}"); - } - - world.insert_non_send_resource(runtime); - } - - fn post_load( - &mut self, - frame: Frame, - max_snapshots: usize, - entity_map: &EntityMap, - world: &mut World, - ) { - let runtime = world.remove_non_send_resource::().unwrap(); - - let mut entity_map_json = Vec::new(); - - for from in entity_map.keys() { - let to = entity_map.get(from).unwrap(); - if from != to { - entity_map_json.push(serde_json::json!({ - "f": JsEntity::from(from), - "t": JsEntity::from(to), - })); - } - } - - // We use extremely brief keys here to avoid encoding more string across the FFI - let args = serde_json::json!({ - "f": frame, - "m": max_snapshots, - "e": entity_map_json, - }); - if let Err(e) = runtime.eval(&format!("globalThis.loadSnapshot({})", args), world) { - error!("Error running JS save snapshot hook: {e:?}"); - } - - world.insert_non_send_resource(runtime); - } -} +// struct ScriptingRollbackHooks; + +// impl RollbackEventHook for ScriptingRollbackHooks { +// fn pre_save(&mut self, frame: Frame, max_snapshots: usize, world: &mut World) { +// let runtime = world.remove_non_send_resource::().unwrap(); + +// // We use extremely brief keys here to avoid encoding more string across the FFI +// let args = serde_json::json!({ +// "f": frame, +// "m": max_snapshots, +// }); +// if let Err(e) = runtime.eval(&format!("globalThis.saveSnapshot({})", args), world) { +// error!("Error running JS save snapshot hook: {e:?}"); +// } + +// world.insert_non_send_resource(runtime); +// } + +// fn post_load( +// &mut self, +// frame: Frame, +// max_snapshots: usize, +// entity_map: &EntityMap, +// world: &mut World, +// ) { +// let runtime = world.remove_non_send_resource::().unwrap(); + +// let mut entity_map_json = Vec::new(); + +// for from in entity_map.keys() { +// let to = entity_map.get(from).unwrap(); +// if from != to { +// entity_map_json.push(serde_json::json!({ +// "f": JsEntity::from(from), +// "t": JsEntity::from(to), +// })); +// } +// } + +// // We use extremely brief keys here to avoid encoding more string across the FFI +// let args = serde_json::json!({ +// "f": frame, +// "m": max_snapshots, +// "e": entity_map_json, +// }); +// if let Err(e) = runtime.eval(&format!("globalThis.loadSnapshot({})", args), world) { +// error!("Error running JS save snapshot hook: {e:?}"); +// } + +// world.insert_non_send_resource(runtime); +// } +// } impl Plugin for ScriptingPlugin { fn build(&self, app: &mut App) { @@ -123,8 +122,8 @@ impl Plugin for ScriptingPlugin { .insert_non_send_resource(JsRuntimeConfig { custom_ops }) .add_plugin(JsScriptingPlugin { skip_core_stage_setup: true, - }) - .extend_rollback_plugin(|plugin| plugin.add_rollback_hook(ScriptingRollbackHooks)); + }); + // .extend_rollback_plugin(|plugin| plugin.add_rollback_hook(ScriptingRollbackHooks)); { let type_registry = app.world.resource::(); From 6e04ea0b70868a96cd6ea0907facf6c41f942f02 Mon Sep 17 00:00:00 2001 From: Zicklag Date: Mon, 28 Nov 2022 20:12:24 -0600 Subject: [PATCH 6/6] Fix Grenade In Rollback Mode --- Cargo.lock | 9 ++++----- Cargo.toml | 3 +++ src/map/elements/grenade.rs | 6 +++++- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 690ed39f53..807f125b71 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -619,8 +619,7 @@ dependencies = [ [[package]] name = "bevy_hierarchy" version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5eb1ec76099ea5a716de08ea42ff41f036ebe2502df1d569168b58f16458a85e" +source = "git+https://github.com/zicklag/bevy.git?branch=dont-error-on-non-mapped-children-entities#0db2b8e67b8cd848fdad2a98bebead4cfce6b336" dependencies = [ "bevy_app", "bevy_ecs", @@ -5631,7 +5630,7 @@ dependencies = [ "js-sys", "log", "naga", - "parking_lot 0.12.1", + "parking_lot 0.11.2", "raw-window-handle", "smallvec", "wasm-bindgen", @@ -5657,7 +5656,7 @@ dependencies = [ "fxhash", "log", "naga", - "parking_lot 0.12.1", + "parking_lot 0.11.2", "profiling", "raw-window-handle", "smallvec", @@ -5694,7 +5693,7 @@ dependencies = [ "metal", "naga", "objc", - "parking_lot 0.12.1", + "parking_lot 0.11.2", "profiling", "range-alloc", "raw-window-handle", diff --git a/Cargo.toml b/Cargo.toml index 3e8bf0b5f5..d93626f8f4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -95,3 +95,6 @@ debug = true [profile.release] lto = true codegen-units = 1 # Improved rapier physics perf, so it might help other stuff, too + +[patch.crates-io] +bevy_hierarchy = { git = "https://github.com/zicklag/bevy.git", branch = "dont-error-on-non-mapped-children-entities" } diff --git a/src/map/elements/grenade.rs b/src/map/elements/grenade.rs index 3b11760d50..44e2bc3207 100644 --- a/src/map/elements/grenade.rs +++ b/src/map/elements/grenade.rs @@ -45,7 +45,11 @@ impl Plugin for GrenadePlugin { ) .add_system_to_stage(RollbackStage::UpdateInGame, update_idle_grenades); }) - .extend_rollback_plugin(|plugin| plugin.register_rollback_type::()); + .extend_rollback_plugin(|plugin| { + plugin + .register_rollback_type::() + .register_rollback_type::() + }); } }