- 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
This commit is contained in:
FantasyPvP
2024-03-22 00:12:15 +00:00
parent 5c6ec299ee
commit d5d9e031d5
29 changed files with 439 additions and 436 deletions
-4
View File
@@ -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)]
+1 -5
View File
@@ -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 {}
}
+3 -3
View File
@@ -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() };
+9 -23
View File
@@ -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);
-1
View File
@@ -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';
-1
View File
@@ -1,4 +1,3 @@
use crate::println;
pub fn init() -> Result<(), ()> {
Ok(())
}
+1 -1
View File
@@ -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;
+7 -3
View File
@@ -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() {
+26 -4
View File
@@ -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 {
+1 -2
View File
@@ -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};
-3
View File
@@ -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;
-6
View File
@@ -293,12 +293,6 @@ impl GameTimer {
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
}
-3
View File
@@ -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<Token>,
idx: i32,
-1
View File
@@ -1,6 +1,5 @@
use alloc::format;
use alloc::string::String;
use crate::println;
const PI: f64 = 3.14159265358979323846264338327950288419716939937510;
+6 -5
View File
@@ -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 $$$$$$\\ $$\\ $$\\ $$$$$$\\ $$$$$$\\
+146 -146
View File
@@ -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<Box<dyn Skill>>,
helmet: Option<Helmet>,
chestplate: Option<Chestplate>,
boots: Option<Boots>,
inventory: Vec<Item>,
}
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<Item> {
&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<Box<dyn Skill>>,
//
// helmet: Option<Helmet>,
// chestplate: Option<Chestplate>,
// boots: Option<Boots>,
//
// inventory: Vec<Item>,
// }
//
// 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<Item> {
// &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,
// }
+2 -5
View File
@@ -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<String>) -> 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(())
}
}
-2
View File
@@ -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,
+4 -10
View File
@@ -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::<CgLineEdit>().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) {
+56 -12
View File
@@ -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<String>) -> 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<Frame, RenderError> {
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;
}
}
+1 -1
View File
@@ -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};
+8 -13
View File
@@ -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" => {
+6 -16
View File
@@ -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<String>) -> 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>) -> Direction {
+4 -5
View File
@@ -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();
}
}
+112 -114
View File
@@ -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<String>) -> 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<Position> {
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::<Vec<Position>>()
}
_ => 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<String>) -> 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<Position> {
// 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::<Vec<Position>>()
// }
// _ => unimplemented!("E"),
// }
// }
// }
//
//
//
//
//
//
//
//
+2 -5
View File
@@ -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;
+8 -9
View File
@@ -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
});
+12 -10
View File
@@ -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(())
}
+23 -22
View File
@@ -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::<String>();
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");
})
}
};