@@ -1,2 +1,4 @@
|
|||||||
|
pub mod phase;
|
||||||
pub mod pom;
|
pub mod pom;
|
||||||
pub mod tile;
|
pub mod tile;
|
||||||
|
pub mod ui;
|
||||||
|
|||||||
79
src/components/phase.rs
Normal file
79
src/components/phase.rs
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
use bevy::prelude::*;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
|
pub enum Phase {
|
||||||
|
Break { duration: f32 },
|
||||||
|
Focus { duration: f32 },
|
||||||
|
Paused { previous_phase: Box<Phase> },
|
||||||
|
Finished { completed_phase: Box<Phase> },
|
||||||
|
}
|
||||||
|
|
||||||
|
fn format_time(seconds: f32) -> String {
|
||||||
|
let seconds = seconds.max(0.0) as u32;
|
||||||
|
|
||||||
|
if seconds >= 3600 {
|
||||||
|
let hours = seconds / 3600;
|
||||||
|
let minutes = (seconds % 3600) / 60;
|
||||||
|
let secs = seconds % 60;
|
||||||
|
format!("{:02}:{:02}:{:02}", hours, minutes, secs)
|
||||||
|
} else {
|
||||||
|
let minutes = seconds / 60;
|
||||||
|
let secs = seconds % 60;
|
||||||
|
format!("{:02}:{:02}", minutes, secs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Phase {
|
||||||
|
pub fn ui_color(&self) -> Color {
|
||||||
|
match self {
|
||||||
|
Phase::Focus { .. } => Color::srgb(0.9, 0.3, 0.3),
|
||||||
|
Phase::Break { .. } => Color::srgb(0.3, 0.8, 0.5),
|
||||||
|
Phase::Paused { .. } => Color::srgb(0.5, 0.5, 0.5),
|
||||||
|
Phase::Finished { .. } => Color::srgb(0.9, 0.8, 0.2),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn display_name(&self) -> &str {
|
||||||
|
match self {
|
||||||
|
Phase::Focus { .. } => "Fokus",
|
||||||
|
Phase::Break { .. } => "Pause",
|
||||||
|
Phase::Paused { .. } => "PAUSIERT [Leertaste]",
|
||||||
|
Phase::Finished { .. } => "ABGELAUFEN [Enter]",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn format_duration(&self) -> String {
|
||||||
|
match self {
|
||||||
|
Phase::Focus { duration } | Phase::Break { duration } => format_time(*duration),
|
||||||
|
Phase::Paused { previous_phase } => previous_phase.format_duration(),
|
||||||
|
Phase::Finished { .. } => "00:00".to_string(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Resource, Debug)]
|
||||||
|
pub struct CurrentPhase(pub Phase);
|
||||||
|
|
||||||
|
#[derive(Resource, Debug)]
|
||||||
|
pub struct TimerSettings {
|
||||||
|
pub focus_duration: f32,
|
||||||
|
pub short_break_duration: f32,
|
||||||
|
pub long_break_duration: f32,
|
||||||
|
pub long_break_interval: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for TimerSettings {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
focus_duration: 25.0 * 60.0,
|
||||||
|
short_break_duration: 5.0 * 60.0,
|
||||||
|
long_break_duration: 15.0 * 60.0,
|
||||||
|
long_break_interval: 4,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Resource, Debug, Default)]
|
||||||
|
pub struct SessionTracker {
|
||||||
|
pub completed_focus_phases: u32,
|
||||||
|
}
|
||||||
10
src/components/ui.rs
Normal file
10
src/components/ui.rs
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
use bevy::prelude::*;
|
||||||
|
|
||||||
|
#[derive(Component)]
|
||||||
|
pub struct UiStatusRootContainer;
|
||||||
|
|
||||||
|
#[derive(Component)]
|
||||||
|
pub struct UiPhaseText;
|
||||||
|
|
||||||
|
#[derive(Component)]
|
||||||
|
pub struct UiTimerText;
|
||||||
@@ -31,6 +31,8 @@ fn main() {
|
|||||||
plugins::GridPlugin,
|
plugins::GridPlugin,
|
||||||
plugins::PomPlugin,
|
plugins::PomPlugin,
|
||||||
plugins::InputPlugin,
|
plugins::InputPlugin,
|
||||||
|
plugins::PhasePlugin,
|
||||||
|
plugins::StatusPlugin,
|
||||||
))
|
))
|
||||||
.insert_resource(config)
|
.insert_resource(config)
|
||||||
.run();
|
.run();
|
||||||
|
|||||||
7
src/messages/interact.rs
Normal file
7
src/messages/interact.rs
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
use bevy::prelude::*;
|
||||||
|
|
||||||
|
#[derive(Message)]
|
||||||
|
pub struct InteractStartMessage {
|
||||||
|
pub x: u32,
|
||||||
|
pub y: u32,
|
||||||
|
}
|
||||||
3
src/messages/mod.rs
Normal file
3
src/messages/mod.rs
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
pub mod interact;
|
||||||
|
pub mod r#move;
|
||||||
|
pub mod phase;
|
||||||
@@ -10,9 +10,3 @@ pub struct MoveMessage {
|
|||||||
pub struct InvalidMoveMessage {
|
pub struct InvalidMoveMessage {
|
||||||
pub message: String,
|
pub message: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Message)]
|
|
||||||
pub struct InteractStartMessage {
|
|
||||||
pub x: u32,
|
|
||||||
pub y: u32,
|
|
||||||
}
|
|
||||||
13
src/messages/phase.rs
Normal file
13
src/messages/phase.rs
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
use crate::components::phase::Phase;
|
||||||
|
use bevy::prelude::*;
|
||||||
|
|
||||||
|
#[derive(Message)]
|
||||||
|
pub struct PhaseTimerFinishedMessage {
|
||||||
|
pub phase: Phase,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Message)]
|
||||||
|
pub struct PhaseTimerPauseMessage;
|
||||||
|
|
||||||
|
#[derive(Message)]
|
||||||
|
pub struct NextPhaseMessage;
|
||||||
@@ -2,9 +2,14 @@ use bevy::input::mouse::MouseButton;
|
|||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
use bevy::window::PrimaryWindow;
|
use bevy::window::PrimaryWindow;
|
||||||
|
|
||||||
|
use crate::components::phase::{CurrentPhase, Phase};
|
||||||
use crate::components::tile::{Grid, TileState};
|
use crate::components::tile::{Grid, TileState};
|
||||||
use crate::config::GameConfig;
|
use crate::config::GameConfig;
|
||||||
use crate::messages::{InteractStartMessage, InvalidMoveMessage, MoveMessage};
|
use crate::messages::phase::{NextPhaseMessage, PhaseTimerPauseMessage};
|
||||||
|
use crate::messages::{
|
||||||
|
interact::InteractStartMessage,
|
||||||
|
r#move::{InvalidMoveMessage, MoveMessage},
|
||||||
|
};
|
||||||
use crate::plugins::grid::world_to_grid_coords;
|
use crate::plugins::grid::world_to_grid_coords;
|
||||||
use crate::states::AppState;
|
use crate::states::AppState;
|
||||||
|
|
||||||
@@ -21,6 +26,15 @@ impl Plugin for InputPlugin {
|
|||||||
Update,
|
Update,
|
||||||
interact_click.run_if(in_state(AppState::GameScreen)),
|
interact_click.run_if(in_state(AppState::GameScreen)),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
app.add_message::<PhaseTimerPauseMessage>();
|
||||||
|
app.add_systems(
|
||||||
|
Update,
|
||||||
|
phase_timer_pause.run_if(in_state(AppState::GameScreen)),
|
||||||
|
);
|
||||||
|
|
||||||
|
app.add_message::<NextPhaseMessage>();
|
||||||
|
app.add_systems(Update, next_phase.run_if(in_state(AppState::GameScreen)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -30,7 +44,13 @@ fn move_click(
|
|||||||
window: Single<&Window, With<PrimaryWindow>>,
|
window: Single<&Window, With<PrimaryWindow>>,
|
||||||
camera: Single<(&Camera, &GlobalTransform), With<Camera2d>>,
|
camera: Single<(&Camera, &GlobalTransform), With<Camera2d>>,
|
||||||
config: Res<GameConfig>,
|
config: Res<GameConfig>,
|
||||||
|
phase: Res<CurrentPhase>,
|
||||||
) {
|
) {
|
||||||
|
match phase.0 {
|
||||||
|
Phase::Focus { .. } => return,
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
|
||||||
if mouse_btn.just_pressed(MouseButton::Right) {
|
if mouse_btn.just_pressed(MouseButton::Right) {
|
||||||
let (cam, cam_transform) = *camera;
|
let (cam, cam_transform) = *camera;
|
||||||
|
|
||||||
@@ -53,10 +73,16 @@ fn interact_click(
|
|||||||
window: Single<&Window, With<PrimaryWindow>>,
|
window: Single<&Window, With<PrimaryWindow>>,
|
||||||
camera: Single<(&Camera, &GlobalTransform), With<Camera2d>>,
|
camera: Single<(&Camera, &GlobalTransform), With<Camera2d>>,
|
||||||
config: Res<GameConfig>,
|
config: Res<GameConfig>,
|
||||||
|
phase: Res<CurrentPhase>,
|
||||||
// for debug
|
// for debug
|
||||||
grid: ResMut<Grid>,
|
grid: ResMut<Grid>,
|
||||||
tile_query: Query<&mut TileState>,
|
tile_query: Query<&mut TileState>,
|
||||||
) {
|
) {
|
||||||
|
match phase.0 {
|
||||||
|
Phase::Focus { .. } => return,
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
|
||||||
if mouse_btn.just_pressed(MouseButton::Left) {
|
if mouse_btn.just_pressed(MouseButton::Left) {
|
||||||
let (cam, cam_transform) = *camera;
|
let (cam, cam_transform) = *camera;
|
||||||
|
|
||||||
@@ -85,3 +111,18 @@ fn interact_click(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn phase_timer_pause(
|
||||||
|
mut pause_messages: MessageWriter<PhaseTimerPauseMessage>,
|
||||||
|
keys: Res<ButtonInput<KeyCode>>,
|
||||||
|
) {
|
||||||
|
if keys.just_pressed(KeyCode::Space) {
|
||||||
|
pause_messages.write(PhaseTimerPauseMessage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn next_phase(mut messages: MessageWriter<NextPhaseMessage>, keys: Res<ButtonInput<KeyCode>>) {
|
||||||
|
if keys.just_pressed(KeyCode::Enter) {
|
||||||
|
messages.write(NextPhaseMessage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -2,12 +2,16 @@ pub mod core;
|
|||||||
pub mod game_screen;
|
pub mod game_screen;
|
||||||
pub mod grid;
|
pub mod grid;
|
||||||
pub mod input;
|
pub mod input;
|
||||||
|
pub mod phase;
|
||||||
pub mod pom;
|
pub mod pom;
|
||||||
pub mod start_screen;
|
pub mod start_screen;
|
||||||
|
pub mod status;
|
||||||
|
|
||||||
pub use core::CorePlugin;
|
pub use core::CorePlugin;
|
||||||
pub use game_screen::GameScreenPlugin;
|
pub use game_screen::GameScreenPlugin;
|
||||||
pub use grid::GridPlugin;
|
pub use grid::GridPlugin;
|
||||||
pub use input::InputPlugin;
|
pub use input::InputPlugin;
|
||||||
|
pub use phase::PhasePlugin;
|
||||||
pub use pom::PomPlugin;
|
pub use pom::PomPlugin;
|
||||||
pub use start_screen::StartScreenPlugin;
|
pub use start_screen::StartScreenPlugin;
|
||||||
|
pub use status::StatusPlugin;
|
||||||
|
|||||||
153
src/plugins/phase.rs
Normal file
153
src/plugins/phase.rs
Normal file
@@ -0,0 +1,153 @@
|
|||||||
|
use crate::{components::phase::*, messages::phase::*, states::AppState};
|
||||||
|
use bevy::prelude::*;
|
||||||
|
|
||||||
|
pub struct PhasePlugin;
|
||||||
|
|
||||||
|
impl Plugin for PhasePlugin {
|
||||||
|
fn build(&self, app: &mut App) {
|
||||||
|
app.init_resource::<TimerSettings>();
|
||||||
|
app.init_resource::<SessionTracker>();
|
||||||
|
app.insert_resource(CurrentPhase(Phase::Focus {
|
||||||
|
duration: 25.0 * 60.0,
|
||||||
|
}));
|
||||||
|
|
||||||
|
app.add_message::<PhaseTimerFinishedMessage>();
|
||||||
|
|
||||||
|
app.add_systems(OnEnter(AppState::GameScreen), load_rules);
|
||||||
|
app.add_systems(
|
||||||
|
Update,
|
||||||
|
(tick_timer, handle_pause, handle_continue).run_if(in_state(AppState::GameScreen)),
|
||||||
|
);
|
||||||
|
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
app.add_systems(Update, debug_short_phase_duration);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
fn debug_short_phase_duration(
|
||||||
|
mut phase_res: ResMut<CurrentPhase>,
|
||||||
|
keys: Res<ButtonInput<KeyCode>>,
|
||||||
|
) {
|
||||||
|
if keys.any_pressed([KeyCode::ShiftLeft, KeyCode::ShiftRight])
|
||||||
|
&& keys.just_pressed(KeyCode::Enter)
|
||||||
|
{
|
||||||
|
let phase = &mut phase_res.0;
|
||||||
|
match phase {
|
||||||
|
Phase::Focus { duration } | Phase::Break { duration } => {
|
||||||
|
*duration = 3.0;
|
||||||
|
println!("Debug: Phase duration set to 3 seconds!");
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn load_rules(mut phase_res: ResMut<CurrentPhase>, settings: Res<TimerSettings>) {
|
||||||
|
let phase = &mut phase_res.0;
|
||||||
|
|
||||||
|
let new_phase = match phase {
|
||||||
|
Phase::Focus { .. } => Some(Phase::Focus {
|
||||||
|
duration: settings.focus_duration,
|
||||||
|
}),
|
||||||
|
Phase::Break { .. } => Some(Phase::Break { duration: 0.0 }),
|
||||||
|
_ => None,
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(p) = new_phase {
|
||||||
|
*phase = p;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn tick_timer(
|
||||||
|
time: Res<Time>,
|
||||||
|
mut phase_res: ResMut<CurrentPhase>,
|
||||||
|
mut finish_writer: MessageWriter<PhaseTimerFinishedMessage>,
|
||||||
|
) {
|
||||||
|
let delta = time.delta_secs();
|
||||||
|
let phase = &mut phase_res.0;
|
||||||
|
|
||||||
|
match phase {
|
||||||
|
Phase::Focus { duration } | Phase::Break { duration } => {
|
||||||
|
*duration -= delta;
|
||||||
|
|
||||||
|
if *duration <= 0.0 {
|
||||||
|
finish_writer.write(PhaseTimerFinishedMessage {
|
||||||
|
phase: phase.clone(),
|
||||||
|
});
|
||||||
|
let completed = phase.clone();
|
||||||
|
*phase = Phase::Finished {
|
||||||
|
completed_phase: Box::new(completed),
|
||||||
|
};
|
||||||
|
|
||||||
|
println!("phase ended");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_pause(
|
||||||
|
mut messages: MessageReader<PhaseTimerPauseMessage>,
|
||||||
|
mut phase_res: ResMut<CurrentPhase>,
|
||||||
|
) {
|
||||||
|
for _ in messages.read() {
|
||||||
|
let phase = &mut phase_res.0;
|
||||||
|
|
||||||
|
match phase {
|
||||||
|
Phase::Focus { .. } | Phase::Break { .. } => {
|
||||||
|
let current_state = phase.clone();
|
||||||
|
*phase = Phase::Paused {
|
||||||
|
previous_phase: Box::new(current_state),
|
||||||
|
};
|
||||||
|
println!("Phase paused");
|
||||||
|
}
|
||||||
|
Phase::Paused { previous_phase } => {
|
||||||
|
*phase = *previous_phase.clone();
|
||||||
|
println!("Phase resumed");
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_continue(
|
||||||
|
mut messages: MessageReader<NextPhaseMessage>,
|
||||||
|
mut phase_res: ResMut<CurrentPhase>,
|
||||||
|
mut session_tracker: ResMut<SessionTracker>,
|
||||||
|
settings: Res<TimerSettings>,
|
||||||
|
) {
|
||||||
|
for _ in messages.read() {
|
||||||
|
let phase = &mut phase_res.0;
|
||||||
|
|
||||||
|
if let Phase::Finished { completed_phase } = phase {
|
||||||
|
match **completed_phase {
|
||||||
|
Phase::Focus { .. } => {
|
||||||
|
session_tracker.completed_focus_phases += 1;
|
||||||
|
|
||||||
|
// TODO: add berry grant logic
|
||||||
|
|
||||||
|
let is_long_break = session_tracker.completed_focus_phases > 0
|
||||||
|
&& session_tracker.completed_focus_phases % settings.long_break_interval
|
||||||
|
== 0;
|
||||||
|
|
||||||
|
if is_long_break {
|
||||||
|
*phase = Phase::Break {
|
||||||
|
duration: settings.long_break_duration,
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
*phase = Phase::Break {
|
||||||
|
duration: settings.short_break_duration,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Phase::Break { .. } => {
|
||||||
|
*phase = Phase::Focus {
|
||||||
|
duration: 25.0 * 60.0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
use crate::components::pom::{GridPosition, MovingState, PathQueue, Pom};
|
use crate::components::pom::{GridPosition, MovingState, PathQueue, Pom};
|
||||||
use crate::components::tile::{Grid, TileState};
|
use crate::components::tile::{Grid, TileState};
|
||||||
use crate::config::GameConfig;
|
use crate::config::GameConfig;
|
||||||
use crate::messages::{InvalidMoveMessage, MoveMessage};
|
use crate::messages::r#move::{InvalidMoveMessage, MoveMessage};
|
||||||
use crate::plugins::grid::{TILE_SIZE, grid_to_world_coords};
|
use crate::plugins::grid::{TILE_SIZE, grid_to_world_coords};
|
||||||
use crate::states::*;
|
use crate::states::*;
|
||||||
use crate::utils::pathfinding::find_path;
|
use crate::utils::pathfinding::find_path;
|
||||||
|
|||||||
74
src/plugins/status.rs
Normal file
74
src/plugins/status.rs
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
use crate::{
|
||||||
|
components::{phase::CurrentPhase, ui::*},
|
||||||
|
states::AppState,
|
||||||
|
};
|
||||||
|
use bevy::prelude::*;
|
||||||
|
|
||||||
|
pub struct StatusPlugin;
|
||||||
|
|
||||||
|
impl Plugin for StatusPlugin {
|
||||||
|
fn build(&self, app: &mut App) {
|
||||||
|
app.add_systems(OnEnter(AppState::GameScreen), setup);
|
||||||
|
app.add_systems(OnExit(AppState::GameScreen), cleanup);
|
||||||
|
app.add_systems(Update, update_status.run_if(in_state(AppState::GameScreen)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn setup(mut commands: Commands) {
|
||||||
|
commands.spawn((
|
||||||
|
UiStatusRootContainer,
|
||||||
|
Node {
|
||||||
|
position_type: PositionType::Absolute,
|
||||||
|
bottom: px(0),
|
||||||
|
left: px(0),
|
||||||
|
|
||||||
|
width: percent(100),
|
||||||
|
height: px(50),
|
||||||
|
|
||||||
|
justify_content: JustifyContent::SpaceAround,
|
||||||
|
align_items: AlignItems::Center,
|
||||||
|
flex_direction: FlexDirection::Row,
|
||||||
|
..default()
|
||||||
|
},
|
||||||
|
BackgroundColor(Color::srgba(0.0, 0.0, 0.0, 0.8)),
|
||||||
|
children![
|
||||||
|
(
|
||||||
|
UiPhaseText,
|
||||||
|
Text::new("..."),
|
||||||
|
TextFont::from_font_size(16.0),
|
||||||
|
TextColor(Color::WHITE)
|
||||||
|
),
|
||||||
|
(
|
||||||
|
UiTimerText,
|
||||||
|
Text::new("--:--"),
|
||||||
|
TextFont::from_font_size(16.0),
|
||||||
|
TextColor(Color::WHITE)
|
||||||
|
)
|
||||||
|
],
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update_status(
|
||||||
|
phase_res: Res<CurrentPhase>,
|
||||||
|
mut phase_query: Query<&mut Text, (With<UiPhaseText>, Without<UiTimerText>)>,
|
||||||
|
mut timer_query: Query<&mut Text, (With<UiTimerText>, Without<UiPhaseText>)>,
|
||||||
|
) {
|
||||||
|
if !phase_res.is_changed() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let current_phase = &phase_res.0;
|
||||||
|
|
||||||
|
if let Ok(mut phase_text) = phase_query.single_mut() {
|
||||||
|
phase_text.0 = current_phase.display_name().to_string();
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Ok(mut timer_text) = timer_query.single_mut() {
|
||||||
|
timer_text.0 = current_phase.format_duration();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cleanup(mut commands: Commands, query: Query<Entity, With<UiStatusRootContainer>>) {
|
||||||
|
for entity in query.iter() {
|
||||||
|
commands.entity(entity).despawn();
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user