Add replay telegrenades

This commit is contained in:
Sofia 2026-07-28 22:18:28 +03:00
parent f68a9dfc1e
commit c5880c4b1a
5 changed files with 121 additions and 1 deletions

View File

@ -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")

View File

@ -1310,10 +1310,16 @@ impl Game {
pub fn spawn_telegrenade(
&mut self,
player_id: u16,
location: NetVector3,
velocity: NetVector3,
) -> Option<Gd<Telegrenade>> {
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
{

View File

@ -220,4 +220,23 @@ impl Map {
None
}
}
pub fn spawn_replay_telegrenade(
&mut self,
location: NetVector3,
velocity: NetVector3,
) -> Option<Gd<Telegrenade>> {
if let Some(prefab) = &GameManager::singleton().bind().telegrenade {
let mut telegrenade = prefab.instantiate_as::<Telegrenade>();
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
}
}
}

View File

@ -286,6 +286,7 @@ impl<T: IPlayer + ICharacterBody3D + WithBaseField> 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(),
);

View File

@ -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<Gd<Map>>,
current_frame_idx: usize,
player_characters: HashMap<u16, Gd<RemotePlayer>>,
telegrenades: HashMap<u16, Gd<Telegrenade>>,
ball: Option<Gd<Ball>>,
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)]