diff --git a/game/Cargo.toml b/game/Cargo.toml index 27126cb..d20822c 100644 --- a/game/Cargo.toml +++ b/game/Cargo.toml @@ -32,6 +32,7 @@ cfg-if = "1.0" num-derive = "0.3" num = "0.4" tiled = { version ="0.9.5", default-features = false } +async-trait = "0.1.51" [dev-dependencies] puffin_viewer = "0.6" diff --git a/game/assets/logos/game-logo-small.png b/game/assets/logos/game-logo-small.png new file mode 100644 index 0000000..fe614a2 Binary files /dev/null and b/game/assets/logos/game-logo-small.png differ diff --git a/game/src/context.rs b/game/src/context.rs index 27fe726..a3e0ac3 100644 --- a/game/src/context.rs +++ b/game/src/context.rs @@ -1,4 +1,6 @@ -use std::cell::RefCell; +use std::{cell::RefCell, sync::mpsc::Sender}; + +use discord_sdk::activity::ActivityBuilder; use crate::{GameConfig, utilities::non_ref_raylib::HackedRaylibHandle}; @@ -6,7 +8,8 @@ use crate::{GameConfig, utilities::non_ref_raylib::HackedRaylibHandle}; #[derive(Debug)] pub struct GameContext { pub renderer: RefCell, - pub config: GameConfig + pub config: GameConfig, + pub discord_rpc_send: Sender> } // impl GameContext { diff --git a/game/src/lib.rs b/game/src/lib.rs index ca21477..d1ab32c 100644 --- a/game/src/lib.rs +++ b/game/src/lib.rs @@ -1,6 +1,7 @@ #![feature(derive_default_enum)] #![feature(custom_inner_attributes)] #![feature(stmt_expr_attributes)] +#![feature(async_await)] #![feature(c_variadic)] #![deny(unsafe_code)] #![warn( @@ -69,7 +70,7 @@ )] #![clippy::msrv = "1.57.0"] -use std::cell::RefCell; +use std::{cell::RefCell, sync::mpsc::TryRecvError}; use discord_sdk::activity::ActivityBuilder; use raylib::prelude::*; @@ -97,6 +98,8 @@ extern crate serde; extern crate approx; #[macro_use] extern crate num_derive; +#[macro_use] +extern crate async_trait; mod context; mod discord_rpc; @@ -133,11 +136,14 @@ pub async fn game_begin(game_config: &mut GameConfig) -> Result<(), Box Result<(), Box Result<(), Box Result<(), Box Result<(), Box { + if let Some(activity) = activity { + if let Err(e) = maybe_set_discord_presence(&discord_rpc, activity).await { + error!("Failed to update discord presence: {:?}", e); + } + } + } + Err(TryRecvError::Empty) => {} + Err(TryRecvError::Disconnected) => { + error!("Discord RPC channel disconnected"); + continue; + } + } } Ok(()) } diff --git a/game/src/scenes/fsm_error_screen.rs b/game/src/scenes/fsm_error_screen.rs index 7a57148..d1fee04 100644 --- a/game/src/scenes/fsm_error_screen.rs +++ b/game/src/scenes/fsm_error_screen.rs @@ -1,6 +1,7 @@ use dirty_fsm::{Action, ActionFlag}; +use discord_sdk::activity::{ActivityBuilder, Assets}; use raylib::{color::Color, prelude::RaylibDraw}; -use tracing::{debug, trace}; +use tracing::{debug, error, trace}; use crate::{ context::GameContext, @@ -26,8 +27,20 @@ impl Action for FsmErrorScreen { Ok(()) } - fn on_first_run(&mut self, _context: &GameContext) -> Result<(), ScreenError> { + fn on_first_run(&mut self, context: &GameContext) -> Result<(), ScreenError> { debug!("Running FsmErrorScreen for the first time"); + + // Update discord + if let Err(e) = context.discord_rpc_send.send(Some( + ActivityBuilder::default() + .details("IT FUCKING DIED") + .assets( + Assets::default().large("game-logo-small", Some(context.config.name.clone())), + ), + )) { + error!("Failed to update discord: {}", e); + } + Ok(()) } diff --git a/game/src/scenes/ingame_scene/mod.rs b/game/src/scenes/ingame_scene/mod.rs index 1509484..bfe505e 100644 --- a/game/src/scenes/ingame_scene/mod.rs +++ b/game/src/scenes/ingame_scene/mod.rs @@ -1,4 +1,5 @@ use dirty_fsm::{Action, ActionFlag}; +use discord_sdk::activity::{ActivityBuilder, Assets}; use raylib::prelude::*; use crate::{ @@ -13,7 +14,7 @@ use crate::{ use self::level::Level; use super::{Scenes, ScreenError}; -use tracing::{debug, trace}; +use tracing::{debug, error, trace}; mod hud; pub mod level; @@ -57,7 +58,7 @@ impl Action for InGameScreen { Ok(()) } - fn on_first_run(&mut self, _context: &GameContext) -> Result<(), ScreenError> { + fn on_first_run(&mut self, context: &GameContext) -> Result<(), ScreenError> { debug!("Running InGameScreen for the first time"); // Set the player to running @@ -68,6 +69,15 @@ impl Action for InGameScreen { -cur_level.platform_tex.height as f32, ); + // Update discord + if let Err(e) = context.discord_rpc_send.send(Some( + ActivityBuilder::default().details("in game").assets( + Assets::default().large("game-logo-small", Some(context.config.name.clone())), + ), + )) { + error!("Failed to update discord: {}", e); + } + Ok(()) } @@ -105,8 +115,6 @@ impl Action for InGameScreen { } else { Ok(ActionFlag::Continue) } - - } fn on_finish(&mut self, _interrupted: bool) -> Result<(), ScreenError> { diff --git a/game/src/scenes/loading_screen.rs b/game/src/scenes/loading_screen.rs index 0ccc70b..01b31be 100644 --- a/game/src/scenes/loading_screen.rs +++ b/game/src/scenes/loading_screen.rs @@ -3,6 +3,7 @@ use std::ops::{Div, Sub}; use cfg_if::cfg_if; use chrono::{DateTime, Utc}; use dirty_fsm::{Action, ActionFlag}; +use discord_sdk::activity::{ActivityBuilder, Assets}; use raylib::prelude::*; use crate::{GameConfig, context::GameContext, utilities::{ @@ -13,7 +14,7 @@ use crate::{GameConfig, context::GameContext, utilities::{ }}; use super::{Scenes, ScreenError}; -use tracing::{debug, info, trace}; +use tracing::{debug, info, error, trace}; /// Defines how long the loading screen should be displayed. const LOADING_SCREEN_DURATION_SECONDS: u8 = 3; @@ -49,9 +50,18 @@ impl Action for LoadingScreen { Ok(()) } - fn on_first_run(&mut self, _context: &GameContext) -> Result<(), ScreenError> { + fn on_first_run(&mut self, context: &GameContext) -> Result<(), ScreenError> { debug!("Running LoadingScreen for the first time"); + // Update discord + if let Err(e) = context.discord_rpc_send.send(Some( + ActivityBuilder::default().details("loading...").assets( + Assets::default().large("game-logo-small", Some(context.config.name.clone())), + ), + )) { + error!("Failed to update discord: {}", e); + } + // Keep track of when this screen is opened self.start_timestamp = Some(Utc::now()); diff --git a/game/src/scenes/main_menu_screen.rs b/game/src/scenes/main_menu_screen.rs index cc0f68b..13c8295 100644 --- a/game/src/scenes/main_menu_screen.rs +++ b/game/src/scenes/main_menu_screen.rs @@ -2,19 +2,24 @@ use std::ops::{Div, Sub}; use chrono::{DateTime, Utc}; use dirty_fsm::{Action, ActionFlag}; +use discord_sdk::activity::{ActivityBuilder, Assets}; use pkg_version::pkg_version_major; use raylib::prelude::*; -use crate::{GameConfig, context::GameContext, utilities::{ +use crate::{ + context::GameContext, + utilities::{ datastore::{load_texture_from_internal_data, ResourceLoadError}, game_version::get_version_string, math::interpolate_exp, non_ref_raylib::HackedRaylibHandle, render_layer::ScreenSpaceRender, - }}; + }, + GameConfig, +}; use super::{Scenes, ScreenError}; -use tracing::{debug, info, trace}; +use tracing::{debug, error, info, trace}; #[derive(Debug)] pub struct MainMenuScreen {} @@ -32,9 +37,18 @@ impl Action for MainMenuScreen { Ok(()) } - fn on_first_run(&mut self, _context: &GameContext) -> Result<(), ScreenError> { + fn on_first_run(&mut self, context: &GameContext) -> Result<(), ScreenError> { debug!("Running MainMenuScreen for the first time"); + // Update discord + if let Err(e) = context.discord_rpc_send.send(Some( + ActivityBuilder::default().details("main menu").assets( + Assets::default().large("game-logo-small", Some(context.config.name.clone())), + ), + )) { + error!("Failed to update discord: {}", e); + } + Ok(()) } @@ -47,7 +61,11 @@ impl Action for MainMenuScreen { self.render_screen_space(&mut context.renderer.borrow_mut(), &context.config); // TODO: TEMP - if context.renderer.borrow_mut().is_key_pressed(KeyboardKey::KEY_SPACE) { + if context + .renderer + .borrow_mut() + .is_key_pressed(KeyboardKey::KEY_SPACE) + { Ok(ActionFlag::SwitchState(Scenes::InGameScene)) } else { Ok(ActionFlag::Continue) @@ -64,7 +82,7 @@ impl ScreenSpaceRender for MainMenuScreen { fn render_screen_space( &self, raylib: &mut crate::utilities::non_ref_raylib::HackedRaylibHandle, - config: &GameConfig + config: &GameConfig, ) { // Render the background raylib.clear_background(Color::BLACK); diff --git a/game/src/scenes/pause_screen.rs b/game/src/scenes/pause_screen.rs index e960b71..a496c5a 100644 --- a/game/src/scenes/pause_screen.rs +++ b/game/src/scenes/pause_screen.rs @@ -2,19 +2,24 @@ use std::ops::{Div, Sub}; use chrono::{DateTime, Utc}; use dirty_fsm::{Action, ActionFlag}; +use discord_sdk::activity::{ActivityBuilder, Assets}; use pkg_version::pkg_version_major; use raylib::prelude::*; -use crate::{GameConfig, context::GameContext, utilities::{ +use crate::{ + context::GameContext, + utilities::{ datastore::{load_texture_from_internal_data, ResourceLoadError}, game_version::get_version_string, math::interpolate_exp, non_ref_raylib::HackedRaylibHandle, render_layer::ScreenSpaceRender, - }}; + }, + GameConfig, +}; use super::{Scenes, ScreenError}; -use tracing::{debug, info, trace}; +use tracing::{debug, error, info, trace}; #[derive(Debug)] pub struct PauseScreen {} @@ -32,9 +37,18 @@ impl Action for PauseScreen { Ok(()) } - fn on_first_run(&mut self, _context: &GameContext) -> Result<(), ScreenError> { + fn on_first_run(&mut self, context: &GameContext) -> Result<(), ScreenError> { debug!("Running PauseScreen for the first time"); + // Update discord + if let Err(e) = context.discord_rpc_send.send(Some( + ActivityBuilder::default().details("paused").assets( + Assets::default().large("game-logo-small", Some(context.config.name.clone())), + ), + )) { + error!("Failed to update discord: {}", e); + } + Ok(()) } @@ -49,26 +63,35 @@ impl Action for PauseScreen { //Mouse Position let mouse_position: Vector2 = context.renderer.borrow_mut().get_mouse_position(); //Mouse Input - let is_left_click = context.renderer.borrow_mut().is_mouse_button_down(MouseButton::MOUSE_LEFT_BUTTON); - + let is_left_click = context + .renderer + .borrow_mut() + .is_mouse_button_down(MouseButton::MOUSE_LEFT_BUTTON); //"Hitboxes" for the resume and Main menu buttons - if is_left_click && Rectangle::new(322.0,321.0,435.0,80.0).check_collision_point_rec(mouse_position) { + if is_left_click + && Rectangle::new(322.0, 321.0, 435.0, 80.0).check_collision_point_rec(mouse_position) + { return Ok(ActionFlag::SwitchState(Scenes::InGameScene)); } - if is_left_click && Rectangle::new(390.0,464.0,200.0,50.0).check_collision_point_rec(mouse_position) { + if is_left_click + && Rectangle::new(390.0, 464.0, 200.0, 50.0).check_collision_point_rec(mouse_position) + { return Ok(ActionFlag::SwitchState(Scenes::MainMenuScreen)); } - if context.renderer.borrow_mut().is_key_pressed(KeyboardKey::KEY_ESCAPE) { + if context + .renderer + .borrow_mut() + .is_key_pressed(KeyboardKey::KEY_ESCAPE) + { Ok(ActionFlag::SwitchState(Scenes::InGameScene)) } else { Ok(ActionFlag::Continue) } } - fn on_finish(&mut self, _interrupted: bool) -> Result<(), ScreenError> { debug!("Finished PauseScreen"); Ok(()) @@ -76,11 +99,10 @@ impl Action for PauseScreen { } impl ScreenSpaceRender for PauseScreen { - fn render_screen_space( &self, raylib: &mut crate::utilities::non_ref_raylib::HackedRaylibHandle, - config: &GameConfig + config: &GameConfig, ) { let screen_size = raylib.get_screen_size(); @@ -98,85 +120,83 @@ impl ScreenSpaceRender for PauseScreen { (screen_size.x as i32 / 2) - 223, (screen_size.y as i32 / 2) - 40, 120, - Color::RED + Color::RED, ); raylib.draw_text( "Paused", (screen_size.x as i32 / 2) - 217, (screen_size.y as i32 / 2) - 40, 120, - Color::BLUE + Color::BLUE, ); raylib.draw_text( "Paused", (screen_size.x as i32 / 2) - 220, (screen_size.y as i32 / 2) - 40, 120, - Color::WHITE + Color::WHITE, ); raylib.draw_text( "Click To Resume", (screen_size.x as i32 / 2) - 80, (screen_size.y as i32 / 2) + 60, 20, - Color::RED + Color::RED, ); raylib.draw_text( "Click To Resume", (screen_size.x as i32 / 2) - 80, (screen_size.y as i32 / 2) + 60, 20, - Color::BLUE + Color::BLUE, ); raylib.draw_text( "Click To Resume", (screen_size.x as i32 / 2) - 80, (screen_size.y as i32 / 2) + 60, 20, - Color::WHITE + Color::WHITE, ); raylib.draw_text( "Main Menu", (screen_size.x as i32 / 2) - 123, (screen_size.y as i32 / 2) + 100, 50, - Color::RED + Color::RED, ); raylib.draw_text( "Main Menu", (screen_size.x as i32 / 2) - 117, (screen_size.y as i32 / 2) + 100, 50, - Color::BLUE + Color::BLUE, ); raylib.draw_text( "Main Menu", (screen_size.x as i32 / 2) - 120, (screen_size.y as i32 / 2) + 100, 50, - Color::WHITE + Color::WHITE, ); - if Rectangle::new(390.0,464.0,200.0,50.0).check_collision_point_rec(mouse_position) { + if Rectangle::new(390.0, 464.0, 200.0, 50.0).check_collision_point_rec(mouse_position) { raylib.draw_text( "Main Menu", (screen_size.x as i32 / 2) - 120, (screen_size.y as i32 / 2) + 100, 50, - Color::YELLOW + Color::YELLOW, ); } - if Rectangle::new(322.0,321.0,435.0,80.0).check_collision_point_rec(mouse_position) { + if Rectangle::new(322.0, 321.0, 435.0, 80.0).check_collision_point_rec(mouse_position) { raylib.draw_text( "Paused", (screen_size.x as i32 / 2) - 220, (screen_size.y as i32 / 2) - 40, 120, - Color::DARKBLUE + Color::DARKBLUE, ); } - - } }