Added a read_maybe_null_ascii_string to game::util.

Added information to `Decks`.
All decks are now read with `game::deck::Table`.
This commit is contained in:
2020-05-01 14:08:13 +01:00
parent 8dffe82143
commit a1c9867ccb
3 changed files with 124 additions and 30 deletions

View File

@@ -1,8 +1,86 @@
//! Decks
// byteorder
use byteorder::{ByteOrder, LittleEndian};
// Crate
use crate::game::{util, Bytes};
/// A deck
#[derive(Debug)]
#[derive(::serde::Serialize, ::serde::Deserialize)]
pub struct Deck {
/// Name of this deck
pub name: ascii::AsciiString,
/// Digimon who plays this deck
pub owner: ascii::AsciiString,
/// All of the card ids that make up this deck
pub cards: [u16; 30],
}
/// Error type for [`Bytes::from_bytes`]
#[derive(Debug, derive_more::Display, err_impl::Error)]
pub enum FromBytesError {
/// Unable to read the deck name
#[display(fmt = "Unable to read the deck name")]
Name(#[error(source)] util::ReadMaybeNullAsciiStringError),
/// Unable to read the deck owner
#[display(fmt = "Unable to read the deck owner")]
Owner(#[error(source)] util::ReadMaybeNullAsciiStringError),
}
/// Error type for [`Bytes::to_bytes`]
#[derive(Debug, derive_more::Display, err_impl::Error)]
pub enum ToBytesError {
/// Unable to write the deck name
#[display(fmt = "Unable to write the deck name")]
Name(#[error(source)] util::WriteNullAsciiStringError),
/// Unable to write the deck owner
#[display(fmt = "Unable to write the deck owner")]
Owner(#[error(source)] util::WriteNullAsciiStringError),
}
impl Bytes for Deck {
type ByteArray = [u8; 0x6e];
type FromError = FromBytesError;
type ToError = ToBytesError;
fn from_bytes(bytes: &Self::ByteArray) -> Result<Self, Self::FromError> {
// Split the bytes
let bytes = util::array_split!(&bytes,
deck : [0x3c],
name : [0x13],
owner: [0x13],
_unknown: [0xc],
);
Ok(Self {
name: util::read_maybe_null_ascii_string(bytes.name)
.map_err(FromBytesError::Name)?
.to_ascii_string(),
owner: util::read_maybe_null_ascii_string(bytes.owner)
.map_err(FromBytesError::Owner)?
.to_ascii_string(),
cards: {
let mut cards_buf = [0; 0x1e];
for (card_id, card) in cards_buf.iter_mut().enumerate() {
*card = LittleEndian::read_u16(&bytes.deck[0x0 + card_id * 2..0x2 + card_id * 2]);
}
cards_buf
},
})
}
fn to_bytes(&self, _bytes: &mut Self::ByteArray) -> Result<(), Self::ToError> {
todo!();
}
}

View File

@@ -3,12 +3,9 @@
// Std
use std::io::{Read, Seek, Write};
// byteorder
use byteorder::{ByteOrder, LittleEndian};
// Crate
use crate::{
game::Deck,
game::{deck::deck, Bytes, Deck},
io::{address::Data, GameFile},
};
@@ -41,14 +38,22 @@ pub enum DeserializeError {
/// Unable to read table header
#[display(fmt = "Unable to read table header")]
ReadHeader(#[error(source)] std::io::Error),
/*
/// The magic of the table was wrong
#[display(fmt = "Found wrong table header magic (expected {:x}, found {:x})", Table::HEADER_MAGIC, "magic")]
HeaderMagic { magic: u32 },
*/
/// Could not read a deck entry from the deck table
#[display(fmt = "Unable to fully read a deck entry (The file was too small)")]
DeckEntry(#[error(source)] std::io::Error),
/// Could not read a deck entry
#[display(fmt = "Unable to read deck entry with id {}", "id")]
ReadDeck {
id: usize,
#[error(source)]
err: std::io::Error,
},
/// Could not parse a deck entry
#[display(fmt = "Unable to parse deck entry with id {}", "id")]
ParseDeck {
id: usize,
#[error(source)]
err: deck::FromBytesError,
},
}
impl Table {
@@ -64,25 +69,14 @@ impl Table {
.seek(std::io::SeekFrom::Start(u64::from(Self::DECK_TABLE_START_ADDRESS)))
.map_err(DeserializeError::Seek)?;
// Then loop until we're at the end of the table
//'table_loop: loop
for _ in 0..100 {
// Read the deck
let mut buf = [0u8; 110];
game_file.read_exact(&mut buf).map_err(DeserializeError::DeckEntry)?;
// Then get each deck
for id in 0..159 {
// Read all bytes of the deck
let mut bytes = [0; 0x6e];
game_file.read_exact(&mut bytes).map_err(|err| DeserializeError::ReadDeck { id, err })?;
// And construct the deck
let deck = Deck {
cards: {
let mut cards_buf = [0u16; 30];
for card_id in 0..30 {
cards_buf[card_id] = LittleEndian::read_u16(&buf[0x0 + card_id * 2..0x2 + card_id * 2]);
}
cards_buf
},
};
// And try to serialize the deck
let deck = Deck::from_bytes(&bytes).map_err(|err| DeserializeError::ParseDeck { id, err })?;
// And add it
decks.push(deck);

View File

@@ -134,6 +134,28 @@ pub fn read_null_ascii_string(buf: &impl AsRef<[u8]>) -> Result<&ascii::AsciiStr
ascii::AsciiStr::from_ascii(buf).map_err(ReadNullAsciiStringError::NotAscii)
}
/// Error type for [`read_maybe_null_ascii_string`]
#[derive(Debug)]
#[derive(derive_more::Display, err_impl::Error)]
pub enum ReadMaybeNullAsciiStringError {
/// The string was not ascii
#[display(fmt = "The buffer did not contain valid Ascii")]
NotAscii(#[error(source)] ascii::AsAsciiStrError),
}
/// Reads a possibly null-terminated ascii string from a buffer.
pub fn read_maybe_null_ascii_string(buf: &impl AsRef<[u8]>) -> Result<&ascii::AsciiStr, ReadMaybeNullAsciiStringError> {
// Find the first null and trim the buffer until it
let buf = buf.as_ref();
let buf = match buf.iter().position(|&b| b == 0) {
Some(null_idx) => &buf[0..null_idx],
None => buf,
};
// Then convert it from Ascii
ascii::AsciiStr::from_ascii(buf).map_err(ReadMaybeNullAsciiStringError::NotAscii)
}
/// Error type for [`write_null_ascii_string`]
#[derive(Debug)]
#[derive(derive_more::Display, err_impl::Error)]