diff --git a/godot/scenes/misc/replay_teleport_grenade.tscn b/godot/scenes/misc/replay_teleport_grenade.tscn new file mode 100644 index 0000000..a16b204 --- /dev/null +++ b/godot/scenes/misc/replay_teleport_grenade.tscn @@ -0,0 +1,54 @@ +[gd_scene format=3 uid="uid://ceeuegblh6qj4"] + +[ext_resource type="PackedScene" uid="uid://baexh5xmqj4ki" path="res://mesh/telegrenade.tscn" id="1_nt0dp"] + +[sub_resource type="SphereShape3D" id="SphereShape3D_1cgct"] +radius = 0.5088567 + +[sub_resource type="ParticleProcessMaterial" id="ParticleProcessMaterial_1cgct"] +particle_flag_align_y = true +angular_velocity_min = -1.6093254e-05 +angular_velocity_max = -1.6093254e-05 +radial_velocity_min = -50.000023 +radial_velocity_max = -2.2351742e-05 +gravity = Vector3(0, 0, 0) +radial_accel_min = -2.2351742e-06 +radial_accel_max = -2.2351742e-06 + +[sub_resource type="Curve" id="Curve_bbjda"] +_data = [Vector2(0, 1), 0.0, 0.0, 0, 0, Vector2(1, 0), 0.0, 0.0, 0, 0] +point_count = 2 + +[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_m77kh"] +albedo_color = Color(0, 0, 1, 1) +emission_enabled = true +emission = Color(0, 0, 1, 1) +emission_energy_multiplier = 10.0 +use_particle_trails = true + +[sub_resource type="TubeTrailMesh" id="TubeTrailMesh_3g557"] +material = SubResource("StandardMaterial3D_m77kh") +radius = 0.05 +section_length = 0.15 +section_rings = 5 +cap_top = false +cap_bottom = false +curve = SubResource("Curve_bbjda") + +[node name="teleport_grenade" type="Telegrenade" unique_id=1670808846] +collision_layer = 0 +collision_mask = 0 +contact_monitor = true +max_contacts_reported = 1 + +[node name="collision_shape_3d" type="CollisionShape3D" parent="." unique_id=1124839205] +shape = SubResource("SphereShape3D_1cgct") + +[node name="Telegrenade" parent="." unique_id=1761178296 instance=ExtResource("1_nt0dp")] +transform = Transform3D(0.1, 0, 0, 0, 0.1, 0, 0, 0, 0.1, 0, 0, 0) + +[node name="gpu_particles_3d" type="GPUParticles3D" parent="." unique_id=608816258] +amount = 2 +trail_enabled = true +process_material = SubResource("ParticleProcessMaterial_1cgct") +draw_pass_1 = SubResource("TubeTrailMesh_3g557") diff --git a/rust/src/game_manager.rs b/rust/src/game_manager.rs index d7168fc..eaf2cb3 100644 --- a/rust/src/game_manager.rs +++ b/rust/src/game_manager.rs @@ -1310,10 +1310,16 @@ impl Game { pub fn spawn_telegrenade( &mut self, + player_id: u16, location: NetVector3, velocity: NetVector3, ) -> Option> { if let Some(map) = &mut self.current_map { + if let Some(recorder) = &mut self.replay_recorder { + recorder + .bind_mut() + .record_event(ReplayEvent::TelegrenadeSpawn(player_id, location, velocity)); + } map.bind_mut().spawn_telegrenade(location, velocity) } else { None @@ -1321,6 +1327,11 @@ impl Game { } pub fn on_throw_telegrenade(&mut self, player_id: u16, to: NetVector3) { + if let Some(recorder) = &mut self.replay_recorder { + recorder + .bind_mut() + .record_event(ReplayEvent::TelegrenadeDespawn(player_id)); + } if let Some(player) = self.find_player_mut(player_id) && let Some(character) = &mut player.character { @@ -1330,6 +1341,11 @@ impl Game { // Handle telegrenade activate from server to client pub fn handle_telegrenade_teleport(&mut self, player_id: u16, to: NetVector3) { + if let Some(recorder) = &mut self.replay_recorder { + recorder + .bind_mut() + .record_event(ReplayEvent::TelegrenadeDespawn(player_id)); + } if let Some(player) = self.find_player_mut(player_id) && let Some(character) = &mut player.character { diff --git a/rust/src/map.rs b/rust/src/map.rs index 6beec86..29cabea 100644 --- a/rust/src/map.rs +++ b/rust/src/map.rs @@ -220,4 +220,23 @@ impl Map { None } } + + pub fn spawn_replay_telegrenade( + &mut self, + location: NetVector3, + velocity: NetVector3, + ) -> Option> { + if let Some(prefab) = &GameManager::singleton().bind().telegrenade { + let mut telegrenade = prefab.instantiate_as::(); + telegrenade.set_collision_mask(0); + self.base_mut().add_child(&telegrenade); + + telegrenade.set_global_position(location.into()); + telegrenade.set_linear_velocity(velocity.into()); + + Some(telegrenade) + } else { + None + } + } } diff --git a/rust/src/player/mod.rs b/rust/src/player/mod.rs index 4408d24..6bd1b70 100644 --- a/rust/src/player/mod.rs +++ b/rust/src/player/mod.rs @@ -286,6 +286,7 @@ impl PlayerCommon for T { && let Some(origin) = s.get_camera_origin() { let mut telegrenade = game.bind_mut().spawn_telegrenade( + s.get_player_id().unwrap_or(0), origin.get_global_position().into(), (to.normalized() * 50.).into(), ); diff --git a/rust/src/replay.rs b/rust/src/replay.rs index 523093f..62c00da 100644 --- a/rust/src/replay.rs +++ b/rust/src/replay.rs @@ -16,7 +16,7 @@ use crate::{ pickup::{PickupKind, ReplayVisibility}, player::{ DamageSource, IPlayer, NetTransform, ball::Ball, remote_player::RemotePlayer, - weapon::WeaponType, + telegrenade::Telegrenade, weapon::WeaponType, }, ui::hud::Hud, }; @@ -147,6 +147,7 @@ pub struct ReplayPlayback { pub current_map: Option>, current_frame_idx: usize, player_characters: HashMap>, + telegrenades: HashMap>, ball: Option>, pub current_time: f64, @@ -295,6 +296,29 @@ impl INode for ReplayPlayback { character.bind_mut().on_pickup(*kind); } } + ReplayEvent::TelegrenadeSpawn(player_id, location, velocity) => { + if let Some(prev_grenade) = self.telegrenades.get_mut(player_id) { + prev_grenade.queue_free(); + } + self.telegrenades.remove(player_id); + + if let Some(map) = &mut self.current_map + && let Some(player) = self.replay.players.get(player_id) + { + if let Some(telegrenade) = map.bind_mut().spawn_replay_telegrenade( + (*location).into(), + (*velocity).into(), + ) { + self.telegrenades.insert(*player_id, telegrenade); + } + } + } + ReplayEvent::TelegrenadeDespawn(player_id) => { + if let Some(prev_grenade) = self.telegrenades.get_mut(player_id) { + prev_grenade.queue_free(); + } + self.telegrenades.remove(player_id); + } } } } @@ -350,6 +374,10 @@ impl INode for ReplayPlayback { character.queue_free(); } self.player_characters.clear(); + for (_, telegrenade) in &mut self.telegrenades { + telegrenade.queue_free(); + } + self.telegrenades.clear(); if let Some(mut ball) = self.ball.take() { ball.queue_free(); } @@ -603,6 +631,8 @@ pub enum ReplayEvent { Punch(u16, NetVector3), TakeDamage(u16, DamageSource, i32), Pickup(PickupKind, u16), + TelegrenadeSpawn(u16, NetVector3, NetVector3), + TelegrenadeDespawn(u16), } #[derive(Debug, Clone, Default, Serialize, Deserialize)]