game.rs
game.rs
RUST1use std::fmt::Debug;23use super::cubios;4use super::cubios::{topology, comm, gfx};567#[allow(dead_code)]8#[derive(Debug)]9pub enum GameErr {10 ValueIsNone,11 SceneNotFound(u8),12 AssetNotFound(&'static str),13 ImgNotFound(u8),14 InvalidModule(u8, u8),15 InvalidPlace(u8, u8),16 InvalidTwist(u8, u8),17 InvalidDirection(u8),18 InvalidOrientation(u8)19}2021#[allow(dead_code)]22#[derive(Debug)]23pub enum GamePkt {24 SetNone = 0,25 SetMap,26 SetScene,27 Custom28}2930#[allow(dead_code)]31#[derive(Debug)]32pub enum RotationDir {33 Forward,34 Backward,35 Right,36 Left37}3839#[allow(dead_code)]40#[derive(Debug)]41pub struct Anim<T> {42 pub val: T,43 pub anim: u8,44 pub step: u8,45 pub cycle: bool,46 pub enable: bool47}4849#[allow(dead_code)]50pub trait Game {51 fn on_render(&self) -> Result<(), GameErr> {52 Ok(())53 }5455 fn on_init(&mut self) -> Result<(), GameErr> {56 Ok(())57 }5859 fn on_tick(&mut self) -> Result<(), GameErr> {60 Ok(())61 }6263 fn on_phys_tick(&mut self) -> Result<(), GameErr> {64 Ok(())65 }6667 fn on_twist(&mut self) -> Result<(), GameErr> {68 Ok(())69 }7071 fn on_rx(&mut self, _line: usize) -> Result<(), GameErr> {72 Ok(())73 }74 fn on_pat(&mut self) -> Result<(), GameErr> {75 Ok(())76 }77}7879#[allow(dead_code)]80pub trait Assetable {81 fn get_asset_id(asset: &'static str) -> Result<u32, GameErr> {82 let id = gfx::get_asset_id(asset);8384 if id.is_negative() {85 return Err(GameErr::AssetNotFound(asset));86 }87 Ok(id as u32)88 }89}9091#[allow(dead_code)]92pub trait Mappable {93 fn get_place(&self, module: u32, screen: u32, orientation: cubios::TopologyOrientation) -> Result<(u32, u32), GameErr> {94 let mut place = cubios::TopologyPlace {face:0xff, position: 0xff};95 topology::get_place(module, screen, orientation, &mut place);9697 if place.position == 0xff || place.position == 4 || place.face == 0xff || place.face == 6 {98 return Err(GameErr::InvalidPlace(place.face as u8, place.position as u8));99 }100 Ok((place.face as u32, place.position as u32))101 }102103 fn get_place_orientation(&self, face: u32, pos: u32) -> Result<cubios::TopologyLocation, GameErr> {104 let orient = topology::get_place_orientation(face, pos);105106 if orient == cubios::TopologyLocation::Max as i32 || orient == 0xff {107 return Err(GameErr::InvalidOrientation(orient as u8));108 }109110 let res = match orient {111 0 => cubios::TopologyLocation::Up,112 1 => cubios::TopologyLocation::Down,113 2 => cubios::TopologyLocation::Front,114 3 => cubios::TopologyLocation::Back,115 4 => cubios::TopologyLocation::Left,116 5 => cubios::TopologyLocation::Right,117 _ => return Err(GameErr::InvalidOrientation(orient as u8))118 };119 Ok(res)120 }121122 fn get_info(&self, face: u8, pos: u8, orientation: cubios::TopologyOrientation) -> Result<(u32, u32), GameErr> {123 let mut info = cubios::TopologyFaceletInfo {124 module: 0xff,125 screen: 0xff,126 connected: 0127 };128 topology::get_facelet(face as u32, pos as u32, orientation, &mut info);129130 if info.module == 0xff || info.screen == 0xff {131 return Err(GameErr::InvalidModule(info.module as u8, info.screen as u8));132 }133 Ok((info.module as u32, info.screen as u32))134 }135136 fn get_info_dir(&self, module: u32, screen: u32, dir: cubios::TopologyNeighbour) -> Result<(u32, u32), GameErr> {137 let mut info = cubios::TopologyFaceletInfo {138 module: 0xff,139 screen: 0xff,140 connected: 0141 };142 topology::get_adjacent_facelet(module, screen, dir, &mut info);143144 if info.module == 0xff || info.screen == 0xff {145 return Err(GameErr::InvalidModule(info.module as u8, info.screen as u8));146 }147 Ok((info.module as u32, info.screen as u32))148 }149150 fn get_twist(&self) -> Result<(u8, u8), GameErr> {151 let mut twist_info = cubios::TopologyTwistInfo {152 screen: 0xff,153 direction: 0xff,154 count: 0xff,155 };156157 topology::get_twist(&mut twist_info);158159 if twist_info.screen == 0xff || twist_info.direction == 0xff {160 return Err(GameErr::InvalidTwist(twist_info.screen as u8, twist_info.direction as u8))161 }162163 let remap = match twist_info.screen {164 0 => 1,165 1 => 2,166 2 => 0,167 _ => return Err(GameErr::InvalidTwist(twist_info.screen as u8, twist_info.direction as u8))168 };169170 Ok((remap, twist_info.direction as u8))171 }172}173174#[allow(dead_code)]175pub trait Packable: Sized {176 fn to_pkt(&self, module: u8, screen: u8) -> [u8; 4];177 fn from_pkt(pkt: [u8; 4]) -> (Self, u8, u8);178}179180pub struct MapBase<T: Packable> {181 pub inited: bool,182 last_update_time: usize,183 pub screen_map: [Option<T>; 3],184 pub master_map: [[Option<T>; 3]; 8]185}186187pub struct SceneSwitch {188 last_update_time: usize,189190 pub scene_id: u8,191 pub scenes: &'static [usize],192 pub last_switch_time: usize,193}194195#[allow(dead_code)]196impl<T: Packable + Copy> MapBase<T> {197 pub fn new(val: T) -> Self {198 Self {199 inited: false,200 last_update_time: 0,201 screen_map: [Some(val); 3],202 master_map: [[Some(val); 3]; 8]203 }204 }205}206207#[allow(dead_code)]208pub trait Broadcastable {209 fn broadcast_part(&mut self, _module: u8, _screen: u8, _delay: usize) -> Result<(), GameErr> {210 Ok(())211 }212 fn broadcast(&mut self, delay: usize) -> Result<(), GameErr>;213214 fn recv(&mut self, pkt: [u8; 4]) -> Result<(), GameErr>;215}216217#[allow(dead_code)]218pub trait Shuffable {219 fn rotate(&mut self, dir: &RotationDir) -> Result<(), GameErr>;220 fn shuffle(&mut self, algo: &[RotationDir]) -> Result<(), GameErr>;221}222223impl<T: Packable + PartialEq + Debug> Broadcastable for MapBase<T> {224 fn broadcast_part(&mut self, module: u8, screen: u8, delay: usize) -> Result<(), GameErr> {225 if topology::get_cuben() != 0 || (comm::get_time() as usize - self.last_update_time < delay) {226 return Ok(());227 }228229 let pkt = self.master_map[module as usize][screen as usize].to_pkt(module, screen);230231 for i in 0..3 {232 comm::send_message(i, pkt.as_ptr(), 4);233 }234235 Ok(())236 }237238 fn broadcast(&mut self, delay: usize) -> Result<(), GameErr> {239 if topology::get_cuben() != 0 || (comm::get_time() as usize - self.last_update_time < delay) {240 return Ok(());241 }242243 for module in 1..8 {244 for screen in 0..3 {245 self.broadcast_part(module, screen, delay)?;246 }247 }248 self.last_update_time = comm::get_time() as usize;249250 Ok(())251 }252253 fn recv(&mut self, pkt: [u8; 4]) -> Result<(), GameErr> {254 match pkt[0] {255 v if [GamePkt::SetMap as u8, GamePkt::SetNone as u8].contains(&v) => {256 let (val, module, screen) = Option::<T>::from_pkt(pkt);257258 if module != topology::get_cuben() as u8 || screen >= 3 {259 return Ok(());260 }261262 self.screen_map[screen as usize] = val;263264 if !self.screen_map.iter().any(|e| e.is_none()) {265 self.inited = true;266 }267 }268 _ => ()269 }270 Ok(())271 }272}273274#[allow(dead_code)]275impl<T: Packable> Mappable for MapBase<T> {}276277#[allow(dead_code)]278impl<T: Packable + PartialEq + Copy> Shuffable for MapBase<T> {279 fn rotate(&mut self, dir: &RotationDir) -> Result<(), GameErr> {280 if topology::get_cuben() != 0 {281 return Ok(());282 }283284 let (rot_face, rot_offs) = match dir {285 RotationDir::Forward => (2, 1),286 RotationDir::Backward => (2, 3),287 RotationDir::Right => (1, 1),288 RotationDir::Left => (1, 3)289 };290291 // get rotation face292 let (face, pos) = self.get_place(0, rot_face, cubios::TopologyOrientation::Menu)?;293 let left_face = topology::get_reversed_face(face as u32).ok_or(GameErr::InvalidPlace(face as u8, pos as u8))? as u8;294295 // save map296 let mut tmp = Box::new([([None; 3], (0, 0)); 4]);297298 for i in 0..4 {299 let (module, screen) = self.get_info(left_face, i, cubios::TopologyOrientation::Menu)?;300 tmp[i as usize] = (self.master_map[module as usize], (module, screen));301 }302303 // rotate304 for i in 0..4 {305 let offs = (i as usize + rot_offs) % 4;306307 let (module, screen) = self.get_info(left_face, i, cubios::TopologyOrientation::Menu)?;308 let (_, right_screen) = self.get_info_dir(module, screen, cubios::TopologyNeighbour::Right)?;309 let (_, bottom_screen) = self.get_info_dir(module, screen, cubios::TopologyNeighbour::Bottom)?;310311 let (next_module, next_screen) = tmp[offs].1;312 let (_, next_right_screen) = self.get_info_dir(next_module, next_screen, cubios::TopologyNeighbour::Right)?;313 let (_, next_bottom_screen) = self.get_info_dir(next_module, next_screen, cubios::TopologyNeighbour::Bottom)?;314315 self.master_map[module as usize][screen as usize] = tmp[offs].0[next_screen as usize];316 self.master_map[module as usize][right_screen as usize] = tmp[offs].0[next_right_screen as usize];317 self.master_map[module as usize][bottom_screen as usize] = tmp[offs].0[next_bottom_screen as usize];318 }319320 Ok(())321 }322323 fn shuffle(&mut self, algo: &[RotationDir]) -> Result<(), GameErr> {324 if topology::get_cuben() != 0 {325 return Ok(());326 }327328 for mv in algo {329 self.rotate(mv)?;330 }331 Ok(())332 }333}334335#[allow(dead_code)]336impl<T: Packable + Copy> Default for MapBase<T> {337 fn default() -> Self {338 MapBase {339 inited: false,340 last_update_time: 0,341 screen_map: [None; 3],342 master_map: [[None; 3]; 8]343 }344 }345}346347#[allow(dead_code)]348impl<T: Packable> Packable for Option<T> {349 fn from_pkt(pkt: [u8; 4]) -> (Self, u8, u8) {350 if pkt[0] == GamePkt::SetNone as u8 {351 return (None, pkt[1], pkt[2])352 }353354 let (obj, module, screen) = T::from_pkt(pkt);355 (Some(obj), module, screen)356 }357358 fn to_pkt(&self, module: u8, screen: u8) -> [u8; 4] {359 match self {360 Some(v) => v.to_pkt(module, screen),361 None => [362 GamePkt::SetNone as u8,363 module,364 screen,365 0366 ]367 }368 }369}370371#[allow(dead_code)]372impl<T: Default> Default for Anim<T> {373 fn default() -> Self {374 Anim {375 val: Default::default(),376 anim: 100,377 step: 1,378 cycle: false,379 enable: true,380 }381 }382}383384#[allow(dead_code)]385impl Packable for u8 {386 fn to_pkt(&self, module: u8, screen: u8) -> [u8; 4] {387 [388 GamePkt::SetMap as u8,389 module,390 screen,391 self.clone()392 ]393 }394395 fn from_pkt(pkt: [u8; 4]) -> (Self, u8, u8) {396 (pkt[3], pkt[1], pkt[2])397 }398}399400#[allow(dead_code)]401impl Packable for (u8, u8) {402 fn to_pkt(&self, module: u8, screen: u8) -> [u8; 4] {403 [404 GamePkt::SetMap as u8,405 (module & 0xf) | (screen << 4),406 self.0,407 self.1408 ]409 }410411 fn from_pkt(pkt: [u8; 4]) -> (Self, u8, u8) {412 let module = pkt[1] & 0xf;413 let screen = (pkt[1] >> 4) & 0xf;414415 ((pkt[2], pkt[3]), module, screen)416 }417}418419#[allow(dead_code)]420impl Broadcastable for SceneSwitch {421 fn broadcast(&mut self, delay: usize) -> Result<(), GameErr> {422 if topology::get_cuben() != 0 || (comm::get_time() as usize - self.last_update_time < delay) {423 return Ok(());424 }425426 self.last_update_time = comm::get_time() as usize;427428 let pkt = [429 GamePkt::SetScene as u8,430 self.scene_id,431 0,432 0433 ];434435 for i in 0..3 {436 comm::send_message(i, pkt.as_ptr(), 4);437 }438 Ok(())439 }440441 fn recv(&mut self, pkt: [u8; 4]) -> Result<(), GameErr> {442 match pkt[0] {443 v if v == GamePkt::SetScene as u8 => self.set_scene(pkt[1]),444 _ => Ok(())445 }446 }447}448449#[allow(dead_code)]450impl SceneSwitch {451 pub fn new(scenes: &'static [usize], start_time: usize) -> Self {452 Self {453 last_update_time: 0,454455 scene_id: 0,456 scenes,457 last_switch_time: start_time,458 }459 }460461 pub fn next_scene(&mut self) {462 if topology::get_cuben() != 0 {463 return;464 }465466 self.last_switch_time = comm::get_time() as usize;467 self.scene_id = (self.scene_id + 1) % self.scenes.len() as u8;468 }469470 pub fn set_scene(&mut self, id: u8) -> Result<(), GameErr> {471 if id >= self.scenes.len() as u8 {472 return Err(GameErr::SceneNotFound(id))473 }474475 if id == self.scene_id {476 return Ok(())477 }478479 self.last_switch_time = comm::get_time() as usize;480 self.scene_id = id;481482 Ok(())483 }484}485486#[allow(dead_code)]487impl<T> Anim<T> {488 pub fn animate(&mut self) {489 if !self.enable {490 return;491 }492493 if self.anim <= 100 {494 self.anim += self.step;495 }496497 self.anim = self.anim.min(100);498499 if self.cycle {500 self.anim %= 100;501 }502 }503}504505506// entry507pub fn game_init<T: Game>(game: &mut T, cid: u32) {508 cubios::on_init(cid);509510 while let Err(_e) = game.on_init() {511 comm::log_e("on_init: failed to initialize game!");512 }513}514515pub fn game_run<T: Game>(game: &mut T) {516 let event_list = cubios::event::get_list();517518 // events519 if (cubios::event::Event::ON_CLOSE as i32 & event_list) != 0 {520 comm::log_e("exit\n");521 return;522 }523524 if (cubios::event::Event::ON_NET_UART0_RX as i32 & event_list) != 0 {525 if let Err(_e) = game.on_rx(0) {526 // log_e(format!("on_rx:1: {:?}", e).as_str()); // issue with WASM compilation527 comm::log_e("on_rx:0: failed to handle!");528 }529 }530531 if (cubios::event::Event::ON_NET_UART1_RX as i32 & event_list) != 0 {532 if let Err(_e) = game.on_rx(1) {533 // comm::log_e(format!("on_rx:1: {:?}", e).as_str()); // issue with WASM compilation534 comm::log_e("on_rx:1: failed to handle!");535 }536 }537538 if (cubios::event::Event::ON_NET_UART2_RX as i32 & event_list) != 0 {539 if let Err(_e) = game.on_rx(2) {540 // comm::log_e(format!("on_rx:2: {:?}", e).as_str()); // issue with WASM compilation541 comm::log_e("on_rx:2: failed to handle!");542 }543 }544545 if (cubios::event::Event::ON_PHYSICAL_TICK as i32 & event_list) != 0 {546 if let Err(_e) = game.on_phys_tick() {547 // comm::log_e(format!("on_phys_tick: {:?}", e).as_str()); // issue with WASM compilation548 comm::log_e("on_phys_tick: failed to handle!");549 }550 }551552 if (cubios::event::Event::ON_TWIST as i32 & event_list) != 0 {553 if let Err(_e) = game.on_twist() {554 // comm::log_e(format!("on_twist: {:?}", e).as_str()); // issue with WASM compilation555 comm::log_e("on_twist: failed to handle!");556 }557 }558559 if (cubios::event::Event::ON_PAT as i32 & event_list) != 0 {560 if let Err(_e) = game.on_pat() {561 // comm::log_e(format!("on_pat: {:?}", e).as_str()); // issue with WASM compilation562 comm::log_e("on_pat: failed to handle!");563 }564 }565566 // mandatory events567 if let Err(_e) = game.on_tick() {568 // comm::log_e(format!("on_tick: {:?}", e).as_str()); // issue with WASM compilation569 comm::log_e("on_tick: failed to handle!");570 }571572 if let Err(_e) = game.on_render() {573 // comm::log_e(format!("on_render: {:?}", e).as_str()); // issue with WASM compilation574 comm::log_e("on_render: failed to handle!");575 }576}577
Wrapped for easier reading. Turn wrap off to inspect exact line lengths.