feat: implement wonder event response handling and visual feedback
This commit is contained in:
@@ -1,6 +1,8 @@
|
|||||||
use self::components::{MaxFieldSize, WonderEventMessage};
|
use self::components::{MaxFieldSize, WonderEventMessage};
|
||||||
use crate::features::phase::components::{CurrentPhase, Phase, TimerSettings};
|
use crate::features::phase::components::{CurrentPhase, Phase, TimerSettings};
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
use std::sync::Mutex;
|
||||||
|
use std::sync::mpsc::{Receiver, Sender, channel};
|
||||||
use std::thread;
|
use std::thread;
|
||||||
use tungstenite::{Message as WsMessage, connect};
|
use tungstenite::{Message as WsMessage, connect};
|
||||||
use url::Url;
|
use url::Url;
|
||||||
@@ -15,8 +17,24 @@ pub struct RequestWonderEvent {
|
|||||||
pub max_field_size: MaxFieldSize,
|
pub max_field_size: MaxFieldSize,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Resource)]
|
||||||
|
pub struct WonderEventSender(pub Sender<WonderEventMessage>);
|
||||||
|
|
||||||
|
#[derive(Resource)]
|
||||||
|
pub struct WonderEventReceiver(pub Mutex<Receiver<WonderEventMessage>>);
|
||||||
|
|
||||||
|
#[derive(Component)]
|
||||||
|
struct FloatingText {
|
||||||
|
timer: Timer,
|
||||||
|
velocity: Vec3,
|
||||||
|
}
|
||||||
|
|
||||||
impl Plugin for WonderEventPlugin {
|
impl Plugin for WonderEventPlugin {
|
||||||
fn build(&self, app: &mut App) {
|
fn build(&self, app: &mut App) {
|
||||||
|
let (tx, rx) = channel();
|
||||||
|
app.insert_resource(WonderEventSender(tx));
|
||||||
|
app.insert_resource(WonderEventReceiver(Mutex::new(rx)));
|
||||||
|
|
||||||
app.init_resource::<WonderEventState>();
|
app.init_resource::<WonderEventState>();
|
||||||
app.add_message::<RequestWonderEvent>();
|
app.add_message::<RequestWonderEvent>();
|
||||||
app.add_systems(
|
app.add_systems(
|
||||||
@@ -24,6 +42,8 @@ impl Plugin for WonderEventPlugin {
|
|||||||
(
|
(
|
||||||
check_halfway_focus.run_if(in_state(AppState::GameScreen)),
|
check_halfway_focus.run_if(in_state(AppState::GameScreen)),
|
||||||
handle_wonder_event_trigger,
|
handle_wonder_event_trigger,
|
||||||
|
handle_wonder_event_response.run_if(in_state(AppState::GameScreen)),
|
||||||
|
animate_floating_text,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -75,10 +95,14 @@ fn check_halfway_focus(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_wonder_event_trigger(mut events: MessageReader<RequestWonderEvent>) {
|
fn handle_wonder_event_trigger(
|
||||||
|
mut events: MessageReader<RequestWonderEvent>,
|
||||||
|
sender: Res<WonderEventSender>,
|
||||||
|
) {
|
||||||
for event in events.read() {
|
for event in events.read() {
|
||||||
let url_str = event.url_str.clone();
|
let url_str = event.url_str.clone();
|
||||||
let max_field_size = event.max_field_size.clone();
|
let max_field_size = event.max_field_size.clone();
|
||||||
|
let tx = sender.0.clone();
|
||||||
|
|
||||||
thread::spawn(move || {
|
thread::spawn(move || {
|
||||||
println!("WonderEvent: Connecting to {}", url_str);
|
println!("WonderEvent: Connecting to {}", url_str);
|
||||||
@@ -96,6 +120,25 @@ fn handle_wonder_event_trigger(mut events: MessageReader<RequestWonderEvent>) {
|
|||||||
eprintln!("WonderEvent: Error sending message: {}", e);
|
eprintln!("WonderEvent: Error sending message: {}", e);
|
||||||
} else {
|
} else {
|
||||||
println!("WonderEvent: Request sent successfully");
|
println!("WonderEvent: Request sent successfully");
|
||||||
|
|
||||||
|
// Read response
|
||||||
|
if let Ok(msg) = socket.read() {
|
||||||
|
if let Ok(text) = msg.into_text() {
|
||||||
|
println!("WonderEvent: Received response: {}", text);
|
||||||
|
if let Ok(response) =
|
||||||
|
serde_json::from_str::<WonderEventMessage>(&text)
|
||||||
|
{
|
||||||
|
if let Err(e) = tx.send(response) {
|
||||||
|
eprintln!(
|
||||||
|
"WonderEvent: Failed to send response to main thread: {}",
|
||||||
|
e
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
eprintln!("WonderEvent: Failed to parse response JSON");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
eprintln!("WonderEvent: Error serializing request");
|
eprintln!("WonderEvent: Error serializing request");
|
||||||
@@ -115,3 +158,98 @@ fn handle_wonder_event_trigger(mut events: MessageReader<RequestWonderEvent>) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn handle_wonder_event_response(
|
||||||
|
receiver: Res<WonderEventReceiver>,
|
||||||
|
grid: Res<Grid>,
|
||||||
|
mut tile_query: Query<&mut TileState>,
|
||||||
|
game_config: Res<GameConfig>,
|
||||||
|
mut commands: Commands,
|
||||||
|
) {
|
||||||
|
if let Ok(rx) = receiver.0.try_lock() {
|
||||||
|
while let Ok(msg) = rx.try_recv() {
|
||||||
|
match msg {
|
||||||
|
WonderEventMessage::WonderGranted { position } => {
|
||||||
|
println!("WonderEvent: GRANTED at ({}, {})", position.x, position.y);
|
||||||
|
|
||||||
|
// Update Tile State
|
||||||
|
if let Ok(_) = grid.map_tile_state(
|
||||||
|
(position.x, position.y),
|
||||||
|
|state| {
|
||||||
|
if let TileState::Occupied {
|
||||||
|
seed,
|
||||||
|
watered,
|
||||||
|
growth_stage,
|
||||||
|
withered,
|
||||||
|
dry_counter,
|
||||||
|
} = state
|
||||||
|
{
|
||||||
|
// Progress growth stage
|
||||||
|
let mut new_stage = *growth_stage;
|
||||||
|
if let Some(config) = seed.get_seed_config(&game_config) {
|
||||||
|
if new_stage < config.growth_stages {
|
||||||
|
new_stage += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TileState::Occupied {
|
||||||
|
seed: seed.clone(),
|
||||||
|
watered: *watered,
|
||||||
|
growth_stage: new_stage,
|
||||||
|
withered: *withered,
|
||||||
|
dry_counter: *dry_counter,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
state.clone()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
tile_query.reborrow(),
|
||||||
|
) {
|
||||||
|
let world_pos = grid_to_world_coords(
|
||||||
|
position.x,
|
||||||
|
position.y,
|
||||||
|
None,
|
||||||
|
grid.width,
|
||||||
|
grid.height,
|
||||||
|
);
|
||||||
|
commands.spawn((
|
||||||
|
Text2d::new("Wonder!"),
|
||||||
|
TextFont {
|
||||||
|
font_size: 20.0,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
TextColor(Color::srgb(1.0, 0.8, 0.2)),
|
||||||
|
Transform::from_translation(world_pos + Vec3::new(0.0, 20.0, 10.0)),
|
||||||
|
FloatingText {
|
||||||
|
timer: Timer::from_seconds(1.5, TimerMode::Once),
|
||||||
|
velocity: Vec3::new(0.0, 20.0, 0.0),
|
||||||
|
},
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
WonderEventMessage::RequestError { error } => {
|
||||||
|
println!("WonderEvent: REQUEST ERROR: {}", error);
|
||||||
|
}
|
||||||
|
WonderEventMessage::NoWonder => {
|
||||||
|
println!("WonderEvent: NO WONDER");
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn animate_floating_text(
|
||||||
|
mut commands: Commands,
|
||||||
|
time: Res<Time>,
|
||||||
|
mut query: Query<(Entity, &mut FloatingText, &mut Transform)>,
|
||||||
|
) {
|
||||||
|
for (entity, mut float, mut transform) in query.iter_mut() {
|
||||||
|
float.timer.tick(time.delta());
|
||||||
|
transform.translation += float.velocity * time.delta_secs();
|
||||||
|
|
||||||
|
if float.timer.is_finished() {
|
||||||
|
commands.entity(entity).despawn();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user