From d5d9e031d52fcdcdb91cc8d1273a742c623d0e54 Mon Sep 17 00:00:00 2001 From: FantasyPvP <80643031+FantasyPvP@users.noreply.github.com> Date: Fri, 22 Mar 2024 00:12:15 +0000 Subject: [PATCH] - added a new API for switching between terminal and application mode - removed unneeded imports to reduce the dumb amount of warnings from the compiler - added a bounds check in frame.rs to avoid a panic when a frame tries to render a character out of bounds, instead returning an error --- src/lib.rs | 4 - src/main.rs | 6 +- src/system/kernel/interrupts.rs | 6 +- src/system/kernel/render.rs | 32 +-- src/system/kernel/serial.rs | 1 - src/system/kernel/sysinit.rs | 1 - src/system/kernel/tasks/keyboard.rs | 2 +- src/system/std/frame.rs | 10 +- src/system/std/io.rs | 30 ++- src/system/std/random.rs | 3 +- src/system/std/time.rs | 3 - src/user/bin/asteroids.rs | 8 +- src/user/bin/calc/calc.rs | 3 - src/user/bin/calc/functions.rs | 1 - src/user/bin/crystalfetch.rs | 11 +- src/user/bin/crystalrpg/entity.rs | 292 ++++++++++++++-------------- src/user/bin/gameoflife.rs | 7 +- src/user/bin/gigachad_detector.rs | 2 - src/user/bin/grapher.rs | 14 +- src/user/bin/pong.rs | 68 +++++-- src/user/bin/rickroll.rs | 2 +- src/user/bin/shell.rs | 21 +- src/user/bin/snake.rs | 22 +-- src/user/bin/tasks.rs | 9 +- src/user/bin/tetris.rs | 226 +++++++++++---------- src/user/lib/libgui/cg_core.rs | 7 +- src/user/lib/libgui/cg_inputs.rs | 17 +- src/user/lib/libgui/cg_utils.rs | 22 ++- src/user/lib/libgui/cg_widgets.rs | 45 ++--- 29 files changed, 439 insertions(+), 436 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index c79743e..ccd2599 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,12 +7,9 @@ #![feature(alloc_error_handler)] #![feature(async_fn_in_trait)] #![feature(async_closure)] -#![feature(global_asm)] #![feature(inherent_associated_types)] -use alloc::string::String; -use alloc::vec; use bootloader::{entry_point, BootInfo}; use core::panic::PanicInfo; extern crate alloc; @@ -23,7 +20,6 @@ pub mod user; pub use system::std as std; pub use user::bin::*; use crate::calc::Calculator; -use crate::std::application::Application; #[derive(Debug, Clone, Copy, PartialEq, Eq)] diff --git a/src/main.rs b/src/main.rs index 4dfea64..06b37a0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,7 +7,7 @@ use bootloader::{entry_point, BootInfo}; use core::panic::PanicInfo; use CrystalOS::std::tasks::{Executor, Task}; -use CrystalOS::{print, print_log, printerr, println, println_log, std::syscall}; +use CrystalOS::{printerr, std::syscall}; extern crate alloc; use CrystalOS::user::bin::shell; @@ -40,9 +40,5 @@ fn main(boot_info: &'static BootInfo) -> ! { loop { executor.try_run(); } - - - - loop {} } diff --git a/src/system/kernel/interrupts.rs b/src/system/kernel/interrupts.rs index faa77ae..802ba2d 100644 --- a/src/system/kernel/interrupts.rs +++ b/src/system/kernel/interrupts.rs @@ -1,6 +1,6 @@ use x86_64::structures::idt::{InterruptDescriptorTable, InterruptStackFrame}; -use crate::{print, println}; +use crate::println; use super::gdt; use lazy_static::lazy_static; use spin; @@ -28,7 +28,7 @@ extern "x86-interrupt" fn timer_interrupt_handler(_stack_frame: InterruptStackFr extern "x86-interrupt" fn keyboard_interrupt_handler(_stack_frame: InterruptStackFrame) { - use pc_keyboard::{layouts, DecodedKey, HandleControl, Keyboard, ScancodeSet1}; + use pc_keyboard::{layouts, HandleControl, Keyboard, ScancodeSet1}; use spin::Mutex; use x86_64::instructions::port::Port; @@ -38,7 +38,7 @@ extern "x86-interrupt" fn keyboard_interrupt_handler(_stack_frame: InterruptStac }; } - let mut keyboard = KEYBOARD.lock(); + let keyboard = KEYBOARD.lock(); let mut port = Port::new(0x60); let scancode: u8 = unsafe { port.read() }; diff --git a/src/system/kernel/render.rs b/src/system/kernel/render.rs index 56c0e58..09a63de 100644 --- a/src/system/kernel/render.rs +++ b/src/system/kernel/render.rs @@ -3,12 +3,8 @@ use lazy_static::lazy_static; use spin::Mutex; use volatile::Volatile; -use alloc::borrow::ToOwned; use alloc::vec; use alloc::vec::Vec; -use crate::system::kernel::render::RenderError::InvalidRenderMode; -use crate::serial_println; -use crate::std::io::Screen; #[allow(dead_code)] #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -137,24 +133,14 @@ impl Renderer { self.internal_render(); } - pub fn application_mode(&mut self) -> Result<(), RenderError> { - if self.application_mode { - return Err(InvalidRenderMode); - } else { - self.application_mode = true; - self.internal_render(); - Ok(()) - } + pub fn application_mode(&mut self) { + self.application_mode = true; + self.internal_render(); } - pub fn terminal_mode(&mut self) -> Result<(), RenderError> { - if !self.application_mode { - return Err(InvalidRenderMode); - } else { - self.application_mode = false; - self.internal_render(); - Ok(()) - } + pub fn terminal_mode(&mut self) { + self.application_mode = false; + self.internal_render(); } pub fn mode_is_app(&self) -> bool { @@ -210,10 +196,10 @@ impl Renderer { pub fn cursor_position(&mut self, x: u8, y: u8) -> Result<(), RenderError> { // check that x and y are within bounds - if x >= 80 || x < 0 || y >= 25 || y < 0 { + if x >= 80 || y >= 25 { return Err(RenderError::OutOfBounds( - x >= 80 || x < 0, - y >= 25 || y < 0 + x >= 80, + y >= 25 )) } self.internal_set_cursor_position(x, y); diff --git a/src/system/kernel/serial.rs b/src/system/kernel/serial.rs index 546efc3..dee31af 100644 --- a/src/system/kernel/serial.rs +++ b/src/system/kernel/serial.rs @@ -25,7 +25,6 @@ pub fn _serial_print(args: core::fmt::Arguments) { } pub fn serial_reply(chr: char) -> char { - use core::fmt::Write; use x86_64::instructions::interrupts; let mut chr_return: char = 'X'; diff --git a/src/system/kernel/sysinit.rs b/src/system/kernel/sysinit.rs index 68e2b07..cfbd3c1 100644 --- a/src/system/kernel/sysinit.rs +++ b/src/system/kernel/sysinit.rs @@ -1,4 +1,3 @@ -use crate::println; pub fn init() -> Result<(), ()> { Ok(()) } \ No newline at end of file diff --git a/src/system/kernel/tasks/keyboard.rs b/src/system/kernel/tasks/keyboard.rs index e124e41..88e0cc9 100644 --- a/src/system/kernel/tasks/keyboard.rs +++ b/src/system/kernel/tasks/keyboard.rs @@ -5,7 +5,7 @@ use x86_64::instructions::interrupts; use conquer_once::spin::OnceCell; use crossbeam_queue::ArrayQueue; -use crate::{println, serial_println}; +use crate::println; use core::{pin::Pin, task::{Poll, Context}}; use futures_util::stream::Stream; diff --git a/src/system/std/frame.rs b/src/system/std/frame.rs index 56e7ce7..0325bea 100644 --- a/src/system/std/frame.rs +++ b/src/system/std/frame.rs @@ -2,7 +2,7 @@ use alloc::string::String; use alloc::vec; use alloc::vec::Vec; use crate::system::kernel::render::{RENDERER, ScreenChar}; -use crate::std::io::{Color, Screen}; +use crate::std::io::Color; /// TODO: get a working implementation for CLI apps /// elements can be created using their from_str() method @@ -135,8 +135,12 @@ impl Frame { pub fn dimensions(&self) -> Dimensions { self.dimensions } - pub fn write(&mut self, position: Position, char: ColouredChar) { - self.frame[position.y][position.x] = char + pub fn write(&mut self, position: Position, char: ColouredChar) -> Result<(), RenderError> { + if position.x >= self.dimensions.x || position.y >= self.dimensions.y { + return Err(RenderError::OutOfBounds(true, true)); + } + self.frame[position.y][position.x] = char; + Ok(()) } pub fn place_child_element(&mut self, other: &Frame) { for (i, row) in other.frame.iter().enumerate() { diff --git a/src/system/std/io.rs b/src/system/std/io.rs index 9877844..692d0da 100644 --- a/src/system/std/io.rs +++ b/src/system/std/io.rs @@ -48,13 +48,15 @@ pub enum Screen { Terminal, Application, } + +/// DEPRECATED - STOP USING THIS SOON impl Screen { /// mode can be set for the kernel using this method pub fn set_mode(&self) -> Result<(), RenderError> { - match self { + Ok(match self { Screen::Terminal => RENDERER.lock().terminal_mode(), Screen::Application => RENDERER.lock().application_mode(), - } + }) } /// returns the current display mode @@ -68,9 +70,9 @@ impl Screen { /// switches between modes pub fn switch(&self) { if RENDERER.lock().mode_is_app() == true { - RENDERER.lock().terminal_mode().unwrap(); + RENDERER.lock().terminal_mode(); } else { - RENDERER.lock().application_mode().unwrap(); + RENDERER.lock().application_mode(); } } pub fn clear() { @@ -78,6 +80,26 @@ impl Screen { } } +/// An interface that tells the kernel what rendering mode to use +/// Creating an instance of this struct will enable application rendering mode +/// Dropping the instance will return the display to focus on the terminal. +pub struct Display; + +impl Display { + pub fn borrow() -> Display { + RENDERER.lock().application_mode(); + Display + } +} + +impl Drop for Display { + fn drop(&mut self) { + RENDERER.lock().terminal_mode(); + } +} + + + #[macro_export] macro_rules! println_log { diff --git a/src/system/std/random.rs b/src/system/std/random.rs index 393c970..1ada4f1 100644 --- a/src/system/std/random.rs +++ b/src/system/std/random.rs @@ -1,6 +1,5 @@ use alloc::{string::{String, ToString}, vec::Vec}; -use core::ops::Index; -use rand::{Rng, SeedableRng, rngs::SmallRng, RngCore}; +use rand::{SeedableRng, rngs::SmallRng, RngCore}; use spin::Mutex; use lazy_static::lazy_static; use cmos_rtc::{ReadRTC, Time}; diff --git a/src/system/std/time.rs b/src/system/std/time.rs index 86a9aad..4bbb2c6 100644 --- a/src/system/std/time.rs +++ b/src/system/std/time.rs @@ -1,6 +1,3 @@ -use core::time::Duration; -use embedded_time::{Clock, Timer}; -use cmos_rtc::{ReadRTC, Time}; use crate::println; use super::super::kernel::interrupts::GLOBALTIMER; use x86_64::instructions::interrupts; diff --git a/src/user/bin/asteroids.rs b/src/user/bin/asteroids.rs index 2039179..e863c06 100644 --- a/src/user/bin/asteroids.rs +++ b/src/user/bin/asteroids.rs @@ -292,13 +292,7 @@ impl GameTimer { self.time_since_spawn += 1; self.time_since_move += 1; } - - pub fn get_spawn_time(&self) -> u32 { - self.time_since_spawn - } - pub fn reset_spawn_time(&mut self) { - self.time_since_spawn = 0 - } + pub fn get_move_time(&self) -> u32 { self.time_since_move } diff --git a/src/user/bin/calc/calc.rs b/src/user/bin/calc/calc.rs index d776f79..f424649 100755 --- a/src/user/bin/calc/calc.rs +++ b/src/user/bin/calc/calc.rs @@ -5,15 +5,12 @@ use alloc::borrow::ToOwned; use crate::{println, print, mknode, std}; use async_trait::async_trait; -use lazy_static::lazy_static; use crate::std::application::{ Application, Error as ShellError }; - - struct Parser { tokens: Vec, idx: i32, diff --git a/src/user/bin/calc/functions.rs b/src/user/bin/calc/functions.rs index 5b8f879..98cdbd4 100644 --- a/src/user/bin/calc/functions.rs +++ b/src/user/bin/calc/functions.rs @@ -1,6 +1,5 @@ use alloc::format; use alloc::string::String; -use crate::println; const PI: f64 = 3.14159265358979323846264338327950288419716939937510; diff --git a/src/user/bin/crystalfetch.rs b/src/user/bin/crystalfetch.rs index 3df08b4..72ab279 100644 --- a/src/user/bin/crystalfetch.rs +++ b/src/user/bin/crystalfetch.rs @@ -1,11 +1,12 @@ use async_trait::async_trait; use alloc::{boxed::Box, format, string::String, vec::Vec}; -use log::info; -use crate::{std::os::OS, std::io::{Color, write, Screen}, println, std::application::{ - Application, - Error, -}, std}; +use crate::std::{ + os::OS, + io::{Color, write, Screen}, + application::{Application, Error}, +}; +use crate::println; const CRYSTAL_LOGO: &str = "\n $$$$$$\\ $$\\ $$\\ $$$$$$\\ $$$$$$\\ diff --git a/src/user/bin/crystalrpg/entity.rs b/src/user/bin/crystalrpg/entity.rs index cc90662..bf0a866 100644 --- a/src/user/bin/crystalrpg/entity.rs +++ b/src/user/bin/crystalrpg/entity.rs @@ -1,146 +1,146 @@ -use alloc::{boxed::Box, string::String, vec::Vec}; -use core::cmp::min; - -struct Player { - username: String, - stats: EntityStats, - - exp: u32, - level: u32, - skill_points: u32, - skills: Vec>, - - helmet: Option, - chestplate: Option, - boots: Option, - - inventory: Vec, -} - -struct EntityStats { - health: i32, - max_health: i32, - mana: i32, - max_mana: i32, - defence: i32, -} - -impl Player { - fn new(username: String) -> Self { - Self { - username, - stats: EntityStats { - health: 100, - max_health: 100, - mana: 100, - max_mana: 100, - defence: 0, - }, - exp: 0, - level: 0, - skill_points: 0, - skills: Vec::new(), - - helmet: None, - chestplate: None, - boots: None, - inventory: Vec::new(), - } - } - - fn heal(&mut self, amount: i32) { - let max_health = self.max_health(); - - self.stats.health = min(self.stats.health + amount, max_health); - } - - fn damage(&mut self, amount: i32) { - let hp = self.health_points(); - } - - fn inventory_contents_mut(&mut self) -> &mut Vec { - &mut self.inventory - } - - fn max_health(&self) -> i32 { - let mut max_health = self.stats.max_health; - - if let Some(helmet) = &self.helmet { - max_health += helmet.stats.health_bonus; - } - if let Some(chestplate) = &self.chestplate { - max_health += chestplate.stats.health_bonus; - } - if let Some(boots) = &self.boots { - max_health += boots.stats.health_bonus; - } - - max_health - } - - fn health_points(&self) -> i32 { - let mut hp = self.stats.health; - if let Some(helmet) = &self.helmet { - hp += helmet.stats.health_bonus; - } - if let Some(chestplate) = &self.chestplate { - hp += chestplate.stats.health_bonus; - } - if let Some(boots) = &self.boots { - hp += boots.stats.health_bonus; - } - hp - } -} - -enum Item { - Helmet(Helmet), - Chestplate(Chestplate), - Boots(Boots), - Sword, - Potion, -} - -struct Helmet { - name: &'static str, - lore: &'static str, - stats: ArmourStats, -} - -struct Chestplate { - name: &'static str, - lore: &'static str, - stats: ArmourStats, -} - -struct Boots { - name: &'static str, - lore: &'static str, - stats: ArmourStats, -} - -struct ArmourStats { - durability: i32, - max_durability: i32, - defence: i32, - health_bonus: i32, - mana_bonus: i32, -} - -struct PlayerStats {} - -trait Skill { - fn skill_name(&self) -> &str; // returns the name of the skill - fn skill_level(&self) -> &str; // returns the level of that skill - fn description(&self) -> &str; // returns the status of that skill - fn skillpoint_level_req(&self) -> i32; - fn increase_level(&mut self, level: &u32, skill_points: &mut u32) -> Result<(), GameError>; - fn decrease_level(&mut self, skill_points: &mut u32) -> Result<(), GameError>; - fn modify_stats(&self, stats: EntityStats) -> EntityStats; -} - -enum GameError { - SkillLevelMaxed, - InsufficientSkillPoints, - InsufficientLevel, -} +// use alloc::{boxed::Box, string::String, vec::Vec}; +// use core::cmp::min; +// +// struct Player { +// username: String, +// stats: EntityStats, +// +// exp: u32, +// level: u32, +// skill_points: u32, +// skills: Vec>, +// +// helmet: Option, +// chestplate: Option, +// boots: Option, +// +// inventory: Vec, +// } +// +// struct EntityStats { +// health: i32, +// max_health: i32, +// mana: i32, +// max_mana: i32, +// defence: i32, +// } +// +// impl Player { +// fn new(username: String) -> Self { +// Self { +// username, +// stats: EntityStats { +// health: 100, +// max_health: 100, +// mana: 100, +// max_mana: 100, +// defence: 0, +// }, +// exp: 0, +// level: 0, +// skill_points: 0, +// skills: Vec::new(), +// +// helmet: None, +// chestplate: None, +// boots: None, +// inventory: Vec::new(), +// } +// } +// +// fn heal(&mut self, amount: i32) { +// let max_health = self.max_health(); +// +// self.stats.health = min(self.stats.health + amount, max_health); +// } +// +// fn damage(&mut self, amount: i32) { +// let hp = self.health_points(); +// } +// +// fn inventory_contents_mut(&mut self) -> &mut Vec { +// &mut self.inventory +// } +// +// fn max_health(&self) -> i32 { +// let mut max_health = self.stats.max_health; +// +// if let Some(helmet) = &self.helmet { +// max_health += helmet.stats.health_bonus; +// } +// if let Some(chestplate) = &self.chestplate { +// max_health += chestplate.stats.health_bonus; +// } +// if let Some(boots) = &self.boots { +// max_health += boots.stats.health_bonus; +// } +// +// max_health +// } +// +// fn health_points(&self) -> i32 { +// let mut hp = self.stats.health; +// if let Some(helmet) = &self.helmet { +// hp += helmet.stats.health_bonus; +// } +// if let Some(chestplate) = &self.chestplate { +// hp += chestplate.stats.health_bonus; +// } +// if let Some(boots) = &self.boots { +// hp += boots.stats.health_bonus; +// } +// hp +// } +// } +// +// enum Item { +// Helmet(Helmet), +// Chestplate(Chestplate), +// Boots(Boots), +// Sword, +// Potion, +// } +// +// struct Helmet { +// name: &'static str, +// lore: &'static str, +// stats: ArmourStats, +// } +// +// struct Chestplate { +// name: &'static str, +// lore: &'static str, +// stats: ArmourStats, +// } +// +// struct Boots { +// name: &'static str, +// lore: &'static str, +// stats: ArmourStats, +// } +// +// struct ArmourStats { +// durability: i32, +// max_durability: i32, +// defence: i32, +// health_bonus: i32, +// mana_bonus: i32, +// } +// +// struct PlayerStats {} +// +// trait Skill { +// fn skill_name(&self) -> &str; // returns the name of the skill +// fn skill_level(&self) -> &str; // returns the level of that skill +// fn description(&self) -> &str; // returns the status of that skill +// fn skillpoint_level_req(&self) -> i32; +// fn increase_level(&mut self, level: &u32, skill_points: &mut u32) -> Result<(), GameError>; +// fn decrease_level(&mut self, skill_points: &mut u32) -> Result<(), GameError>; +// fn modify_stats(&self, stats: EntityStats) -> EntityStats; +// } +// +// enum GameError { +// SkillLevelMaxed, +// InsufficientSkillPoints, +// InsufficientLevel, +// } diff --git a/src/user/bin/gameoflife.rs b/src/user/bin/gameoflife.rs index 67118b6..dee0b73 100644 --- a/src/user/bin/gameoflife.rs +++ b/src/user/bin/gameoflife.rs @@ -1,4 +1,3 @@ -use alloc::borrow::ToOwned; use alloc::string::String; use alloc::vec; use alloc::vec::Vec; @@ -6,9 +5,8 @@ use alloc::boxed::Box; use crate::std::application::{Application, Error}; use async_trait::async_trait; use crate::std::frame::{ColouredChar, Frame, Position, Dimensions, RenderError}; -use crate::std::io::{KeyStroke, Screen, Stdin, Color, ColorCode}; +use crate::std::io::{KeyStroke, Stdin, Color, ColorCode, Display}; use crate::std::time::wait; -use crate::user::bin::snake::Game; pub struct GameOfLife { frame: Frame @@ -25,7 +23,7 @@ impl Application for GameOfLife { } async fn run(&mut self, args: Vec) -> Result<(), Error> { // setup: - Screen::Application.set_mode(); + let d = Display::borrow(); let xoffset = 38; let yoffset = 5; @@ -56,7 +54,6 @@ impl Application for GameOfLife { self.mainloop()?; - Screen::Terminal.set_mode(); Ok(()) } } diff --git a/src/user/bin/gigachad_detector.rs b/src/user/bin/gigachad_detector.rs index f62db88..fcca659 100644 --- a/src/user/bin/gigachad_detector.rs +++ b/src/user/bin/gigachad_detector.rs @@ -2,8 +2,6 @@ use async_trait::async_trait; use alloc::{boxed::Box, string::String, vec::Vec}; use crate::{ - std::os::OS, - std::io::{Color, write}, println, std::application::{ Application, diff --git a/src/user/bin/grapher.rs b/src/user/bin/grapher.rs index 2e9d2cd..08ee7cc 100644 --- a/src/user/bin/grapher.rs +++ b/src/user/bin/grapher.rs @@ -2,17 +2,11 @@ use alloc::string::{String, ToString}; use alloc::{format, vec}; use alloc::vec::Vec; use alloc::boxed::Box; -use alloc::fmt::format; -use alloc::sync::Arc; use core::any::Any; use async_trait::async_trait; -use spin::Mutex; -use crate::{println, serial_println}; -use crate::std::io::{ColorCode}; -use crate::shell::command_handler; use crate::std::application::{Application, Error}; -use crate::std::frame::{self, Frame, Position, Dimensions, ColouredChar, RenderError}; -use crate::std::io::{Color, KeyStroke, Screen, Stdin}; +use crate::std::frame::{Frame, Position, Dimensions, ColouredChar, RenderError}; +use crate::std::io::{KeyStroke, Screen, Stdin}; use crate::user::lib::libgui::{ cg_core::{CgComponent}, @@ -100,7 +94,7 @@ impl Application for Grapher { while let c = Stdin::keystroke().await { - let mut entry_widget = container.elements.get("entry_box").unwrap(); + let entry_widget = container.elements.get("entry_box").unwrap(); let mut entry = entry_widget.fetch::().unwrap(); rerender = true; @@ -196,7 +190,7 @@ impl Grapher { let offset_x = point.x + OFFSET_X; let offset_y = point.y + OFFSET_Y; - self.frame.write(Position::new(offset_x as usize, 21-offset_y as usize), ColouredChar::new('*')); + self.frame.write(Position::new(offset_x as usize, 21-offset_y as usize), ColouredChar::new('*')).expect("Failed to write to frame - this function is broken."); } fn reset_frame(&mut self) { diff --git a/src/user/bin/pong.rs b/src/user/bin/pong.rs index 152f42f..916e473 100644 --- a/src/user/bin/pong.rs +++ b/src/user/bin/pong.rs @@ -1,12 +1,15 @@ use alloc::boxed::Box; use alloc::string::String; use alloc::vec::Vec; +use core::any::Any; use async_trait::async_trait; -use core::fmt::Write; use crate::std::application::{Application, Error}; use crate::std; +use crate::std::frame::{ColouredChar, Dimensions, Frame, Position, RenderError}; +use crate::std::io::{Display, KeyStroke, Stdin}; +use crate::user::lib::libgui::cg_core::CgComponent; -struct Game { +pub(crate) struct Game { ball: Ball, player1: Player, player2: Player, @@ -18,40 +21,81 @@ impl Application for Game { Game { ball: Ball::new(), player1: Player::new(1), - player2: Player::new(2), + player2: Player::new(78), } } async fn run(&mut self, _: Vec) -> Result<(), Error> { + let d = Display::borrow(); + loop { - self.ball.update(&self.player1, &self.player2); + std::time::wait(0.01); + + if let Some(key) = Stdin::try_keystroke() { + match key { + KeyStroke::Char('w') => { + self.player1.pos.y -= 1; + }, + KeyStroke::Char('s') => { + self.player1.pos.y += 1; + }, + KeyStroke::Up => { + self.player2.pos.y -= 1; + }, + KeyStroke::Down => { + self.player2.pos.y += 1; + } + _ => {} + } + } + if let Ok(frame) = self.render() { + frame.write_to_screen().unwrap(); + } + // self.ball.update(&self.player1, &self.player2); } Ok(()) } } +impl CgComponent for Game { + fn render(&self) -> Result { + let mut frame = Frame::new(Dimensions::new(0, 0), Dimensions::new(80, 25))?; + + frame.write(self.player1.pos, ColouredChar::new('@')).unwrap(); + frame.write(self.player2.pos, ColouredChar::new('@')).unwrap(); + frame.write(self.ball.pos, ColouredChar::new('@')).unwrap(); + + Ok(frame) + } + + fn as_any(&self) -> &dyn Any { + self + } +} + struct Player { - x: i32, - y: i32, + pos: Position, score: i32, } impl Player { - fn new(y: i32) -> Self { - Player { x: 0, y, score: 0 } + fn new(x: usize) -> Self { + Player { pos: Position::new(x, 12), score: 0 } } } struct Ball { - x: i32, - y: i32, + pos: Position, + vx: i32, + vy: i32, } impl Ball { fn new() -> Self { - Ball { x: 0, y: 0 } + Ball { pos: Position::new(40, 12), vx: 1, vy: 0 } } + fn update(&mut self, player1: &Player, player2: &Player) { - self.x += 1; + self.pos.x = (self.pos.x as i32 + self.vx) as usize; } } diff --git a/src/user/bin/rickroll.rs b/src/user/bin/rickroll.rs index 05c14aa..63d564e 100644 --- a/src/user/bin/rickroll.rs +++ b/src/user/bin/rickroll.rs @@ -43,7 +43,7 @@ const RICKROLL2: &str = " 1a###w#*mObo*oatXkW*oo#*###p `--' `---' `----' `-----' | |-' `--'"; -use crate::{println, serial_println}; +use crate::println; use alloc::{string::String, boxed::Box, vec::Vec}; diff --git a/src/user/bin/shell.rs b/src/user/bin/shell.rs index 8c6760e..faeaef2 100644 --- a/src/user/bin/shell.rs +++ b/src/user/bin/shell.rs @@ -1,33 +1,26 @@ -use async_trait::async_trait; use lazy_static::lazy_static; use spin::Mutex; use alloc::{boxed::Box, format, string::{String, ToString}, vec, vec::Vec}; -use futures_util::TryFutureExt; -use vga::writers::{GraphicsWriter, PrimitiveDrawing}; +use vga::writers::{PrimitiveDrawing}; use crate::{ - print, printerr, println, - serial_println, }; use crate::std::{ application::{Application, Error, Exit}, time::{timer, wait}, - random::Random, io::{ Color, write, Screen, Stdin, Serial, KeyStroke }, - frame::{Dimensions, Position, ColorCode}, }; use crate::user::{ lib::libgui::{ - cg_core::{CgComponent, CgTextEdit, CgKeyboardCapture, CgTextInput, Widget}, - cg_widgets::{CgTextBox, CgContainer, CgLabel, CgStatusBar, CgDialog}, - cg_inputs::CgLineEdit, + cg_core::{CgComponent, CgKeyboardCapture}, + cg_widgets::CgDialog, }, bin::*, }; @@ -140,6 +133,9 @@ async fn exec() -> Result<(), Error> { let mut asteroid_game = asteroids::Game::new(); asteroid_game.run(args).await?; } + "pong" => { + pong::Game::new().run(args).await?; + } "serial" => { let c = Serial::reply_char('e'); println!("{}", c); @@ -149,8 +145,8 @@ async fn exec() -> Result<(), Error> { game.run(Vec::new()).await?; } "tetris" => { - let mut game = tetris::TetrisEngine::new(); - game.run(Vec::new()).await?; + // let mut game = tetris::TetrisEngine::new(); + // game.run(Vec::new()).await?; } "gigachad?" => { @@ -192,7 +188,6 @@ async fn exec() -> Result<(), Error> { }; } "time" => { - use crate::std::time::timer; timer(); } "test_features" => { diff --git a/src/user/bin/snake.rs b/src/user/bin/snake.rs index 5bb3345..189b98b 100644 --- a/src/user/bin/snake.rs +++ b/src/user/bin/snake.rs @@ -1,19 +1,13 @@ -use alloc::string::{String, ToString}; +use alloc::string::String; use alloc::{format, vec, vec::Vec, boxed::Box}; -use alloc::borrow::ToOwned; -use core::arch::x86_64::_mm_test_all_ones; -use core::cell::RefCell; use async_trait::async_trait; -use crate::std::io::{Color, KeyStroke, Screen, Stdin}; +use crate::std::io::{Color, Display, KeyStroke, Stdin}; use crate::std::time; -use crossbeam_queue::SegQueue; -use lazy_static::lazy_static; -use crate::{println, serial_println}; use crate::std::application::{Application, Error}; use crate::std::frame::{ColouredChar, Dimensions, Frame, RenderError, ColorCode}; use crate::std::random::Random; use crate::system::std::frame; -use super::super::lib::coords::{Line, Position, Direction}; +use super::super::lib::coords::{Position, Direction}; #[derive(PartialEq)] enum Gamemode { @@ -53,10 +47,10 @@ impl Application for Game { async fn run(&mut self, args: Vec) -> Result<(), Error> { - let mut settings = [0, 0, 0]; // ai_count, snake_len, poi_count + let settings = [0, 0, 0]; // ai_count, snake_len, poi_count if args.len() == 0 { - self.gamemode == Gamemode::SinglePlayer; + self.gamemode = Gamemode::SinglePlayer; } else { match args[0].as_str() { "easy" => { @@ -81,13 +75,11 @@ impl Application for Game { self.prepare(); // switch OS to application mode - Screen::Application.set_mode(); + let d = Display::borrow(); // render the initial state of the screen. self.render().map_err(|_| Error::ApplicationError(String::from("failed to render game screen")))?; // run the game self.gameloop().await?; - // return to the terminal - Screen::Terminal.set_mode(); Ok(()) } } @@ -356,8 +348,6 @@ impl PathFinder { // serial_println!("{:?} {:?} {:?} {:?}", nearest_poi, rel_pos, head, optimal); return optimal; } - - Direction::None } fn optimal_move(head: &Position, rel_pos: &Position, moves: &Vec) -> Direction { diff --git a/src/user/bin/tasks.rs b/src/user/bin/tasks.rs index db3c6df..3136e60 100644 --- a/src/user/bin/tasks.rs +++ b/src/user/bin/tasks.rs @@ -3,12 +3,11 @@ use crate::std::application::{ Application, Error }; -use crate::{print, println}; +use crate::println; use lazy_static::lazy_static; use spin::Mutex; use async_trait::async_trait; use alloc::{ - string::ToString, borrow::ToOwned, }; @@ -101,13 +100,13 @@ println!("\n-------------------------------------"); impl Tasks { fn add_task(&mut self, content: String) { - TASKS.lock().add(content); + TASKS.lock().add(content).unwrap(); } fn remove_task(&self, idx: usize) { - TASKS.lock().remove(idx); + TASKS.lock().remove(idx).unwrap(); } fn select_task(&self, idx: i32) { - TASKS.lock().select(idx); + TASKS.lock().select(idx).unwrap(); } } diff --git a/src/user/bin/tetris.rs b/src/user/bin/tetris.rs index 4551b2b..c7446f2 100644 --- a/src/user/bin/tetris.rs +++ b/src/user/bin/tetris.rs @@ -1,117 +1,115 @@ -use async_trait::async_trait; -use alloc::boxed::Box; -use alloc::string::String; -use alloc::vec; -use alloc::vec::Vec; -use crate::std::frame::{ColouredChar}; -use crate::{serial_print, serial_println}; -use crate::std::application::{Application, Error}; -use crate::std::io::Screen; -use crate::user::lib::coords::{Direction, Position, PositionReal}; - - -pub(crate) struct TetrisEngine { - score: u32, - next: TetrisPiece, - completed_frame: [[ColouredChar; 80]; 25], // this frame does not contain falling blocks, only static ones - -} - -#[async_trait] -impl Application for TetrisEngine { - fn new() -> Self { - Self { - score: 0, - next: TetrisPiece::new(PieceType::OPiece), - completed_frame: [[ColouredChar::null(); 80]; 25], - } - } - async fn run(&mut self, args: Vec) -> Result<(), Error> { - // setup: - Screen::Application.set_mode(); - - let piece_type = PieceType::OPiece; - let mut piece = TetrisPiece::new(piece_type); - - serial_println!("{:?}", piece.get_positions()); - piece.rotate_right(); - serial_println!("{:?}", piece.get_positions()); - - - Screen::Terminal.set_mode(); - Ok(()) - } -} - - - - - - - - - - - -enum PieceType { - OPiece, - IPiece, - JPiece, - LPiece, - SPiece, - ZPiece, -} - -struct TetrisPiece { - type_: PieceType, - pos: Position, - rotation: Direction, -} - -impl TetrisPiece { - fn new(type_: PieceType) -> Self { - Self { - type_, - pos: Position { x: 40, y: 30 }, - rotation: Direction::Degrees0, - } - } - fn rotate_right(&mut self) { - self.rotation = match self.rotation { - Direction::Degrees90 => Direction::Degrees180, - Direction::Degrees180 => Direction::Degrees270, - Direction::Degrees270 => Direction::Degrees0, - Direction::Degrees0 => Direction::Degrees90, - Direction::None => panic!("direction should never be none in this application"), - }; - } - - /// function that maps the coordinates of the object. - fn get_positions(&self) -> Vec { - match self.type_ { - PieceType::OPiece => { - let positions = vec![ - PositionReal { x: -0.5, y: -0.5 }, - PositionReal { x: 0.5, y: -0.5 }, - PositionReal { x: -0.5, y: 0.5 }, - PositionReal { x: 0.5, y: 0.5 }, - ]; - positions.into_iter().map(|p| - ( p.rotate(self.rotation.clone()) + self.pos.clone().real() + PositionReal { x: -0.5, y: 0.5 } ).integer() - ).collect::>() - } - _ => unimplemented!("E"), - } - } -} - - - - - - - - +// use async_trait::async_trait; +// use alloc::boxed::Box; +// use alloc::string::String; +// use alloc::vec; +// use alloc::vec::Vec; +// use crate::std::frame::{ColouredChar}; +// use crate::{serial_print, serial_println}; +// use crate::std::application::{Application, Error}; +// use crate::std::io::{Display, Screen}; +// use crate::user::lib::coords::{Direction, Position, PositionReal}; +// +// +// pub(crate) struct TetrisEngine { +// score: u32, +// next: TetrisPiece, +// completed_frame: [[ColouredChar; 80]; 25], // this frame does not contain falling blocks, only static ones +// +// } +// +// #[async_trait] +// impl Application for TetrisEngine { +// fn new() -> Self { +// Self { +// score: 0, +// next: TetrisPiece::new(PieceType::OPiece), +// completed_frame: [[ColouredChar::null(); 80]; 25], +// } +// } +// async fn run(&mut self, args: Vec) -> Result<(), Error> { +// // setup: +// let d = Display::borrow(); +// +// let piece_type = PieceType::OPiece; +// let mut piece = TetrisPiece::new(piece_type); +// +// serial_println!("{:?}", piece.get_positions()); +// piece.rotate_right(); +// serial_println!("{:?}", piece.get_positions()); +// +// Ok(()) +// } +// } +// +// +// +// +// +// +// +// +// +// +// +// enum PieceType { +// OPiece, +// IPiece, +// JPiece, +// LPiece, +// SPiece, +// ZPiece, +// } +// +// struct TetrisPiece { +// type_: PieceType, +// pos: Position, +// rotation: Direction, +// } +// +// impl TetrisPiece { +// fn new(type_: PieceType) -> Self { +// Self { +// type_, +// pos: Position { x: 40, y: 30 }, +// rotation: Direction::Degrees0, +// } +// } +// fn rotate_right(&mut self) { +// self.rotation = match self.rotation { +// Direction::Degrees90 => Direction::Degrees180, +// Direction::Degrees180 => Direction::Degrees270, +// Direction::Degrees270 => Direction::Degrees0, +// Direction::Degrees0 => Direction::Degrees90, +// Direction::None => panic!("direction should never be none in this application"), +// }; +// } +// +// /// function that maps the coordinates of the object. +// fn get_positions(&self) -> Vec { +// match self.type_ { +// PieceType::OPiece => { +// let positions = vec![ +// PositionReal { x: -0.5, y: -0.5 }, +// PositionReal { x: 0.5, y: -0.5 }, +// PositionReal { x: -0.5, y: 0.5 }, +// PositionReal { x: 0.5, y: 0.5 }, +// ]; +// positions.into_iter().map(|p| +// ( p.rotate(self.rotation.clone()) + self.pos.clone().real() + PositionReal { x: -0.5, y: 0.5 } ).integer() +// ).collect::>() +// } +// _ => unimplemented!("E"), +// } +// } +// } +// +// +// +// +// +// +// +// diff --git a/src/user/lib/libgui/cg_core.rs b/src/user/lib/libgui/cg_core.rs index 0fde949..aa4d4bc 100644 --- a/src/user/lib/libgui/cg_core.rs +++ b/src/user/lib/libgui/cg_core.rs @@ -1,13 +1,10 @@ use hashbrown::HashMap; -use spin::{Mutex, MutexGuard}; -use crate::{printerr, serial_println}; -use crate::std::frame::{ColouredChar, Dimensions, Position, special_char, Frame, RenderError, ColorCode}; +use spin::{Mutex}; +use crate::std::frame::{Frame, RenderError}; use alloc::{ boxed::Box, sync::Arc, - vec::Vec, - vec, string::String, }; use core::any::Any; diff --git a/src/user/lib/libgui/cg_inputs.rs b/src/user/lib/libgui/cg_inputs.rs index 2f85ac7..2734bad 100644 --- a/src/user/lib/libgui/cg_inputs.rs +++ b/src/user/lib/libgui/cg_inputs.rs @@ -2,7 +2,6 @@ use alloc::string::String; use alloc::vec::Vec; use alloc::boxed::Box; use core::any::Any; -use core::task::ready; use async_trait::async_trait; use crate::std::application::Exit; use crate::std::frame::{ColouredChar, Dimensions, Frame, Position, RenderError}; @@ -23,7 +22,7 @@ impl CgLineEdit { CgLineEdit { position, dimensions: Dimensions::new(width, 1), - prompt: prompt, + prompt, text: Vec::new(), ptr: 0 } @@ -39,24 +38,24 @@ impl CgComponent for CgLineEdit { if idx >= self.dimensions.x { break; } - frame.write(Position::new(idx, 0), ColouredChar::new(c)); + frame.write(Position::new(idx, 0), ColouredChar::new(c)).unwrap(); idx += 1 } idx += 1; // create a space between the prompt and the text if idx + self.text.len() > self.dimensions.x { - frame.write(Position::new(idx, 0), ColouredChar::new('[')); - frame.write(Position::new(idx + 1, 0), ColouredChar::new('.')); - frame.write(Position::new(idx + 2, 0), ColouredChar::new('.')); - frame.write(Position::new(idx + 3, 0), ColouredChar::new('.')); - frame.write(Position::new(idx + 4, 0), ColouredChar::new(']')); + frame.write(Position::new(idx, 0), ColouredChar::new('[')).unwrap(); + frame.write(Position::new(idx + 1, 0), ColouredChar::new('.')).unwrap(); + frame.write(Position::new(idx + 2, 0), ColouredChar::new('.')).unwrap(); + frame.write(Position::new(idx + 3, 0), ColouredChar::new('.')).unwrap(); + frame.write(Position::new(idx + 4, 0), ColouredChar::new(']')).unwrap(); idx += 5 } self.text.iter().rev().take(self.dimensions.x - idx).rev().for_each(|c| { - frame.write(Position::new(idx, 0), ColouredChar::new(*c)); + frame.write(Position::new(idx, 0), ColouredChar::new(*c)).unwrap(); idx += 1 }); diff --git a/src/user/lib/libgui/cg_utils.rs b/src/user/lib/libgui/cg_utils.rs index 88ebeb5..0a8709c 100644 --- a/src/user/lib/libgui/cg_utils.rs +++ b/src/user/lib/libgui/cg_utils.rs @@ -1,21 +1,23 @@ -use crate::std::frame::{ColouredChar, Dimensions, Frame, Position}; +use crate::std::frame::{ColouredChar, Dimensions, Frame, Position, RenderError}; -pub(crate) fn render_outline(frame: &mut Frame, dimensions: Dimensions) { +pub(crate) fn render_outline(frame: &mut Frame, dimensions: Dimensions) -> Result<(), RenderError> { // draws the sides of the container for i in 0..frame.dimensions.x { - frame.write(Position::new(i, 0), ColouredChar::new('─')); - frame.write(Position::new(i, frame.dimensions.y - 1), ColouredChar::new('─')); + frame.write(Position::new(i, 0), ColouredChar::new('─'))?; + frame.write(Position::new(i, frame.dimensions.y - 1), ColouredChar::new('─'))?; } // draws the top and bottom of the container for i in 0..frame.dimensions.y { - frame.write(Position::new(0, i), ColouredChar::new('│')); - frame.write(Position::new(frame.dimensions.x - 1, i), ColouredChar::new('│')); + frame.write(Position::new(0, i), ColouredChar::new('│'))?; + frame.write(Position::new(frame.dimensions.x - 1, i), ColouredChar::new('│'))?; } // draws the corners of the container - frame.write(Position::new(0, 0), ColouredChar::new('┌')); - frame.write(Position::new(dimensions.x - 1, 0), ColouredChar::new('┐')); - frame.write(Position::new(0, dimensions.y - 1), ColouredChar::new('└')); - frame.write(Position::new(dimensions.x - 1, dimensions.y - 1), ColouredChar::new('┘')); + frame.write(Position::new(0, 0), ColouredChar::new('┌'))?; + frame.write(Position::new(dimensions.x - 1, 0), ColouredChar::new('┐'))?; + frame.write(Position::new(0, dimensions.y - 1), ColouredChar::new('└'))?; + frame.write(Position::new(dimensions.x - 1, dimensions.y - 1), ColouredChar::new('┘'))?; + + Ok(()) } diff --git a/src/user/lib/libgui/cg_widgets.rs b/src/user/lib/libgui/cg_widgets.rs index 2c98914..4326edd 100644 --- a/src/user/lib/libgui/cg_widgets.rs +++ b/src/user/lib/libgui/cg_widgets.rs @@ -1,13 +1,11 @@ -use alloc::{boxed::Box, format, string::String, vec, vec::Vec}; -use alloc::fmt::format; +use alloc::{boxed::Box, format, string::String, vec::Vec}; use alloc::string::ToString; use core::any::Any; use core::cmp::{max, min}; use async_trait::async_trait; use hashbrown::HashMap; -use crate::serial_println; use crate::std::application::Exit; -use super::cg_core::{CgComponent, CgKeyboardCapture, CgOutline, Widget}; +use super::cg_core::{CgComponent, CgKeyboardCapture, Widget}; use super::cg_utils::render_outline; use crate::std::frame::{ColouredChar, Dimensions, Position, Frame, RenderError, ColorCode, BUFFER_WIDTH, BUFFER_HEIGHT}; use crate::std::io::{Color, KeyStroke, Stdin}; @@ -48,7 +46,7 @@ impl CgComponent for CgContainer { } if self.outlined { - render_outline(&mut result, self.dimensions.clone()); + render_outline(&mut result, self.dimensions.clone())?; } Ok(result) @@ -73,17 +71,18 @@ impl CgTextBox { CgTextBox { title, content, position, dimensions, outlined, wrap_words: true } } - fn render_title(&self, frame: &mut Frame) { + fn render_title(&self, frame: &mut Frame) -> Result<(), RenderError>{ let title = self.title.chars(); for (i, c) in title.enumerate() { if i + 2 == self.dimensions.x - 3 { // we don't want to write at the top of the text box - frame.write(Position::new(i + 1, 0), ColouredChar::new('.')); + frame.write(Position::new(i + 1, 0), ColouredChar::new('.'))?; } else if i + 2 >= self.dimensions.x - 2 { - frame.write(Position::new(i + 1, 0), ColouredChar::new('.')); + frame.write(Position::new(i + 1, 0), ColouredChar::new('.'))?; break; } - frame.write(Position::new(i + 2, 0), ColouredChar::new(c)); - } + frame.write(Position::new(i + 2, 0), ColouredChar::new(c))?; + }; + Ok(()) } pub fn wrap_words(&mut self, wrap: bool) { self.wrap_words = wrap; @@ -95,10 +94,10 @@ impl CgComponent for CgTextBox { let mut result = Frame::new(self.position, self.dimensions)?; if self.outlined { - render_outline(&mut result, self.dimensions.clone()); + render_outline(&mut result, self.dimensions.clone())?; } - self.render_title(&mut result); + self.render_title(&mut result)?; let (mut x, mut y) = (1, 1); @@ -123,13 +122,13 @@ impl CgComponent for CgTextBox { if y == self.dimensions.y - 1 { if c != ' ' { (2..5).for_each(|z| { - result.write(Position::new(self.dimensions.x - z, self.dimensions.y - 1), ColouredChar::new('.')); + result.write(Position::new(self.dimensions.x - z, self.dimensions.y - 1), ColouredChar::new('.')).unwrap(); }) } break; } - result.write(Position::new(x, y), ColouredChar::new(c)); + result.write(Position::new(x, y), ColouredChar::new(c))?; x += 1; }; } @@ -180,11 +179,11 @@ impl CgComponent for CgLabel { for (i, c) in shortened_string.chars().enumerate() { if i + left >= self.dimensions.x { (0..3).for_each(|z| { - result.write(Position::new(self.dimensions.x - z + left, self.dimensions.y - 1), ColouredChar::new('.')); + result.write(Position::new(self.dimensions.x - z + left, self.dimensions.y - 1), ColouredChar::new('.')).expect("failed to write"); }); break; } - result.write(Position::new(i + left, 0), ColouredChar::new(c)); + result.write(Position::new(i + left, 0), ColouredChar::new(c))?; }; Ok(result) } @@ -235,7 +234,7 @@ impl CgComponent for CgIndicatorWidget { let shortened_string = self.content.chars().take(self.max_width).collect::(); for (i, c) in shortened_string.chars().enumerate() { - result.write(Position::new(i, 0), ColouredChar::coloured(c, self.colour)); + result.write(Position::new(i, 0), ColouredChar::coloured(c, self.colour)).expect("failed to render indicator widget"); }; Ok(result) @@ -419,7 +418,9 @@ impl CgComponent for CgDialog { // now that we know the X and Y offsets, we can start to draw the frame let mut frame = Frame::new(Position::new(x_offset, y_offset), Dimensions::new(width, height))?; - render_outline(&mut frame, Dimensions::new(width, height)); + if let Err(e) = render_outline(&mut frame, Dimensions::new(width, height)) { + return Err(e); + } // render title @@ -449,7 +450,7 @@ impl CgComponent for CgDialog { break; } - frame.write(Position::new(x, y), ColouredChar::new(c)); + frame.write(Position::new(x, y), ColouredChar::new(c)).unwrap(); x += 1; }; } @@ -462,7 +463,7 @@ impl CgComponent for CgDialog { frame.write(Position::new(button_x_offset + i, height - 3), ColouredChar { character: c, colour: ColorCode::new(Color::Cyan, Color::Black), - }); + }).expect("failed to write to frame, perhaps buttons were placed wrongly or width too great"); }) } CgDialogType::Confirmation => { @@ -483,7 +484,7 @@ impl CgComponent for CgDialog { let button_x_offset = (width - button_fmt.len()) / 2; button_fmt.into_iter().enumerate().for_each(|(i, c)| { - frame.write(Position::new(button_x_offset + i, height - 3), c); + frame.write(Position::new(button_x_offset + i, height - 3), c).expect("failed to write to frame, perhaps buttons were placed wrongly or width too great"); }) }, CgDialogType::Selection(options) => { @@ -504,7 +505,7 @@ impl CgComponent for CgDialog { let button_x_offset = (width - button_fmt.len()) / 2; button_fmt.into_iter().enumerate().for_each(|(i, c)| { - frame.write(Position::new(button_x_offset + i, height - 3), c); + frame.write(Position::new(button_x_offset + i, height - 3), c).expect("failed to write to frame, perhaps buttons were placed wrongly or width too great"); }) } };