Add pickup visibility for replays

This commit is contained in:
Sofia 2026-07-27 19:46:12 +03:00
parent f92ddf567d
commit e6793fde61
5 changed files with 55 additions and 7 deletions

View File

@ -196,8 +196,6 @@ impl Map {
} }
pub fn register_pickup(&mut self, pickup: DynGd<Node3D, dyn Pickup>) -> u8 { pub fn register_pickup(&mut self, pickup: DynGd<Node3D, dyn Pickup>) -> u8 {
godot_print!("Registered {:?}", pickup);
let id = self.pickup_counter; let id = self.pickup_counter;
self.pickup_counter += 1; self.pickup_counter += 1;
self.pickups.insert(id, pickup); self.pickups.insert(id, pickup);

View File

@ -14,6 +14,14 @@ pub enum PickupKind {
Health, Health,
} }
#[derive(Debug, Default)]
pub enum ReplayVisibility {
#[default]
NoReplay,
Hidden,
Visible,
}
#[derive(GodotClass)] #[derive(GodotClass)]
#[class(base=Node3D, init, tool)] #[class(base=Node3D, init, tool)]
pub struct HealthPickup { pub struct HealthPickup {
@ -23,6 +31,7 @@ pub struct HealthPickup {
time_elapsed: f64, time_elapsed: f64,
pickup_id: Option<u8>, pickup_id: Option<u8>,
respawn: f64, respawn: f64,
replay_visibility: ReplayVisibility,
base: Base<Node3D>, base: Base<Node3D>,
} }
@ -52,8 +61,14 @@ impl INode3D for HealthPickup {
self.time_elapsed += delta; self.time_elapsed += delta;
self.respawn -= delta; self.respawn -= delta;
self.update_common(self.time_elapsed); self.update_common(self.time_elapsed);
if let Some(area) = &mut self.pickup_area { if let Some(mut area) = self.pickup_area.clone() {
area.set_visible(self.respawn <= 0.); match self.replay_visibility {
ReplayVisibility::NoReplay => {
area.set_visible(self.is_active());
}
ReplayVisibility::Hidden => area.set_visible(false),
ReplayVisibility::Visible => area.set_visible(true),
}
} }
} }
} }
@ -84,7 +99,15 @@ impl Pickup for HealthPickup {
} }
fn on_pickup(&mut self) { fn on_pickup(&mut self) {
self.respawn = 10.; self.respawn = 30.;
}
fn is_active(&self) -> bool {
self.respawn <= 0.
}
fn set_replay(&mut self, visible: ReplayVisibility) {
self.replay_visibility = visible;
} }
} }
@ -93,6 +116,8 @@ pub trait Pickup {
fn kind(&self) -> PickupKind; fn kind(&self) -> PickupKind;
fn id(&self) -> Option<u8>; fn id(&self) -> Option<u8>;
fn on_pickup(&mut self); fn on_pickup(&mut self);
fn is_active(&self) -> bool;
fn set_replay(&mut self, visibility: ReplayVisibility);
} }
pub trait PickupCommon { pub trait PickupCommon {

View File

@ -309,7 +309,6 @@ impl IPlayer for LocalPlayer {
} }
fn on_pickup(&mut self, kind: PickupKind) { fn on_pickup(&mut self, kind: PickupKind) {
godot_print!("picked up");
match kind { match kind {
PickupKind::Health => self.heal(100), PickupKind::Health => self.heal(100),
} }

View File

@ -15,6 +15,7 @@ use crate::{
game_manager::{Game, GameManager, Player}, game_manager::{Game, GameManager, Player},
map::Map, map::Map,
net::{network_manager::BallSync, util::NetVector3}, net::{network_manager::BallSync, util::NetVector3},
pickup::ReplayVisibility,
player::{ player::{
DamageSource, IPlayer, NetTransform, ball::Ball, remote_player::RemotePlayer, DamageSource, IPlayer, NetTransform, ball::Ball, remote_player::RemotePlayer,
weapon::WeaponType, weapon::WeaponType,
@ -196,6 +197,17 @@ impl INode for ReplayPlayback {
self.player_data = frame.player_data.clone(); self.player_data = frame.player_data.clone();
self.running_goals = frame.goals.clone(); self.running_goals = frame.goals.clone();
if let Some(map) = &mut self.current_map {
for (id, visible) in frame.pickups_visible {
if let Some(pickup) = map.bind_mut().pickups.get_mut(&id) {
pickup.dyn_bind_mut().set_replay(match visible {
true => ReplayVisibility::Visible,
false => ReplayVisibility::Hidden,
});
}
}
}
if let ReplayBall::World(ball_state) = &frame.ball_data { if let ReplayBall::World(ball_state) = &frame.ball_data {
if let Some(ball) = &mut self.ball { if let Some(ball) = &mut self.ball {
ball.bind_mut().apply_sync(BallSync { ball.bind_mut().apply_sync(BallSync {
@ -325,6 +337,11 @@ impl INode for ReplayPlayback {
} }
fn exit_tree(&mut self) { fn exit_tree(&mut self) {
if let Some(map) = &mut self.current_map {
for (_, pickup) in &mut map.bind_mut().pickups {
pickup.dyn_bind_mut().set_replay(ReplayVisibility::NoReplay);
}
}
for (_, character) in &mut self.player_characters { for (_, character) in &mut self.player_characters {
character.queue_free(); character.queue_free();
} }
@ -424,6 +441,8 @@ impl ReplayRecorder {
let mut goals = HashMap::new(); let mut goals = HashMap::new();
let mut pickups_visible = HashMap::new();
if let Some(game) = Game::singleton() { if let Some(game) = Game::singleton() {
for player in &game.bind().players { for player in &game.bind().players {
if let Some(state) = player.get_state(player.clone()) { if let Some(state) = player.get_state(player.clone()) {
@ -443,6 +462,12 @@ impl ReplayRecorder {
ReplayBall::Held ReplayBall::Held
}; };
if let Some(map) = &game.bind().current_map {
for (id, pickup) in &map.bind().pickups {
pickups_visible.insert(*id, pickup.dyn_bind().is_active());
}
}
goals = game.bind().goals.clone(); goals = game.bind().goals.clone();
} }
@ -451,6 +476,7 @@ impl ReplayRecorder {
ReplayFrame { ReplayFrame {
time: self.time_elapsed, time: self.time_elapsed,
goals, goals,
pickups_visible,
player_data, player_data,
ball_data, ball_data,
events: Vec::new(), events: Vec::new(),
@ -530,6 +556,7 @@ pub struct ReplayFrame {
time: f64, time: f64,
player_data: HashMap<u16, ReplayPlayerState>, player_data: HashMap<u16, ReplayPlayerState>,
ball_data: ReplayBall, ball_data: ReplayBall,
pickups_visible: HashMap<u8, bool>,
events: Vec<ReplayEvent>, events: Vec<ReplayEvent>,
goals: HashMap<u8, u16>, goals: HashMap<u8, u16>,
} }

View File

@ -63,7 +63,6 @@ impl IHBoxContainer for PlayerListing {
impl PlayerListing { impl PlayerListing {
pub fn update(&mut self) { pub fn update(&mut self) {
godot_print!("update");
if let Some(player_id) = self.player_id { if let Some(player_id) = self.player_id {
if let Some(game) = Game::singleton() { if let Some(game) = Game::singleton() {
if let Some(player) = game.bind().find_player(player_id) { if let Some(player) = game.bind().find_player(player_id) {