made a game

made a snake game and rewrote some rendering stuff again
This commit is contained in:
FantasyPvP
2023-10-02 00:56:18 +01:00
parent f0ee584c87
commit bf9c9be88d
19 changed files with 532 additions and 241 deletions
Generated
+23
View File
@@ -25,6 +25,7 @@ dependencies = [
"rgb", "rgb",
"spin", "spin",
"uart_16550", "uart_16550",
"uchan",
"volatile 0.2.7", "volatile 0.2.7",
"x86_64", "x86_64",
] ]
@@ -96,6 +97,12 @@ version = "1.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "374d28ec25809ee0e23827c2ab573d729e293f281dfe393500e7ad618baa61c6" checksum = "374d28ec25809ee0e23827c2ab573d729e293f281dfe393500e7ad618baa61c6"
[[package]]
name = "cache-padded"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "981520c98f422fcc584dc1a95c334e6953900b9106bc47a9839b81790009eb21"
[[package]] [[package]]
name = "cfg-if" name = "cfg-if"
version = "0.1.10" version = "0.1.10"
@@ -343,6 +350,12 @@ dependencies = [
"lock_api", "lock_api",
] ]
[[package]]
name = "sptr"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3b9b39299b249ad65f3b7e96443bad61c02ca5cd3589f46cb6d610a0fd6c0d6a"
[[package]] [[package]]
name = "syn" name = "syn"
version = "2.0.37" version = "2.0.37"
@@ -365,6 +378,16 @@ dependencies = [
"x86_64", "x86_64",
] ]
[[package]]
name = "uchan"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5045a07b95977d6b1e0a6aa8d0d68a84017e2b8ae01d6bfcafcaa1c0a65e19dc"
dependencies = [
"cache-padded",
"sptr",
]
[[package]] [[package]]
name = "unicode-ident" name = "unicode-ident"
version = "1.0.12" version = "1.0.12"
+1
View File
@@ -30,6 +30,7 @@ hashbrown = "0.13.2"
cmos-rtc = "0.1.2" cmos-rtc = "0.1.2"
libm = "0.2.7" libm = "0.2.7"
log = "0.4.20" log = "0.4.20"
uchan = { version = "0.1.4", default-features = false }
[dependencies.lazy_static] [dependencies.lazy_static]
version = "1.0" version = "1.0"
+3 -2
View File
@@ -5,7 +5,7 @@
#![reexport_test_harness_main = "test_main"] #![reexport_test_harness_main = "test_main"]
use core::panic::PanicInfo; use core::panic::PanicInfo;
use CrystalOS::{println, print, println_log, print_log}; use CrystalOS::{println, print, println_log, print_log, kernel, printerr};
use CrystalOS::kernel::tasks::{Task, executor::Executor}; use CrystalOS::kernel::tasks::{Task, executor::Executor};
use bootloader::{BootInfo, entry_point}; use bootloader::{BootInfo, entry_point};
extern crate alloc; extern crate alloc;
@@ -14,7 +14,8 @@ use CrystalOS::user::bin::shell;
#[cfg(not(test))] #[cfg(not(test))]
#[panic_handler] #[panic_handler]
fn panic(_info: &PanicInfo) -> ! { fn panic(_info: &PanicInfo) -> ! {
println!("{}", _info); kernel::render::RENDERER.lock().terminal_mode_force();
printerr!("{}", _info);
CrystalOS::hlt(); CrystalOS::hlt();
} }
-1
View File
@@ -3,7 +3,6 @@ pub mod fs;
pub mod gdt; pub mod gdt;
pub mod interrupts; pub mod interrupts;
pub mod memory; pub mod memory;
//pub mod render;
pub mod serial; pub mod serial;
pub mod tasks; pub mod tasks;
pub mod sysinit; pub mod sysinit;
+26 -9
View File
@@ -42,24 +42,30 @@ impl ColorCode {
#[derive(Debug, Clone, Copy, PartialEq, Eq)] #[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(C)] #[repr(C)]
struct ScreenChar { pub struct ScreenChar {
character: u8, pub character: u8,
colour: ColorCode, pub colour: ColorCode,
} }
impl ScreenChar { impl ScreenChar {
fn null() -> ScreenChar { pub fn null() -> ScreenChar {
ScreenChar { ScreenChar {
character: 0u8, character: 0u8,
colour: ColorCode::new(Color::White, Color::Black), colour: ColorCode::new(Color::White, Color::Black),
} }
} }
fn white(character: u8) -> ScreenChar { pub fn white(character: u8) -> ScreenChar {
ScreenChar { ScreenChar {
character, character,
colour: ColorCode::new(Color::White, Color::Black), colour: ColorCode::new(Color::White, Color::Black),
} }
} }
pub fn new(character: u8, colour: ColorCode) -> ScreenChar {
ScreenChar {
character,
colour,
}
}
} }
pub const BUFFER_HEIGHT: usize = 25; pub const BUFFER_HEIGHT: usize = 25;
@@ -92,19 +98,26 @@ lazy_static! {
impl Renderer { impl Renderer {
// EXTERNAL API : for use by standard library and other parts of the kernel // EXTERNAL API : for use by standard library and other parts of the kernel
pub fn render_frame(&mut self, frame: [[char; BUFFER_WIDTH]; BUFFER_HEIGHT]) { // renders the given frame to the app buffer pub fn render_frame(&mut self, frame: [[ScreenChar; BUFFER_WIDTH]; BUFFER_HEIGHT]) { // renders the given frame to the app buffer
let mut processed_frame: [[ScreenChar; BUFFER_WIDTH]; BUFFER_HEIGHT] = [[ScreenChar::null(); BUFFER_WIDTH]; BUFFER_HEIGHT]; let mut processed_frame: [[ScreenChar; BUFFER_WIDTH]; BUFFER_HEIGHT] = [[ScreenChar::null(); BUFFER_WIDTH]; BUFFER_HEIGHT];
for (i, row) in frame.iter().enumerate() { for (i, row) in frame.iter().enumerate() {
for (j, col) in row.iter().enumerate() { for (j, col) in row.iter().enumerate() {
processed_frame[i][j] = match self.special_char(*col) { processed_frame[i][j] = match self.special_char(col.character as char) {
Some(c) => ScreenChar::white(c as u8), Some(c) => ScreenChar::new(c as u8, col.colour),
None => ScreenChar::white(*col as u8) None => *col,
}; };
} }
} }
self.app_buffer = processed_frame; self.app_buffer = processed_frame;
self.internal_render();
}
pub fn terminal_mode_force(&mut self) { // THIS SHOULD ONLY BE USED WHEN THE KERNEL PANICS
// TODO: find a way to make this function kernel only
self.application_mode = false;
self.internal_render();
} }
pub fn application_mode(&mut self) -> Result<(), ()> { pub fn application_mode(&mut self) -> Result<(), ()> {
@@ -132,11 +145,13 @@ impl Renderer {
} }
pub fn write_char(&mut self, ch: u8, col: Option<ColorCode>) { // default colour if no colour is selected for character pub fn write_char(&mut self, ch: u8, col: Option<ColorCode>) { // default colour if no colour is selected for character
if self.application_mode { return; };
self.write_byte(ch, col); self.write_byte(ch, col);
self.internal_render(); self.internal_render();
} }
pub fn write_string(&mut self, string: &str, col: Option<ColorCode>) { pub fn write_string(&mut self, string: &str, col: Option<ColorCode>) {
if self.application_mode { return; };
for ch in string.chars() { for ch in string.chars() {
match self.special_char(ch) { match self.special_char(ch) {
Some(c) => self.write_byte(c, col), Some(c) => self.write_byte(c, col),
@@ -150,6 +165,7 @@ impl Renderer {
} }
pub fn backspace(&mut self) -> Result<(), ()> { pub fn backspace(&mut self) -> Result<(), ()> {
if self.application_mode { return Ok(()); };
loop { loop {
if self.internal_backspace()? { if self.internal_backspace()? {
@@ -163,6 +179,7 @@ impl Renderer {
pub fn clear(&mut self) { // clears the screen and all scroll-back pub fn clear(&mut self) { // clears the screen and all scroll-back
if self.application_mode { return; }; if self.application_mode { return; };
self.term_buffer = vec![[ScreenChar::null(); BUFFER_WIDTH]; BUFFER_HEIGHT]; self.term_buffer = vec![[ScreenChar::null(); BUFFER_WIDTH]; BUFFER_HEIGHT];
self.internal_render(); self.internal_render();
} }
@@ -1,4 +1,4 @@
/*
pub mod thread_switch; pub mod thread_switch;
@@ -12,4 +12,4 @@ pub struct Thread {
stack_pointer: Option<VirtAddr>, stack_pointer: Option<VirtAddr>,
stack_bounds: Option<StackBounds>, stack_bounds: Option<StackBounds>,
} }
*/
+1
View File
@@ -14,6 +14,7 @@ pub trait Application {
pub enum Error { pub enum Error {
UnknownCommand(String), UnknownCommand(String),
CommandFailed(String), CommandFailed(String),
ApplicationError(String),
EmptyCommand, EmptyCommand,
} }
+154
View File
@@ -0,0 +1,154 @@
use alloc::string::String;
use alloc::vec::Vec;
use lazy_static::lazy_static;
use crate::kernel::render::{BUFFER_HEIGHT, BUFFER_WIDTH, RENDERER, ScreenChar};
use crate::println;
use spin::Mutex;
/// TODO: get a working implementation for CLI apps
/// elements can be created using their from_str() method
/// you can then render the element to the current frame using the render() method
/// the position of the element by passing a tuple (x,y) to render()
///
/// nothing will appear on the screen until the frame is actually rendered by
/// the render_frame method on the renderer
///
pub type Frame = [ [ ScreenChar; BUFFER_WIDTH ]; BUFFER_HEIGHT];
#[derive(Clone)]
pub struct Element {
frame: Vec<Vec<char>>,
dimensions: (u8, u8)
}
impl Element {
pub fn from_str(elemstr: String) -> Self {
let mut element = Element { frame: Vec::<Vec<char>>::new(), dimensions: (0, 0) };
for line in elemstr.split("\n") {
let mut ln = Vec::<char>::new();
for col in line.chars() {
ln.push(col)
};
element.frame.push(ln);
}
for row in element.clone().frame {
let n = row.len();
if n > element.dimensions.0 as usize {
element.dimensions.0 = n as u8;
}
}
element
}
pub fn generate(frame: Vec::<Vec<char>>, dims: (u8, u8)) -> Self {
Element { frame, dimensions: dims }
}
pub fn render(&mut self, pos: (u8, u8)) { // x,y
for (i, row) in self.frame.iter().enumerate() {
for (j, col) in row.iter().enumerate() {
//println!("{} {} {}", i, j, col);
FRAMEGEN.lock().frame[i + pos.1 as usize][j + pos.0 as usize] = ScreenChar::white(*col as u8);
};
}
FRAMEGEN.lock().render_frame();
}
}
#[derive(Clone)]
pub struct ColouredElement {
frame: Vec<Vec<ScreenChar>>,
dimensions: (u8, u8)
}
impl ColouredElement {
pub fn from_str(elemstr: String) -> Self {
let mut element = ColouredElement { frame: Vec::<Vec<ScreenChar>>::new(), dimensions: (0, 0) };
for line in elemstr.split("\n") {
let mut ln = Vec::<ScreenChar>::new();
for col in line.chars() {
ln.push(ScreenChar::white(col as u8))
};
element.frame.push(ln);
}
for row in element.clone().frame {
let n = row.len();
if n > element.dimensions.0 as usize {
element.dimensions.0 = n as u8;
}
}
element
}
pub fn generate(frame: Vec::<Vec<ScreenChar>>, dims: (u8, u8)) -> Self {
ColouredElement { frame, dimensions: dims }
}
pub fn render(&mut self, pos: (u8, u8)) -> Result<(), ()> { // x,y
// this block returns an error if any characters will be drawn out of the bounds of the screen
if self.dimensions.0 + pos.0 > BUFFER_WIDTH as u8 {
return Err(());
} else if self.dimensions.1 + pos.1 > BUFFER_HEIGHT as u8 {
return Err(());
} else if self.frame.len() != self.dimensions.1 as usize {
return Err(())
} else if self.frame.iter().map(|r| r.len()).max().ok_or_else(|| ())? > self.dimensions.0 as usize {
return Err(())
}
for (i, row) in self.frame.iter().enumerate() {
for (j, col) in row.iter().enumerate() {
//println!("{} {} {}", i, j, col);
FRAMEGEN.lock().frame[i + pos.1 as usize][j + pos.0 as usize] = *col;
};
}
FRAMEGEN.lock().render_frame();
Ok(())
}
}
#[derive(Clone, Copy)]
pub struct FrameGen {
frame: Frame,
}
impl FrameGen {
pub fn render_frame(&self) {
RENDERER.lock().render_frame(self.frame)
}
fn new() -> Self {
let mut frame: [[ScreenChar; BUFFER_WIDTH]; BUFFER_HEIGHT] = [[ScreenChar::null(); BUFFER_WIDTH]; BUFFER_HEIGHT];
Self { frame: Frame::from(frame) }
}
fn set_frame(&mut self, frame: Frame) {
self.frame = frame;
}
pub fn get_frame(&self) -> &[ [ ScreenChar; BUFFER_WIDTH ]; BUFFER_HEIGHT] {
&self.frame
}
}
lazy_static! {
pub static ref FRAMEGEN: Mutex<FrameGen> = Mutex::new(FrameGen::new() );
}
impl core::fmt::Display for FrameGen {
fn fmt(&self, _: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
println!(" ");
for row in &self.frame {
println!("{}", row.iter().map(|c| c.character as char ).collect::<String>());
};
Ok(())
}
}
+14 -137
View File
@@ -1,9 +1,9 @@
use crate::{ use crate::{
kernel::render::{RENDERER, BUFFER_WIDTH, BUFFER_HEIGHT, ColorCode}, kernel::render::{RENDERER, self},
kernel::tasks::keyboard::KEYBOARD, kernel::tasks::keyboard::KEYBOARD,
}; };
use alloc::{boxed::Box, string::{String, ToString}, vec::Vec}; use alloc::string::String;
pub use crate::{print, println, serial_print, serial_println}; pub use crate::{print, println, serial_print, serial_println};
pub use crate::kernel::render::Color; pub use crate::kernel::render::Color;
@@ -45,112 +45,6 @@ impl Screen {
} }
/// TODO: get a working implementation for CLI apps
/// elements can be created using their from_str() method
/// you can then render the element to the current frame using the render() method
/// the position of the element by passing a tuple (x,y) to render()
///
/// nothing will appear on the screen until the frame is actually rendered by
/// the render_frame method on the renderer
///
pub type Frame = [ [ char; BUFFER_WIDTH ]; BUFFER_HEIGHT];
#[derive(Clone)]
pub struct Element {
frame: Vec<Vec<char>>,
dimensions: (u8, u8)
}
impl Element {
pub fn from_str(elemstr: String) -> Self {
let mut element = Element { frame: Vec::<Vec<char>>::new(), dimensions: (0, 0) };
for line in elemstr.split("\n") {
let mut ln = Vec::<char>::new();
for col in line.chars() {
ln.push(col)
};
element.frame.push(ln);
}
for row in element.clone().frame {
let n = row.len();
if n > element.dimensions.0 as usize {
element.dimensions.0 = n as u8;
}
}
element
}
pub fn render(&mut self, pos: (u8, u8)) { // x,y
for (i, row) in self.frame.iter().enumerate() {
for (j, col) in row.iter().enumerate() {
println!("{} {} {}", i, j, col);
FRAMEGEN.lock().frame[i + pos.1 as usize][j + pos.0 as usize] = *col;
};
}
}
}
lazy_static! {
pub static ref FRAMEGEN: Mutex<FrameGen> = Mutex::new(FrameGen::new() );
}
#[derive(Clone, Copy)]
pub struct FrameGen {
frame: Frame,
}
impl FrameGen {
pub fn render_frame(&self) {
RENDERER.lock().render_frame(self.frame)
}
fn new() -> Self {
let mut frame: [[char; BUFFER_WIDTH]; BUFFER_HEIGHT] = [[' '; BUFFER_WIDTH]; BUFFER_HEIGHT];
for i in 0..BUFFER_WIDTH {
frame[0][i] = "┌──────────────────────────────────────────────────────────────────────────────┐".chars().collect::<Vec<char>>()[i];
frame[BUFFER_HEIGHT -1][i] = "└──────────────────────────────────────────────────────────────────────────────┘".chars().collect::<Vec<char>>()[i];
}
for j in 1..BUFFER_HEIGHT -1 {
for i in 0..BUFFER_WIDTH {
frame[j][i] = "│ │".chars().collect::<Vec<char>>()[i];
}
}
Self { frame: Frame::from(frame) }
}
pub fn get_frame(&self) -> &[ [ char; BUFFER_WIDTH ]; BUFFER_HEIGHT] {
&self.frame
}
}
impl core::fmt::Display for FrameGen {
fn fmt(&self, _: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
println!(" ");
for row in &self.frame {
println!("{}", row.iter().collect::<String>());
};
Ok(())
}
}
#[macro_export] #[macro_export]
macro_rules! println_log { macro_rules! println_log {
() => ($crate::print_log!("/n")); () => ($crate::print_log!("/n"));
@@ -173,43 +67,26 @@ macro_rules! print {
($($arg:tt)*) => ($crate::std::io::_print(format_args!($($arg)*))); ($($arg:tt)*) => ($crate::std::io::_print(format_args!($($arg)*)));
} }
#[macro_export]
macro_rules! printerr {
($($arg:tt)*) => ($crate::std::io::_printerr(format_args!($($arg)*)));
}
#[doc(hidden)] #[doc(hidden)]
pub fn _print(args: core::fmt::Arguments) { pub fn _print(args: core::fmt::Arguments) {
use core::fmt::Write; render::write(args, (Color::White, Color::Black));
use x86_64::instructions::interrupts; }
interrupts::without_interrupts(|| { #[doc(hidden)]
let mut writer = RENDERER.lock(); pub fn _printerr(args: core::fmt::Arguments) {
writer.write_fmt(args).unwrap(); render::write(args, (Color::Yellow, Color::Black));
//WRITER.lock().write_fmt(args).unwrap();
//writer.col_code = crate::kernel::render2::ColorCode::new(Color::White, Color::Black);
});
} }
#[doc(hidden)] #[doc(hidden)]
pub fn _log(args: core::fmt::Arguments) { pub fn _log(args: core::fmt::Arguments) {
use core::fmt::Write; render::write(args, (Color::White, Color::Black));
use x86_64::instructions::interrupts;
interrupts::without_interrupts(|| {
let mut writer = RENDERER.lock();
writer.write_fmt(args).unwrap();
//writer.col_code = crate::kernel::render2::ColorCode::new(Color::Yellow, Color::Black);
//WRITER.lock().write_fmt(args).unwrap();
});
} }
pub fn write(args: core::fmt::Arguments, color: (Color, Color)) {
render::write(args, color);
pub fn write(args: core::fmt::Arguments, cols: (Color, Color)) {
crate::kernel::render::write(args, cols);
}
pub fn mkfs() {
use crate::kernel::fs;
fs::mkfs();
println!("{:?}", *(fs::FILESYSTEM.lock()));
} }
+1
View File
@@ -3,6 +3,7 @@ pub mod random;
pub mod application; pub mod application;
pub mod tasks; pub mod tasks;
pub mod os; pub mod os;
pub mod frame;
// this is where the standard library for the operating system will be defined // this is where the standard library for the operating system will be defined
+10 -10
View File
@@ -1,24 +1,24 @@
use async_trait::async_trait; use async_trait::async_trait;
use rand::prelude::*;
use super::{ use super::{
engine::{eventcheck, Choice, Event}, engine::{Choice, Event, eventcheck},
entity::{Entity, Enemy, EntityObject}, entity::{Enemy, Entity, EntityObject},
player::Player, player::Player,
}; };
use alloc::{boxed::Box, string::{String, ToString}, vec::Vec, format, borrow::ToOwned}; use alloc::{borrow::ToOwned, format, string::{String, ToString}, vec::Vec, boxed::Box};
use crate::{ use crate::{
std::{
io::{self, println, serial_println},
frame::FRAMEGEN,
random,
},
std::application::{ std::application::{
Application, Application,
Error, Error,
}, },
std::{
io::{self, println, serial_println, FRAMEGEN, Element},
random,
},
}; };
use crate::system::std::frame::Element;
pub struct GameLoop; pub struct GameLoop;
@@ -91,7 +91,7 @@ impl Application for GameLoop {
for row in fr { for row in fr {
let mut r = String::new(); let mut r = String::new();
for col in row { for col in row {
r.push(col); r.push(col.character as char);
} }
string.push_str(&r); string.push_str(&r);
string.push('\n') string.push('\n')
+9 -9
View File
@@ -8,13 +8,13 @@ use crate::{std::os::OS, std::io::{Color, write, Screen}, println, std::applicat
}, std}; }, std};
const CRYSTAL_LOGO: &str = const CRYSTAL_LOGO: &str =
" $$$$$$\\ $$\\ $$\\ $$$$$$\\ $$$$$$\\ "\n $$$$$$\\ $$\\ $$\\ $$$$$$\\ $$$$$$\\
$$ __$$\\ $$ | $$ $$ __$$\\$$ __$$\\ $$ __$$\\ $$ | $$ $$ __$$\\$$ __$$\\
$$ / \\__|$$$$$$\\ $$\\ $$\\ $$$$$$$\\$$$$$$\\ $$$$$$\\ $$ $$ / $$ $$ / \\__| $$ / \\__|$$$$$$\\ $$\\ $$\\ $$$$$$$\\$$$$$$\\ $$$$$$\\ $$ $$ / $$ $$ / \\__|
$$ | $$ __$$\\$$ | $$ $$ _____\\_$$ _| \\____$$\\$$ $$ | $$ \\$$$$$$\\ $$ | $$ __$$\\$$ | $$ $$ _____\\_$$ _| \\____$$\\$$ $$ | $$ \\$$$$$$\\
$$ | $$ | \\__$$ | $$ \\$$$$$$\\ $$ | $$$$$$$ $$ $$ | $$ |\\____$$\\ $$ | $$ | \\__$$ | $$ \\$$$$$$\\ $$ | $$$$$$$ $$ $$ | $$ |\\____$$\\
$$ | $$\\$$ | $$ | $$ |\\____$$\\ $$ |$$\\$$ __$$ $$ $$ | $$ $$\\ $$ | $$ | $$\\$$ | $$ | $$ |\\____$$\\ $$ |$$\\$$ __$$ $$ $$ | $$ $$\\ $$ |
\\$$$$$$ $$ | \\$$$$$$$ $$$$$$$ | \\$$$$ \\$$$$$$$ $$ |$$$$$$ \\$$$$$$ | \\$$$$$$ $$ | \\$$$$$$$ $$$$$$$ | \\$$$$ \\$$$$$$$ $$ |$$$$$$ \\$$$$$$ |
\\______/\\__| \\____$$ \\_______/ \\$$$$$$\\_______\\__|\\______/ \\______/ \\______/\\__| \\____$$ \\_______/ \\$$$$$$\\_______\\__|\\______/ \\______/
$$\\ $$ | $$ __$$\\ $$\\ $$ | $$ __$$\\
\\$$$$$$ | $$\\ $$\\__/ $$ | \\$$$$$$ | $$\\ $$\\__/ $$ |
@@ -59,10 +59,10 @@ impl Application for CrystalFetch {
[ Author » FantasyPvP / ZXQ5", os, version); [ Author » FantasyPvP / ZXQ5", os, version);
// write to output // write to output
let spacer = "\n".repeat(24 - logo_string.lines().count() - 4 - info_string.lines().count()); let spacer = "\n".repeat(25 - logo_string.lines().count() - 4 - info_string.lines().count());
// write values to console // write values to console
write(format_args!("{}", logo_string), (Color::Cyan, Color::Black)); write(format_args!("{}", logo_string), (Color::Cyan, Color::Black));
println!("\n\n"); println!("\n");
println!("{}", info_string); println!("{}", info_string);
println!("{}", spacer); println!("{}", spacer);
+1
View File
@@ -7,3 +7,4 @@ pub mod shell;
pub mod tasks; pub mod tasks;
mod gigachad_detector; mod gigachad_detector;
mod shellrewrite; mod shellrewrite;
mod snake;
+4 -4
View File
@@ -125,13 +125,13 @@ async fn exec() -> Result<(), Error> {
"switch" => { "switch" => {
Screen::switch(); Screen::switch();
} }
"snake" => {
let mut game = snake::Game::new();
game.run(Vec::new()).await;
}
"gigachad?" => { "gigachad?" => {
let mut gigachad_detector = GigachadDetector::new(); let mut gigachad_detector = GigachadDetector::new();
gigachad_detector.run(args).await?; gigachad_detector.run(args).await?;
}
"filesystem" => {
use crate::std::io;
io::mkfs();
} }
"test_features" => { "test_features" => {
use crate::std::random::Random; use crate::std::random::Random;
+98 -32
View File
@@ -4,11 +4,7 @@ use lazy_static::lazy_static;
use spin::Mutex; use spin::Mutex;
use x86_64::instructions::interrupts; use x86_64::instructions::interrupts;
use alloc::{ use alloc::{boxed::Box, string::{String, ToString}, vec, vec::Vec};
boxed::Box,
string::{String, ToString},
vec::Vec,
};
use crate::{ use crate::{
kernel::tasks::{executor::Executor, Task}, kernel::tasks::{executor::Executor, Task},
@@ -16,6 +12,8 @@ use crate::{
std::io::{print, println, Stdin, Screen}, std::io::{print, println, Stdin, Screen},
user::bin::*, user::bin::*,
}; };
use crate::std::io::{Color, write};
use crate::user::bin::gigachad_detector::GigachadDetector;
use super::*; use super::*;
@@ -34,37 +32,107 @@ use super::*;
/// starts the shell /// starts the shell
/// this function should be directly called by main.rs or by an init system /// this function should be directly called by main.rs or by an init system
fn new_function() {
}
pub fn userspace() -> Result<(), String> { fn run_task(task_name: String, args: Vec<String>) -> Result<(), String> {
let mut executor = Executor::new();
//
// executor.spawn(Task::new(new_function()));
// loop {
// executor.try_run()
// }
Ok(()) Ok(())
} }
// struct Shell {} pub async fn userspace() -> Result<(), String> {
// let mut executor = Executor::new();
// impl Application for Shell {
// fn new() -> Shell {
// Shell {}
// }
// async fn run(&mut self, _: Vec<String>) -> Result<(), Error> {
// Ok(())
// }
// }
let mut shell = Shell::new();
shell.run(vec![]).await.unwrap();
Ok(())
}
struct Shell {
history: Vec<String>,
}
fn parse_args(command: String) -> Result<(String, Vec<String>), String> { #[async_trait]
impl Application for Shell {
fn new() -> Shell {
Shell {
history: Vec::new(),
}
}
async fn run(&mut self, _: Vec<String>) -> Result<(), Error> {
loop {
self.prompt();
let input = Stdin::readline().await;
let (cmd, args) = self.parse_args(input).unwrap();
self.run_cmd(cmd, args).await.unwrap();
}
}
}
impl Shell {
fn prompt(&mut self) {
write(format_args!("\n Crystal> "), (Color::Cyan, Color::Black));
}
// fn exec<R, T: Fn() -> R>(command: T) -> Result<R, Error> { // this command runs when a shell command is executed
// Ok(command())
// }
async fn run_cmd(&mut self, cmd: String, args: Vec<String>) -> Result<(), Error> {
match cmd.as_str() {
"calculate" | "calc" | "solve" => {
let mut cmd = calc::Calculator::new();
cmd.run(args).await?;
}
"rickroll" => {
let mut cmd = rickroll::Rickroll::new();
cmd.run(args).await?;
}
"crystalfetch" => {
let mut cmd = crystalfetch::CrystalFetch::new();
cmd.run(args).await?;
}
"tasks" => {
let mut cmd = tasks::Tasks::new();
cmd.run(args).await?;
}
"play" => {
let mut gameloop = crystal_rpg::init::GameLoop::new();
gameloop.run(args).await?;
}
"echo" => {
println!(
"Crystal: '{}'",
" ".join(args)
)
}
"clear" => {
Screen::clear();
}
"print" => {
use crate::std::os::OS;
let x: String = OS.lock().version.clone();
println!("{}", x);
}
"snake" => {
let mut game = snake::Game::new();
game.run(Vec::new()).await?;
}
"gigachad?" => {
let mut gigachad_detector = GigachadDetector::new();
gigachad_detector.run(args).await?;
}
"test_features" => {
use crate::std::random::Random;
println!("{}", Random::int(0, 10));
}
_ => {
return Err(Error::UnknownCommand(
"command not yet implemented".to_string(),
))
}
}
Ok(())
}
fn parse_args(&self, command: String) -> Result<(String, Vec<String>), String> {
let mut args: Vec<String> = Vec::new(); let mut args: Vec<String> = Vec::new();
for arg in command.split(" ").collect::<Vec<&str>>() { for arg in command.split(" ").collect::<Vec<&str>>() {
@@ -78,15 +146,13 @@ fn parse_args(command: String) -> Result<(String, Vec<String>), String> {
if args.len() > 0 { if args.len() > 0 {
cmd = args[0].clone(); cmd = args[0].clone();
args.remove(0); args.remove(0);
} else { }
else {
return Err("command was empty.".to_string()); return Err("command was empty.".to_string());
}; };
Ok((cmd, args)) Ok((cmd, args))
}
} }
//fn run_binary(binary: dyn Application) -> Result<Vec<String>, String> {
// binary.run();
// Ok(Vec::<String::new()>)
//}
+150
View File
@@ -0,0 +1,150 @@
use alloc::string::String;
use alloc::{format, vec, vec::Vec, boxed::Box};
use async_trait::async_trait;
use crate::std::io::{Color, Screen};
use crate::kernel::tasks::keyboard::KEYBOARD;
use crossbeam_queue::SegQueue;
use crate::kernel::render::{ColorCode, ScreenChar};
use crate::std::application::{Application, Error};
use crate::std::random::Random;
use crate::system::std::frame::ColouredElement;
#[derive(Clone, Debug, PartialEq)]
struct Point {
x: i8,
y: i8,
}
pub struct Game {
snake: SegQueue<Point>,
head: Point,
poi: Point,
score: u8
}
#[async_trait]
impl Application for Game {
fn new() -> Self {
Self {
snake: SegQueue::new(),
head: Point { x: 5, y: 5 },
poi: Point { x: 0, y: 0 },
score: 0
}
}
async fn run(&mut self, _: Vec<String>) -> Result<(), Error> {
Screen::application_mode();
(0..=2).for_each(|x| {
self.snake.push(Point { x, y: 5 });
});
self.head = Point { x: 2, y: 5 };
self.new_poi();
'gameloop: loop {
let chr = KEYBOARD.lock().get_keystroke().await;
match chr {
'w' => self.head.y -= 1,
'a' => self.head.x -= 1,
's' => self.head.y += 1,
'd' => self.head.x += 1,
'x' => break,
_ => continue,
}
self.snake.push(Point { x: self.head.x, y: self.head.y }); // new head added
if self.head == self.poi {
self.new_poi();
self.score += 1
} else {
self.snake.pop().unwrap(); // tail removed if score does not increase
}
if self.lose_condition() {
self.render_end_screen().map_err(|_| Error::ApplicationError(String::from("failed to render game over screen")))?;
while let chr = KEYBOARD.lock().get_keystroke().await {
match chr {
'x' => break 'gameloop,
_ => continue,
}
}
}
let clone = self.clone_snake();
self.render(clone).map_err(|_| Error::ApplicationError(String::from("failed to render game screen")))?;
};
Screen::terminal_mode();
Ok(())
}
}
impl Game {
fn new_poi(&mut self) {
self.poi = Point { x: Random::int(3, 76) as i8, y: Random::int(3, 21) as i8 }
}
fn render(&mut self, snake: Vec<Point>) -> Result<(), ()> {
let mut frame = vec![vec![ScreenChar::null(); 80]; 25];
snake.into_iter().for_each(|p| {
frame[p.y as usize][p.x as usize] = ScreenChar::new('@' as u8, ColorCode::new(Color::Cyan, Color::Black));
});
frame[self.poi.y as usize][self.poi.x as usize] = ScreenChar::new('o' as u8, ColorCode::new(Color::Red, Color::Black));
let literal = format!("snake go brr score: {}", self.score);
let msg = Game::centre_text(80, literal);
frame[1] = msg.chars().map(|c| ScreenChar::new(c as u8, ColorCode::new(Color::LightGreen, Color::Black))).collect();
let mut elem = ColouredElement::generate(frame, (80, 25));
elem.render((0,0))
}
fn lose_condition(&mut self) -> bool {
let cloned = self.clone_snake();
let snake_overlaps = (1..cloned.len()).any(|i| cloned[i..].contains(&cloned[i - 1])); // checks if any part of the snake overlaps itself
let out_of_bounds = cloned.iter().filter(|p| p.x < 0 || p.y < 0 || p.x > 79 || p.y > 24).count() > 0; // checks if the snake goes out of bounds
snake_overlaps || out_of_bounds
}
fn centre_text(dims: usize, text: String) -> String { // centres text in a string of whitespace of a given length
let max_pad = dims / 2;
let mut msg = String::new();
msg.push_str(" ".repeat(max_pad - round_up(text.len() as f64 / 2.0)).as_str());
msg.push_str(text.as_str());
msg.push_str(" ".repeat(max_pad - round_down(text.len() as f64 / 2.0 + 0.51)).as_str());
msg
}
fn render_end_screen(&mut self) -> Result<(), ()> {
let mut frame = vec![vec![ScreenChar::null(); 80]; 25];
frame[10] = Game::centre_text(80, String::from("u lost")).chars().map(|c| ScreenChar::new(c as u8, ColorCode::new(Color::Red, Color::Black))).collect();
frame[12] = Game::centre_text(80, String::from(format!("ur score was {}", self.score))).chars().map(|c| ScreenChar::new(c as u8, ColorCode::new(Color::LightGreen, Color::Black))).collect();
frame[14] = Game::centre_text(80, String::from("L bozo")).chars().map(|c| ScreenChar::new(c as u8, ColorCode::new(Color::Red, Color::Black))).collect();
let mut elem = ColouredElement::generate(frame, (80, 25));
elem.render((0,0))
}
fn clone_snake(&mut self) -> Vec<Point> {
let mut cloned= Vec::new();
let mut snake = SegQueue::new();
while !self.snake.is_empty() {
let item = self.snake.pop().unwrap();
cloned.push(item.clone());
snake.push(item);
}
self.snake = snake;
cloned
}
}
fn round_up(n: f64) -> usize {
(n + 0.99) as usize
}
fn round_down(n: f64) -> usize {
n as usize
}
+5 -5
View File
@@ -1,5 +1,5 @@
use crate::kernel::render::{BUFFER_HEIGHT, BUFFER_WIDTH, RENDERER}; use crate::kernel::render::{BUFFER_HEIGHT, BUFFER_WIDTH, RENDERER, ScreenChar};
use crate::std::io::Frame; use crate::system::std::frame::Frame;
use crate::{print, println}; use crate::{print, println};
use alloc::{ use alloc::{
boxed::Box, boxed::Box,
@@ -154,7 +154,7 @@ impl Element for IndicatorBar {
// rendered. // rendered.
pub fn render_frame(elements: Vec<Container>) { pub fn render_frame(elements: Vec<Container>) {
let mut buffer: Frame = [[' '; BUFFER_WIDTH]; BUFFER_HEIGHT]; let mut buffer: Frame = [[ScreenChar::null(); BUFFER_WIDTH]; BUFFER_HEIGHT];
for frame in elements.iter() { for frame in elements.iter() {
let f = frame.render(); let f = frame.render();
@@ -162,8 +162,8 @@ pub fn render_frame(elements: Vec<Container>) {
for (i, row) in f.0.iter().enumerate() { for (i, row) in f.0.iter().enumerate() {
for (j, chr) in row.iter().enumerate() { for (j, chr) in row.iter().enumerate() {
let mut current = &buffer[i + f.1.y][j + f.1.x]; let mut current = &buffer[i + f.1.y][j + f.1.x];
let newchar = overlap_check(*current, *chr); let newchar = overlap_check(current.character as char, *chr);
buffer[i + f.1.y][j + f.1.x] = newchar; buffer[i + f.1.y][j + f.1.x] = ScreenChar::white(newchar as u8);
//print!("{}", buffer[i+frame.position.1][j+frame.position.0]); //print!("{}", buffer[i+frame.position.1][j+frame.position.0]);
} }