mirror of
https://github.com/Zenithsiz/dcb.git
synced 2026-02-06 17:35:40 +00:00
Added bounds on the Bytes error types.
Started using `err-impl`, fork of `err-derive` that does not implement `Display` or `From`.
This commit is contained in:
parent
18e68dc0c6
commit
e943819853
@ -17,3 +17,4 @@ serde = { version = "1.0", features = ["derive"] }
|
||||
|
||||
# Derives
|
||||
derive_more = "0.99"
|
||||
err-impl = { path = "../err-impl" }
|
||||
|
||||
@ -9,13 +9,13 @@ where
|
||||
const BUF_BYTE_SIZE: usize;
|
||||
|
||||
/// The error type used for the operation
|
||||
type FromError;
|
||||
type FromError: std::fmt::Debug + std::error::Error;
|
||||
|
||||
/// Reads `bytes` and returns a result with `Self`
|
||||
fn from_bytes(bytes: &[u8]) -> Result<Self, Self::FromError>;
|
||||
|
||||
/// The error type used for the operation
|
||||
type ToError;
|
||||
type ToError: std::fmt::Debug + std::error::Error;
|
||||
|
||||
/// Writes bytes into `bytes` from self
|
||||
fn to_bytes(&self, bytes: &mut [u8]) -> Result<(), Self::ToError>;
|
||||
|
||||
@ -14,5 +14,4 @@ pub mod table;
|
||||
pub use digimon ::Digimon;
|
||||
pub use item ::Item;
|
||||
pub use digivolve::Digivolve;
|
||||
|
||||
pub use table::Table;
|
||||
|
||||
@ -7,13 +7,13 @@
|
||||
//!
|
||||
//! | Offset | Size | Type | Name | Location | Details |
|
||||
//! |--------|------|----------------------|---------------------------|--------------------------------|-------------------------------------------------------------------------------------|
|
||||
//! | 0x0 | 0x15 | `char[0x15]` | Name | `basic.name` | |
|
||||
//! | 0x15 | 0x2 | `u16` | Unknown | `basic.unknown_1` | Most likely contains the digimon's model |
|
||||
//! | 0x17 | 0x1 | `u8` | Speciality & Level | `basic.speciality basic.level` | The bottom nibble of this byte is the level, while the top nibble is the speciality |
|
||||
//! | 0x18 | 0x1 | `u8` | DP | `basic.dp_cost` | |
|
||||
//! | 0x19 | 0x1 | `u8` | +P | `basic.dp_give` | |
|
||||
//! | 0x1a | 0x1 | `u8` | Unknown | `basic.unknown_0` | Is` 0` for all digimon |
|
||||
//! | 0x1b | 0x2 | `u16` | Health | `basic.hp` | |
|
||||
//! | 0x0 | 0x15 | `char[0x15]` | Name | `name` | |
|
||||
//! | 0x15 | 0x2 | `u16` | Unknown | `unknown_1` | Most likely contains the digimon's model |
|
||||
//! | 0x17 | 0x1 | `u8` | Speciality & Level | `speciality level` | The bottom nibble of this byte is the level, while the top nibble is the speciality |
|
||||
//! | 0x18 | 0x1 | `u8` | DP | `dp_cost` | |
|
||||
//! | 0x19 | 0x1 | `u8` | +P | `dp_give` | |
|
||||
//! | 0x1a | 0x1 | `u8` | Unknown | `unknown_0` | Is` 0` for all digimon |
|
||||
//! | 0x1b | 0x2 | `u16` | Health | `hp` | |
|
||||
//! | 0x1d | 0x1c | [`Move`] | Circle Move | `moves.circle` | |
|
||||
//! | 0x39 | 0x1c | [`Move`] | Triangle move | `moves.triangle` | |
|
||||
//! | 0x55 | 0x1c | [`Move`] | Cross move | `moves.cross` | |
|
||||
@ -39,26 +39,12 @@ use crate::game::{
|
||||
}
|
||||
};
|
||||
|
||||
/// A digimon card
|
||||
/// The digimon card itself
|
||||
#[derive(PartialEq, Eq, Clone, Hash, Debug)]
|
||||
#[derive(serde::Serialize, serde::Deserialize)]
|
||||
pub struct Digimon
|
||||
{
|
||||
/// The basic info of the digimon
|
||||
pub basic: Basic,
|
||||
|
||||
/// The moves
|
||||
pub moves: Moves,
|
||||
|
||||
/// The support
|
||||
pub support: Support,
|
||||
}
|
||||
|
||||
/// The basic properties of a digimon
|
||||
#[derive(PartialEq, Eq, Clone, Hash, Debug)]
|
||||
#[derive(serde::Serialize, serde::Deserialize)]
|
||||
pub struct Basic
|
||||
{
|
||||
/// The digimon's name
|
||||
pub name: String,
|
||||
pub speciality: Speciality,
|
||||
pub level: Level,
|
||||
@ -73,6 +59,12 @@ pub struct Basic
|
||||
// Unknown fields
|
||||
pub unknown_0: u8,
|
||||
pub unknown_1: u16,
|
||||
|
||||
/// The moves
|
||||
pub moves: Moves,
|
||||
|
||||
/// The support
|
||||
pub support: Support,
|
||||
}
|
||||
|
||||
/// The moves a digimon has
|
||||
@ -94,38 +86,23 @@ pub struct Support
|
||||
pub unknown: u8,
|
||||
|
||||
/// The cross move effect
|
||||
#[serde(default)]
|
||||
pub cross_move: Option<CrossMoveEffect>,
|
||||
|
||||
/// The effect description
|
||||
pub description: [String; 4],
|
||||
|
||||
/// The effect arrow color
|
||||
#[serde(default)]
|
||||
pub arrow_color: Option<ArrowColor>,
|
||||
|
||||
/// The effect conditions
|
||||
pub conditions: SupportConditions,
|
||||
#[serde(default)]
|
||||
pub conditions: [Option<SupportCondition>; 2],
|
||||
|
||||
/// The effects themselves
|
||||
pub effects: SupportSupport,
|
||||
}
|
||||
|
||||
/// All of the support effects
|
||||
#[derive(PartialEq, Eq, Clone, Copy, Hash, Debug)]
|
||||
#[derive(serde::Serialize, serde::Deserialize)]
|
||||
pub struct SupportSupport
|
||||
{
|
||||
pub first : Option<SupportEffect>,
|
||||
pub second: Option<SupportEffect>,
|
||||
pub third : Option<SupportEffect>,
|
||||
}
|
||||
|
||||
/// All of the support effect conditions
|
||||
#[derive(PartialEq, Eq, Clone, Copy, Hash, Debug)]
|
||||
#[derive(serde::Serialize, serde::Deserialize)]
|
||||
pub struct SupportConditions
|
||||
{
|
||||
pub first : Option<SupportCondition>,
|
||||
pub second: Option<SupportCondition>,
|
||||
#[serde(default)]
|
||||
pub effects: [Option<SupportEffect>; 3],
|
||||
}
|
||||
|
||||
/// The error type thrown by [`FromBytes`]
|
||||
@ -140,8 +117,6 @@ pub enum FromBytesError
|
||||
#[display(fmt = "The {} support effect description could not be converted to a string", rank)]
|
||||
SupportEffectDescriptionToString {
|
||||
rank: &'static str,
|
||||
|
||||
|
||||
err: util::ReadNullTerminatedStringError,
|
||||
},
|
||||
|
||||
@ -165,8 +140,6 @@ pub enum FromBytesError
|
||||
#[display(fmt = "Unable to read the {0} support effect condition", rank)]
|
||||
SupportCondition {
|
||||
rank: &'static str,
|
||||
|
||||
|
||||
err: crate::game::card::property::support_condition::FromBytesError,
|
||||
},
|
||||
|
||||
@ -174,8 +147,6 @@ pub enum FromBytesError
|
||||
#[display(fmt = "Unable to read the {} support effect", rank)]
|
||||
SupportEffect {
|
||||
rank: &'static str,
|
||||
|
||||
|
||||
err: crate::game::card::property::support_effect::FromBytesError,
|
||||
},
|
||||
|
||||
@ -183,12 +154,26 @@ pub enum FromBytesError
|
||||
#[display(fmt = "Unable to read the {} move", name)]
|
||||
Move {
|
||||
name: &'static str,
|
||||
|
||||
|
||||
err: crate::game::card::property::moves::FromBytesError,
|
||||
},
|
||||
}
|
||||
|
||||
impl std::error::Error for FromBytesError {
|
||||
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
|
||||
match self {
|
||||
Self::NameToString(err) |
|
||||
Self::SupportEffectDescriptionToString{ err, .. } => Some(err),
|
||||
Self::UnknownSpeciality(err) => Some(err),
|
||||
Self::UnknownLevel(err) => Some(err),
|
||||
Self::UnknownEffectArrowColor(err) => Some(err),
|
||||
Self::UnknownCrossMoveEffect(err) => Some(err),
|
||||
Self::SupportCondition{err, ..} => Some(err),
|
||||
Self::SupportEffect{err, ..} => Some(err),
|
||||
Self::Move{err, ..} => Some(err),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The error type thrown by `ToBytes`
|
||||
#[derive(Debug, derive_more::Display)]
|
||||
pub enum ToBytesError
|
||||
@ -197,8 +182,6 @@ pub enum ToBytesError
|
||||
#[display(fmt = r#"The name "{}" is too long to be written to file"#, name)]
|
||||
NameTooLong {
|
||||
name: String,
|
||||
|
||||
|
||||
err: crate::game::util::WriteNullTerminatedStringError,
|
||||
},
|
||||
|
||||
@ -208,15 +191,11 @@ pub enum ToBytesError
|
||||
name: String,
|
||||
},
|
||||
|
||||
|
||||
|
||||
/// A support effect description was too long to be written to file
|
||||
#[display(fmt = r#"The {0} support effect description "{1}" is too long to be written to file"#, rank, string)]
|
||||
SupportEffectDescriptionTooLong {
|
||||
string: String,
|
||||
rank: String,
|
||||
|
||||
|
||||
err: crate::game::util::WriteNullTerminatedStringError,
|
||||
},
|
||||
|
||||
@ -227,196 +206,199 @@ pub enum ToBytesError
|
||||
rank: String,
|
||||
},
|
||||
|
||||
|
||||
|
||||
/// Unable to write a move
|
||||
#[display(fmt = "Unable to write the {} move", name)]
|
||||
Move {
|
||||
name: &'static str,
|
||||
|
||||
|
||||
err: crate::game::card::property::moves::ToBytesError,
|
||||
},
|
||||
}
|
||||
|
||||
// Impl
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
// Bytes
|
||||
impl Bytes for Digimon
|
||||
{
|
||||
const BUF_BYTE_SIZE : usize = 0x138;
|
||||
|
||||
type FromError = FromBytesError;
|
||||
|
||||
fn from_bytes(bytes: &[u8]) -> Result<Self, Self::FromError>
|
||||
{
|
||||
// Note: We can't use `TryInto` because it only supports arrays up to 32
|
||||
// SAFETY: Safe as we checked the length
|
||||
assert!(bytes.len() == Self::BUF_BYTE_SIZE);
|
||||
let bytes: &[u8; Self::BUF_BYTE_SIZE] = unsafe {
|
||||
#[allow(clippy::as_conversions)]
|
||||
&*( bytes.as_ptr() as *const [u8; Self::BUF_BYTE_SIZE] )
|
||||
};
|
||||
impl std::error::Error for ToBytesError {
|
||||
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
|
||||
match self {
|
||||
Self::NameTooLong{err, ..} |
|
||||
Self::SupportEffectDescriptionTooLong{ err, .. } => Some(err),
|
||||
|
||||
// Return the struct after building it
|
||||
Ok( Self {
|
||||
// 0x0 - 0x1d
|
||||
basic: Basic {
|
||||
name : util::read_null_terminated_string( &bytes[0x0..0x15] ) .map_err(FromBytesError::NameToString)?.to_string(),
|
||||
unknown_1 : LittleEndian::read_u16( &bytes[0x15..0x17] ),
|
||||
speciality: Speciality::from_bytes( &[(bytes[0x17] & 0xF0) >> 4] ) .map_err(FromBytesError::UnknownSpeciality)?,
|
||||
level : Level::from_bytes( &[(bytes[0x17] & 0x0F) >> 0] ) .map_err(FromBytesError::UnknownLevel )?,
|
||||
dp_cost : bytes[0x18],
|
||||
dp_give : bytes[0x19],
|
||||
unknown_0 : bytes[0x1a],
|
||||
hp : LittleEndian::read_u16( &bytes[0x1b..0x1d] ),
|
||||
},
|
||||
|
||||
// 0x1d - 0x71
|
||||
moves: Moves {
|
||||
circle : Move::from_bytes( &bytes[0x1d..0x39] ) .map_err(|err| FromBytesError::Move{ name: "circle" , err })?,
|
||||
triangle: Move::from_bytes( &bytes[0x39..0x55] ) .map_err(|err| FromBytesError::Move{ name: "triangle", err })?,
|
||||
cross : Move::from_bytes( &bytes[0x55..0x71] ) .map_err(|err| FromBytesError::Move{ name: "cross" , err })?,
|
||||
},
|
||||
|
||||
// 0x71 - 0x138
|
||||
support: Support {
|
||||
conditions: SupportConditions {
|
||||
first: if bytes[0x73] != 0 { Some(
|
||||
SupportCondition::from_bytes( &bytes[0x71..0x91] ) .map_err(|err| FromBytesError::SupportCondition{ rank: "1st", err })?
|
||||
)} else { None },
|
||||
|
||||
second: if bytes[0x93] != 0 { Some(
|
||||
SupportCondition::from_bytes( &bytes[0x91..0xb1] ) .map_err(|err| FromBytesError::SupportCondition{ rank: "2nd", err })?
|
||||
)} else { None },
|
||||
},
|
||||
|
||||
effects: SupportSupport {
|
||||
first: if bytes[0xb1] != 0 { Some(
|
||||
SupportEffect::from_bytes( &bytes[0xb1..0xc1] ) .map_err(|err| FromBytesError::SupportEffect{ rank: "1st", err })?
|
||||
)} else { None },
|
||||
|
||||
second: if bytes[0xc1] != 0 { Some(
|
||||
SupportEffect::from_bytes( &bytes[0xc1..0xd1] ) .map_err(|err| FromBytesError::SupportEffect{ rank: "2nd", err })?
|
||||
)} else { None },
|
||||
|
||||
third: if bytes[0xd1] != 0 { Some(
|
||||
SupportEffect::from_bytes( &bytes[0xd1..0xe1] ) .map_err(|err| FromBytesError::SupportEffect{ rank: "3rd", err })?
|
||||
)} else { None },
|
||||
},
|
||||
|
||||
cross_move: if bytes[0xe1] != 0 { Some(
|
||||
CrossMoveEffect::from_bytes( &[ bytes[0xe1] ] ) .map_err(FromBytesError::UnknownCrossMoveEffect)?
|
||||
)} else { None },
|
||||
|
||||
unknown: bytes[0xe2],
|
||||
|
||||
arrow_color: if bytes[0xe3] != 0 {
|
||||
Some( ArrowColor::from_bytes( &bytes[0xe3..0xe4] ) .map_err(FromBytesError::UnknownEffectArrowColor)? )
|
||||
} else { None },
|
||||
|
||||
description: [
|
||||
util::read_null_terminated_string( &bytes[0x0e4..0x0f9] ) .map_err(|err| FromBytesError::SupportEffectDescriptionToString{ rank: "1st", err })?.to_string(),
|
||||
util::read_null_terminated_string( &bytes[0x0f9..0x10e] ) .map_err(|err| FromBytesError::SupportEffectDescriptionToString{ rank: "2nd", err })?.to_string(),
|
||||
util::read_null_terminated_string( &bytes[0x10e..0x123] ) .map_err(|err| FromBytesError::SupportEffectDescriptionToString{ rank: "3rd", err })?.to_string(),
|
||||
util::read_null_terminated_string( &bytes[0x123..0x138] ) .map_err(|err| FromBytesError::SupportEffectDescriptionToString{ rank: "4th", err })?.to_string(),
|
||||
],
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
type ToError = ToBytesError;
|
||||
|
||||
fn to_bytes(&self, bytes: &mut [u8]) -> Result<(), Self::ToError>
|
||||
{
|
||||
// Basic
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
// Name
|
||||
// If it's not valid ascii, return Err
|
||||
// If we cannot write it to the buffer, return Err
|
||||
if !self.basic.name.chars().all(|c| c.is_ascii() && !c.is_ascii_control()) { return Err( ToBytesError::NameNotAscii{name: self.basic.name.clone()} ); }
|
||||
bytes[0x0..0x15].copy_from_slice(
|
||||
util::write_null_terminated_string(&self.basic.name, &mut [0u8; 0x15])
|
||||
.map_err(|err| ToBytesError::NameTooLong{ name: self.basic.name.clone(), err })?
|
||||
);
|
||||
|
||||
// Unknown 1
|
||||
LittleEndian::write_u16(&mut bytes[0x15..0x17], self.basic.unknown_1);
|
||||
|
||||
// Speciality / Level
|
||||
{
|
||||
let (mut speciality_byte, mut level_byte) = ( [0u8], [0u8] );
|
||||
|
||||
self.basic.speciality.to_bytes(&mut speciality_byte)?;
|
||||
self.basic.level .to_bytes(&mut level_byte)?;
|
||||
|
||||
// Merge them
|
||||
bytes[0x17] = (speciality_byte[0] << 4) | level_byte[0];
|
||||
}
|
||||
|
||||
// DP / +P
|
||||
bytes[0x18] = self.basic.dp_cost;
|
||||
bytes[0x19] = self.basic.dp_give;
|
||||
|
||||
// Unknown
|
||||
bytes[0x1a] = self.basic.unknown_0;
|
||||
|
||||
// Health
|
||||
LittleEndian::write_u16(&mut bytes[0x1b..0x1d], self.basic.hp);
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
|
||||
// Moves
|
||||
self.moves.circle .to_bytes(&mut bytes[0x1d..0x39]).map_err(|err| ToBytesError::Move{ name: "circle" , err })?;
|
||||
self.moves.triangle.to_bytes(&mut bytes[0x39..0x55]).map_err(|err| ToBytesError::Move{ name: "triangle", err })?;
|
||||
self.moves.cross .to_bytes(&mut bytes[0x55..0x71]).map_err(|err| ToBytesError::Move{ name: "cross" , err })?;
|
||||
|
||||
// Support
|
||||
// Note: Although support conditions and effects aren't written if they're None,
|
||||
// a bit pattern of all 0s is a valid pattern and means "None" to the game.
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
// Support conditions
|
||||
if let Some(support_condition) = &self.support.conditions.first { support_condition.to_bytes(&mut bytes[0x71..0x91])?; }
|
||||
if let Some(support_condition) = &self.support.conditions.second { support_condition.to_bytes(&mut bytes[0x91..0xb1])?; }
|
||||
|
||||
// Support effects
|
||||
if let Some(support_effect) = &self.support.effects.first { support_effect.to_bytes(&mut bytes[0xb1..0xc1])?; }
|
||||
if let Some(support_effect) = &self.support.effects.second { support_effect.to_bytes(&mut bytes[0xc1..0xd1])?; }
|
||||
if let Some(support_effect) = &self.support.effects.third { support_effect.to_bytes(&mut bytes[0xd1..0xe1])?; }
|
||||
|
||||
// Cross move
|
||||
if let Some(cross_move) = self.support.cross_move { cross_move.to_bytes(&mut bytes[0xe1..0xe2])? };
|
||||
|
||||
// Unknown
|
||||
bytes[0xe2] = self.support.unknown;
|
||||
|
||||
// Support arrow color
|
||||
if let Some(arrow_color) = self.support.arrow_color { arrow_color.to_bytes( &mut bytes[0xe3..0xe4] )?; }
|
||||
|
||||
// Write the support effects
|
||||
for (index, line) in self.support.description.iter().enumerate()
|
||||
{
|
||||
// If it's not valid ascii, return Err
|
||||
if !line.chars().all(|c| c.is_ascii() && !c.is_ascii_control()) {
|
||||
return Err( ToBytesError::SupportEffectDescriptionNotAscii{
|
||||
name: line.clone(),
|
||||
rank: util::as_ordinal((index+1) as u64),
|
||||
});
|
||||
}
|
||||
|
||||
// If we cannot write it to the buffer, return Err
|
||||
bytes[0x0e4 + (0x15 * index) .. 0x0f9 + (0x15 * index)].copy_from_slice(
|
||||
util::write_null_terminated_string(line, &mut [0u8; 0x15])
|
||||
.map_err(|err| ToBytesError::SupportEffectDescriptionTooLong {
|
||||
string: line.clone(),
|
||||
rank: util::as_ordinal((index+1) as u64),
|
||||
err
|
||||
})?
|
||||
);
|
||||
}
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
|
||||
// Return Ok
|
||||
Ok(())
|
||||
Self::NameNotAscii{ .. } |
|
||||
Self::SupportEffectDescriptionNotAscii{ .. } => None,
|
||||
Self::Move{err, ..} => Some(err),
|
||||
}
|
||||
}
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
impl Bytes for Digimon
|
||||
{
|
||||
const BUF_BYTE_SIZE : usize = 0x138;
|
||||
|
||||
type FromError = FromBytesError;
|
||||
|
||||
fn from_bytes(bytes: &[u8]) -> Result<Self, Self::FromError>
|
||||
{
|
||||
// Note: We can't use `TryInto` because it only supports arrays up to 32
|
||||
// SAFETY: Safe as we checked the length
|
||||
assert!(bytes.len() == Self::BUF_BYTE_SIZE);
|
||||
let bytes: &[u8; Self::BUF_BYTE_SIZE] = unsafe {
|
||||
#[allow(clippy::as_conversions)]
|
||||
&*( bytes.as_ptr() as *const [u8; Self::BUF_BYTE_SIZE] )
|
||||
};
|
||||
|
||||
// Return the struct after building it
|
||||
Ok( Self {
|
||||
// 0x0 - 0x1d
|
||||
name : util::read_null_terminated_string( &bytes[0x0..0x15] ) .map_err(FromBytesError::NameToString)?.to_string(),
|
||||
unknown_1 : LittleEndian::read_u16( &bytes[0x15..0x17] ),
|
||||
speciality: Speciality::from_bytes( &[(bytes[0x17] & 0xF0) >> 4] ) .map_err(FromBytesError::UnknownSpeciality)?,
|
||||
level : Level::from_bytes( &[(bytes[0x17] & 0x0F) >> 0] ) .map_err(FromBytesError::UnknownLevel )?,
|
||||
dp_cost : bytes[0x18],
|
||||
dp_give : bytes[0x19],
|
||||
unknown_0 : bytes[0x1a],
|
||||
hp : LittleEndian::read_u16( &bytes[0x1b..0x1d] ),
|
||||
|
||||
// 0x1d - 0x71
|
||||
moves: Moves {
|
||||
circle : Move::from_bytes( &bytes[0x1d..0x39] ) .map_err(|err| FromBytesError::Move{ name: "circle" , err })?,
|
||||
triangle: Move::from_bytes( &bytes[0x39..0x55] ) .map_err(|err| FromBytesError::Move{ name: "triangle", err })?,
|
||||
cross : Move::from_bytes( &bytes[0x55..0x71] ) .map_err(|err| FromBytesError::Move{ name: "cross" , err })?,
|
||||
},
|
||||
|
||||
// 0x71 - 0x138
|
||||
support: Support {
|
||||
conditions: [
|
||||
if bytes[0x73] != 0 { Some(
|
||||
SupportCondition::from_bytes( &bytes[0x71..0x91] ) .map_err(|err| FromBytesError::SupportCondition{ rank: "1st", err })?
|
||||
)} else { None },
|
||||
|
||||
if bytes[0x93] != 0 { Some(
|
||||
SupportCondition::from_bytes( &bytes[0x91..0xb1] ) .map_err(|err| FromBytesError::SupportCondition{ rank: "2nd", err })?
|
||||
)} else { None },
|
||||
],
|
||||
|
||||
effects: [
|
||||
if bytes[0xb1] != 0 { Some(
|
||||
SupportEffect::from_bytes( &bytes[0xb1..0xc1] ) .map_err(|err| FromBytesError::SupportEffect{ rank: "1st", err })?
|
||||
)} else { None },
|
||||
|
||||
if bytes[0xc1] != 0 { Some(
|
||||
SupportEffect::from_bytes( &bytes[0xc1..0xd1] ) .map_err(|err| FromBytesError::SupportEffect{ rank: "2nd", err })?
|
||||
)} else { None },
|
||||
|
||||
if bytes[0xd1] != 0 { Some(
|
||||
SupportEffect::from_bytes( &bytes[0xd1..0xe1] ) .map_err(|err| FromBytesError::SupportEffect{ rank: "3rd", err })?
|
||||
)} else { None },
|
||||
],
|
||||
|
||||
cross_move: if bytes[0xe1] != 0 { Some(
|
||||
CrossMoveEffect::from_bytes( &[ bytes[0xe1] ] ) .map_err(FromBytesError::UnknownCrossMoveEffect)?
|
||||
)} else { None },
|
||||
|
||||
unknown: bytes[0xe2],
|
||||
|
||||
arrow_color: if bytes[0xe3] != 0 {
|
||||
Some( ArrowColor::from_bytes( &bytes[0xe3..0xe4] ) .map_err(FromBytesError::UnknownEffectArrowColor)? )
|
||||
} else { None },
|
||||
|
||||
description: [
|
||||
util::read_null_terminated_string( &bytes[0x0e4..0x0f9] ) .map_err(|err| FromBytesError::SupportEffectDescriptionToString{ rank: "1st", err })?.to_string(),
|
||||
util::read_null_terminated_string( &bytes[0x0f9..0x10e] ) .map_err(|err| FromBytesError::SupportEffectDescriptionToString{ rank: "2nd", err })?.to_string(),
|
||||
util::read_null_terminated_string( &bytes[0x10e..0x123] ) .map_err(|err| FromBytesError::SupportEffectDescriptionToString{ rank: "3rd", err })?.to_string(),
|
||||
util::read_null_terminated_string( &bytes[0x123..0x138] ) .map_err(|err| FromBytesError::SupportEffectDescriptionToString{ rank: "4th", err })?.to_string(),
|
||||
],
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
type ToError = ToBytesError;
|
||||
|
||||
fn to_bytes(&self, bytes: &mut [u8]) -> Result<(), Self::ToError>
|
||||
{
|
||||
// Basic
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
// Name
|
||||
// If it's not valid ascii, return Err
|
||||
// If we cannot write it to the buffer, return Err
|
||||
if !self.name.chars().all(|c| c.is_ascii() && !c.is_ascii_control()) { return Err( ToBytesError::NameNotAscii{name: self.name.clone()} ); }
|
||||
bytes[0x0..0x15].copy_from_slice(
|
||||
util::write_null_terminated_string(&self.name, &mut [0u8; 0x15])
|
||||
.map_err(|err| ToBytesError::NameTooLong{ name: self.name.clone(), err })?
|
||||
);
|
||||
|
||||
// Unknown 1
|
||||
LittleEndian::write_u16(&mut bytes[0x15..0x17], self.unknown_1);
|
||||
|
||||
// Speciality / Level
|
||||
{
|
||||
let (mut speciality_byte, mut level_byte) = ( [0u8], [0u8] );
|
||||
|
||||
self.speciality.to_bytes(&mut speciality_byte)?;
|
||||
self.level .to_bytes(&mut level_byte)?;
|
||||
|
||||
// Merge them
|
||||
bytes[0x17] = (speciality_byte[0] << 4) | level_byte[0];
|
||||
}
|
||||
|
||||
// DP / +P
|
||||
bytes[0x18] = self.dp_cost;
|
||||
bytes[0x19] = self.dp_give;
|
||||
|
||||
// Unknown
|
||||
bytes[0x1a] = self.unknown_0;
|
||||
|
||||
// Health
|
||||
LittleEndian::write_u16(&mut bytes[0x1b..0x1d], self.hp);
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
|
||||
// Moves
|
||||
self.moves.circle .to_bytes(&mut bytes[0x1d..0x39]).map_err(|err| ToBytesError::Move{ name: "circle" , err })?;
|
||||
self.moves.triangle.to_bytes(&mut bytes[0x39..0x55]).map_err(|err| ToBytesError::Move{ name: "triangle", err })?;
|
||||
self.moves.cross .to_bytes(&mut bytes[0x55..0x71]).map_err(|err| ToBytesError::Move{ name: "cross" , err })?;
|
||||
|
||||
// Support
|
||||
// Note: Although support conditions and effects aren't written if they're None,
|
||||
// a bit pattern of all 0s is a valid pattern and means "None" to the game.
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
// Support conditions
|
||||
if let Some(support_condition) = &self.support.conditions[0] { support_condition.to_bytes(&mut bytes[0x71..0x91])?; }
|
||||
if let Some(support_condition) = &self.support.conditions[1] { support_condition.to_bytes(&mut bytes[0x91..0xb1])?; }
|
||||
|
||||
// Support effects
|
||||
if let Some(support_effect) = &self.support.effects[0] { support_effect.to_bytes(&mut bytes[0xb1..0xc1])?; }
|
||||
if let Some(support_effect) = &self.support.effects[1] { support_effect.to_bytes(&mut bytes[0xc1..0xd1])?; }
|
||||
if let Some(support_effect) = &self.support.effects[2] { support_effect.to_bytes(&mut bytes[0xd1..0xe1])?; }
|
||||
|
||||
// Cross move
|
||||
if let Some(cross_move) = self.support.cross_move { cross_move.to_bytes(&mut bytes[0xe1..0xe2])? };
|
||||
|
||||
// Unknown
|
||||
bytes[0xe2] = self.support.unknown;
|
||||
|
||||
// Support arrow color
|
||||
if let Some(arrow_color) = self.support.arrow_color { arrow_color.to_bytes( &mut bytes[0xe3..0xe4] )?; }
|
||||
|
||||
// Write the support effects
|
||||
for (index, line) in self.support.description.iter().enumerate()
|
||||
{
|
||||
// If it's not valid ascii, return Err
|
||||
if !line.chars().all(|c| c.is_ascii() && !c.is_ascii_control()) {
|
||||
return Err( ToBytesError::SupportEffectDescriptionNotAscii{
|
||||
name: line.clone(),
|
||||
rank: util::as_ordinal((index+1) as u64),
|
||||
});
|
||||
}
|
||||
|
||||
// If we cannot write it to the buffer, return Err
|
||||
bytes[0x0e4 + (0x15 * index) .. 0x0f9 + (0x15 * index)].copy_from_slice(
|
||||
util::write_null_terminated_string(line, &mut [0u8; 0x15])
|
||||
.map_err(|err| ToBytesError::SupportEffectDescriptionTooLong {
|
||||
string: line.clone(),
|
||||
rank: util::as_ordinal((index+1) as u64),
|
||||
err
|
||||
})?
|
||||
);
|
||||
}
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
|
||||
// Return Ok
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@ -85,8 +85,6 @@ use serde::Deserialize;
|
||||
#[display(fmt = "Unable to convert the {} support effect description to a string", rank)]
|
||||
SupportEffectDescriptionToString {
|
||||
rank: &'static str,
|
||||
|
||||
|
||||
err: util::ReadNullTerminatedStringError,
|
||||
},
|
||||
|
||||
@ -95,8 +93,6 @@ use serde::Deserialize;
|
||||
SupportEffectCondition {
|
||||
rank: &'static str,
|
||||
digivolve_pos: u64,
|
||||
|
||||
|
||||
err: crate::game::card::property::support_condition::FromBytesError,
|
||||
},
|
||||
|
||||
@ -104,12 +100,24 @@ use serde::Deserialize;
|
||||
#[display(fmt = "Unable to read the {} support effect", rank)]
|
||||
SupportEffect {
|
||||
rank: &'static str,
|
||||
|
||||
|
||||
err: crate::game::card::property::support_effect::FromBytesError,
|
||||
},
|
||||
}
|
||||
|
||||
impl std::error::Error for FromBytesError {
|
||||
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
|
||||
match self {
|
||||
Self::NameToString(err) |
|
||||
Self::SupportEffectDescriptionToString{err, ..} => Some(err),
|
||||
|
||||
Self::EffectArrowColor(err) => Some(err),
|
||||
|
||||
Self::SupportEffectCondition{err, ..} => Some(err),
|
||||
Self::SupportEffect{err, ..} => Some(err),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The error type thrown by `ToBytes`
|
||||
#[derive(Debug, derive_more::Display)]
|
||||
pub enum ToBytesError
|
||||
@ -125,6 +133,15 @@ use serde::Deserialize;
|
||||
string: String,
|
||||
},
|
||||
}
|
||||
|
||||
impl std::error::Error for ToBytesError {
|
||||
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
|
||||
match self {
|
||||
Self::NameTooLong(..) |
|
||||
Self::SupportEffectDescriptionTooLong{ .. } => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
|
||||
// Impl
|
||||
|
||||
@ -81,8 +81,6 @@ use serde::Deserialize;
|
||||
#[display(fmt = "Unable to convert the {} support effect description to a string", rank)]
|
||||
SupportEffectDescriptionToString {
|
||||
rank: &'static str,
|
||||
|
||||
|
||||
err: util::ReadNullTerminatedStringError,
|
||||
},
|
||||
|
||||
@ -91,8 +89,6 @@ use serde::Deserialize;
|
||||
SupportCondition {
|
||||
rank: &'static str,
|
||||
item_pos: u64,
|
||||
|
||||
|
||||
err: crate::game::card::property::support_condition::FromBytesError,
|
||||
},
|
||||
|
||||
@ -100,12 +96,23 @@ use serde::Deserialize;
|
||||
#[display(fmt = "Unable to read the {} support effect", rank)]
|
||||
SupportEffect {
|
||||
rank: &'static str,
|
||||
|
||||
|
||||
err: crate::game::card::property::support_effect::FromBytesError,
|
||||
},
|
||||
}
|
||||
|
||||
impl std::error::Error for FromBytesError {
|
||||
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
|
||||
match self {
|
||||
Self::NameToString(err) |
|
||||
Self::SupportEffectDescriptionToString{err, ..} => Some(err),
|
||||
|
||||
Self::EffectArrowColor(err) => Some(err),
|
||||
Self::SupportCondition{err, ..} => Some(err),
|
||||
Self::SupportEffect{err, ..} => Some(err),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The error type thrown by `ToBytes`
|
||||
#[derive(Debug, derive_more::Display)]
|
||||
pub enum ToBytesError
|
||||
@ -121,6 +128,15 @@ use serde::Deserialize;
|
||||
string: String,
|
||||
},
|
||||
}
|
||||
|
||||
impl std::error::Error for ToBytesError {
|
||||
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
|
||||
match self {
|
||||
Self::NameTooLong(..) |
|
||||
Self::SupportEffectDescriptionTooLong{ .. } => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
|
||||
// Impl
|
||||
|
||||
@ -27,16 +27,16 @@ use byteorder::LittleEndian;
|
||||
}
|
||||
|
||||
/// The error type thrown by `FromBytes`
|
||||
#[derive(Debug, derive_more::Display)]
|
||||
#[derive(Debug, derive_more::Display, err_impl::Error)]
|
||||
pub enum FromBytesError
|
||||
{
|
||||
/// Unable to convert name to a string
|
||||
#[display(fmt = "Unable to convert name to a string")]
|
||||
NameToString( util::ReadNullTerminatedStringError ),
|
||||
NameToString( #[error(source)] util::ReadNullTerminatedStringError ),
|
||||
}
|
||||
|
||||
/// The error type thrown by `ToBytes`
|
||||
#[derive(Debug, derive_more::Display)]
|
||||
#[derive(Debug, derive_more::Display, err_impl::Error)]
|
||||
pub enum ToBytesError
|
||||
{
|
||||
/// The name was too big to be written to file
|
||||
|
||||
@ -50,6 +50,16 @@ use byteorder::{ByteOrder, LittleEndian};
|
||||
#[display(fmt = "Unable to read the effect operation")]
|
||||
Operation( crate::game::card::property::support_condition_operation::UnknownSupportConditionOperation ),
|
||||
}
|
||||
|
||||
impl std::error::Error for FromBytesError {
|
||||
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
|
||||
match self {
|
||||
Self::Condition(err) |
|
||||
Self::PropertyArgument(err) => Some(err),
|
||||
Self::Operation(err) => Some(err),
|
||||
}
|
||||
}
|
||||
}
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
|
||||
// Impl
|
||||
|
||||
@ -180,6 +180,17 @@ use crate::{
|
||||
#[display(fmt = "An unknown attack type was found")]
|
||||
AttackType( crate::game::card::property::attack_type::UnknownAttackType ),
|
||||
}
|
||||
|
||||
impl std::error::Error for FromBytesError {
|
||||
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
|
||||
match self {
|
||||
Self::UnknownEffectType{ .. } => None,
|
||||
Self::PropertyArgument{ err, ..} => Some(err),
|
||||
Self::Operation(err) => Some(err),
|
||||
Self::AttackType(err) => Some(err),
|
||||
}
|
||||
}
|
||||
}
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
|
||||
// Impl
|
||||
|
||||
@ -88,7 +88,7 @@ impl Table {
|
||||
}
|
||||
|
||||
|
||||
/// Error type for [`Structure::DeserializeError`]
|
||||
/// Error type for [`Table::DeserializeError`]
|
||||
#[derive(Debug)]
|
||||
#[derive(derive_more::Display)]
|
||||
pub enum DeserializeError {
|
||||
@ -158,6 +158,61 @@ impl std::error::Error for DeserializeError {
|
||||
}
|
||||
}
|
||||
|
||||
/// Error type for [`Table::DeserializeError`]
|
||||
#[derive(Debug)]
|
||||
#[derive(derive_more::Display)]
|
||||
pub enum SerializeError {
|
||||
/// Unable to seek game file
|
||||
#[display(fmt = "Unable to seek game file to card table")]
|
||||
Seek( std::io::Error ),
|
||||
|
||||
/// Unable to write table header
|
||||
#[display(fmt = "Unable to write table header")]
|
||||
WriteHeader( std::io::Error ),
|
||||
|
||||
/// There were too many cards
|
||||
#[display(fmt = "Too many cards in table ({} digimon, {} item, {} digivolve, {} / {} bytes max)",
|
||||
"digimon_cards",
|
||||
"item_cards",
|
||||
"digivolve_cards",
|
||||
" digimon_cards * (0x3 + Digimon ::BUF_BYTE_SIZE + 0x1) +
|
||||
item_cards * (0x3 + Item ::BUF_BYTE_SIZE + 0x1) +
|
||||
digivolve_cards * (0x3 + Digivolve::BUF_BYTE_SIZE + 0x1)",
|
||||
Table::MAX_BYTE_SIZE
|
||||
)]
|
||||
TooManyCards {
|
||||
digimon_cards: usize,
|
||||
item_cards: usize,
|
||||
digivolve_cards: usize,
|
||||
},
|
||||
|
||||
/// Unable to write card header
|
||||
#[display(fmt = "Unable to write card header for card id {}", id)]
|
||||
WriteCardHeader {
|
||||
id: usize,
|
||||
err: std::io::Error,
|
||||
},
|
||||
|
||||
/// Unable to write card footer
|
||||
#[display(fmt = "Unable to write card footer for card id {}", id)]
|
||||
WriteCardFooter {
|
||||
id: usize,
|
||||
err: std::io::Error,
|
||||
},
|
||||
}
|
||||
|
||||
impl std::error::Error for SerializeError {
|
||||
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
|
||||
match self {
|
||||
Self::Seek(err) |
|
||||
Self::WriteHeader(err) |
|
||||
Self::WriteCardHeader { err, .. } |
|
||||
Self::WriteCardFooter { err, .. } => Some(err),
|
||||
Self::TooManyCards { .. } => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Table {
|
||||
/// Deserializes the card table from a game file
|
||||
pub fn deserialize<R: Read + Write + Seek>(file: &mut GameFile<R>) -> Result<Self, DeserializeError> {
|
||||
@ -266,34 +321,109 @@ impl Table {
|
||||
})
|
||||
}
|
||||
|
||||
/*
|
||||
pub fn serialize<R: Read + Write + Seek>(&self, _file: &mut GameFile<R>) -> Result<(), !> {
|
||||
todo!();
|
||||
|
||||
/*
|
||||
pub fn serialize<R: Read + Write + Seek>(&self, file: &mut GameFile<R>) -> Result<(), SerializeError> {
|
||||
// Get the final table size
|
||||
// Note: + 0x4 here is for the `next` section
|
||||
let table_size = self.digimons .len() * (Digimon ::BUF_BYTE_SIZE + 0x4) +
|
||||
self.items .len() * (Item ::BUF_BYTE_SIZE + 0x4) +
|
||||
self.digivolves.len() * (Digivolve::BUF_BYTE_SIZE + 0x4);
|
||||
let table_size = table_size as u64;
|
||||
let table_size = self.digimons .len() * (0x3 + Digimon ::BUF_BYTE_SIZE + 0x1) +
|
||||
self.items .len() * (0x3 + Item ::BUF_BYTE_SIZE + 0x1) +
|
||||
self.digivolves.len() * (0x3 + Digivolve::BUF_BYTE_SIZE + 0x1);
|
||||
|
||||
// If the total table size is bigger than the max, return Err
|
||||
assert!(table_size > Table::MAX_BYTE_SIZE as u64, "Table is too big");
|
||||
if table_size > Self::MAX_BYTE_SIZE { return Err( SerializeError::TooManyCards {
|
||||
digimon_cards: self.digimons .len(),
|
||||
item_cards: self.items .len(),
|
||||
digivolve_cards: self.digivolves.len(),
|
||||
} ); }
|
||||
|
||||
// Seek to the beginning of the card table
|
||||
file.seek( std::io::SeekFrom::Start( u64::from( Self::START_ADDRESS ) + 0x8 ) )
|
||||
.map_err(SerializeError::Seek)?;
|
||||
|
||||
// Function to write a card to file
|
||||
fn write_card<R: Read + Write + Seek, C: Bytes>(_file: &mut GameFile<R>, _card: &C, _cur_id: usize) {
|
||||
/*
|
||||
// Get the bytes
|
||||
let mut bytes = [0u8; <C as Bytes>::BUF_BYTE_SIZE];
|
||||
card.to_bytes(&mut bytes)
|
||||
.expect("Unable to get digimon as bytes");
|
||||
|
||||
// Write the digimon buffer
|
||||
file.write_all(&bytes)
|
||||
.expect("Unable to write digimon card");
|
||||
|
||||
// And write the 'next' section
|
||||
let mut buf = [0u8; 0x4];
|
||||
|
||||
match idx {
|
||||
num if num + 1 == self.digimons.len() => CardType::Item .to_bytes( &mut buf[0x3..0x4] )?,
|
||||
_ => CardType::Digimon.to_bytes( &mut buf[0x3..0x4] )?,
|
||||
}
|
||||
|
||||
LittleEndian::write_u16( &mut buf[0x1..0x3], cur_id+1);
|
||||
|
||||
file.write_all(&buf)
|
||||
.expect("");
|
||||
*/
|
||||
}
|
||||
|
||||
// Write all digimon, items and digivolves
|
||||
for (id, digimon) in self.digimons.iter().enumerate() {
|
||||
write_card(file, digimon, id);
|
||||
}
|
||||
for (id, item) in self.items.iter().enumerate() {
|
||||
write_card(file, item, self.digimons.len() + id);
|
||||
}
|
||||
for (id, digivolve) in self.digivolves.iter().enumerate() {
|
||||
write_card(file, digivolve, self.digimons.len() + self.items.len() + id);
|
||||
}
|
||||
|
||||
/*
|
||||
if table_size > Table::MAX_BYTE_SIZE as u64
|
||||
enum Card<'a> {
|
||||
Digimon (&'a Digimon ),
|
||||
Item (&'a Item ),
|
||||
Digivolve(&'a Digivolve),
|
||||
}
|
||||
|
||||
// Then write all cards
|
||||
for (idx, card) in std::iter::empty()
|
||||
.chain(self.digimons .iter().map(Card::Digimon ))
|
||||
.chain(self.items .iter().map(Card::Item ))
|
||||
.chain(self.digivolves.iter().map(Card::Digivolve))
|
||||
.enumerate()
|
||||
{
|
||||
return Err( WriteError::TableTooBig{size: table_size, max: Table::MAX_BYTE_SIZE as u64} );
|
||||
let bytes = match card {
|
||||
Card::Digimon(digimon) => {
|
||||
let mut bytes = [0; Digimon::BUF_BYTE_SIZE];
|
||||
digimon.to_bytes(&mut bytes);
|
||||
&bytes as &[u8]
|
||||
},
|
||||
_ => &[],
|
||||
};
|
||||
|
||||
// Write the buffer
|
||||
file.write_all(&bytes)
|
||||
.expect("Unable to write card");
|
||||
|
||||
// And write the 'next' section
|
||||
let mut buf = [0u8; 0x4];
|
||||
|
||||
match idx {
|
||||
num if num + 1 == self.digimons.len() => CardType::Item .to_bytes( &mut buf[0x3..0x4] )?,
|
||||
_ => CardType::Digimon.to_bytes( &mut buf[0x3..0x4] )?,
|
||||
}
|
||||
|
||||
LittleEndian::write_u16( &mut buf[0x1..0x3], (idx+1) as u16);
|
||||
|
||||
file.write_all(&buf)
|
||||
.expect("");
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
// The current id
|
||||
let mut cur_id = 0u16;
|
||||
|
||||
|
||||
// Seek to the beginning of the card table
|
||||
game_file.seek( std::io::SeekFrom::Start( u64::from( Table::START_ADDRESS ) + 0x8 ) )
|
||||
.expect("Unable to seek to card table");
|
||||
|
||||
|
||||
// Then write all cards, first digimon, then items, then digivolves
|
||||
for (idx, digimon) in self.digimons.iter().enumerate()
|
||||
@ -304,21 +434,21 @@ impl Table {
|
||||
.expect("Unable to get digimon as bytes");
|
||||
|
||||
// Write the digimon buffer
|
||||
game_file.write_all(&bytes)
|
||||
file.write_all(&bytes)
|
||||
.expect("Unable to write digimon card");
|
||||
|
||||
// And write the 'next' section
|
||||
let mut buf = [0u8; 0x4];
|
||||
|
||||
match idx {
|
||||
num if num + 1 == self.digimons.len() => { CardType::Item .to_bytes( &mut buf[0x3..0x4] )?; }
|
||||
_ => { CardType::Digimon.to_bytes( &mut buf[0x3..0x4] )?; }
|
||||
num if num + 1 == self.digimons.len() => CardType::Item .to_bytes( &mut buf[0x3..0x4] )?,
|
||||
_ => CardType::Digimon.to_bytes( &mut buf[0x3..0x4] )?,
|
||||
}
|
||||
|
||||
LittleEndian::write_u16( &mut buf[0x1..0x3], cur_id+1);
|
||||
|
||||
game_file.write_all(&buf)
|
||||
.expect("")
|
||||
file.write_all(&buf)
|
||||
.expect("");
|
||||
|
||||
cur_id += 1;
|
||||
}
|
||||
@ -327,10 +457,10 @@ impl Table {
|
||||
{
|
||||
// Get the bytes
|
||||
let mut bytes = [0u8; Item::BUF_BYTE_SIZE as usize];
|
||||
item.to_bytes(&mut bytes).map_err(|err| WriteError::ConvertItem{id: cur_id, err})?;
|
||||
item.to_bytes(&mut bytes).unwrap();//.map_err(|err| SerializeError::ConvertItem{id: cur_id, err})?;
|
||||
|
||||
// Write the item buffer
|
||||
game_file.write_all(&bytes).map_err(|err| WriteError::WriteItem{id: cur_id, err})?;
|
||||
file.write_all(&bytes).unwrap();//.map_err(|err| SerializeError::WriteItem{id: cur_id, err})?;
|
||||
|
||||
// And write the 'next' section
|
||||
let mut buf = [0u8; 0x4];
|
||||
@ -342,7 +472,7 @@ impl Table {
|
||||
|
||||
LittleEndian::write_u16( &mut buf[0x1..0x3], cur_id+1);
|
||||
|
||||
game_file.write_all(&buf).map_err(|err| WriteError::NextEntryInfo{ id: cur_id, err })?;
|
||||
file.write_all(&buf).unwrap();//.map_err(|err| SerializeError::NextEntryInfo{ id: cur_id, err })?;
|
||||
|
||||
cur_id += 1;
|
||||
}
|
||||
@ -351,10 +481,10 @@ impl Table {
|
||||
{
|
||||
// Get the bytes
|
||||
let mut bytes = [0u8; Digivolve::BUF_BYTE_SIZE as usize];
|
||||
digivolve.to_bytes(&mut bytes).map_err(|err| WriteError::ConvertDigivolve{id: cur_id, err})?;
|
||||
digivolve.to_bytes(&mut bytes).unwrap();//.map_err(|err| SerializeError::ConvertDigivolve{id: cur_id, err})?;
|
||||
|
||||
// Write the digimon buffer
|
||||
game_file.write_all(&bytes).map_err(|err| WriteError::WriteDigivolve{id: cur_id, err})?;
|
||||
file.write_all(&bytes).unwrap();//.map_err(|err| SerializeError::WriteDigivolve{id: cur_id, err})?;
|
||||
|
||||
// And write the 'next' section
|
||||
let mut buf = [0u8; 0x4];
|
||||
@ -364,15 +494,13 @@ impl Table {
|
||||
_ => { CardType::Digivolve.to_bytes( &mut buf[0x3..0x4] )?; LittleEndian::write_u16( &mut buf[0x1..0x3], cur_id+1); }
|
||||
}
|
||||
|
||||
game_file.write_all(&buf).map_err(|err| WriteError::NextEntryInfo{ id: cur_id, err })?;
|
||||
file.write_all(&buf).unwrap();//.map_err(|err| SerializeError::NextEntryInfo{ id: cur_id, err })?;
|
||||
|
||||
cur_id += 1;
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
// And return Ok
|
||||
Ok(())
|
||||
*/
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
@ -61,6 +61,15 @@
|
||||
Utf8( std::str::Utf8Error ),
|
||||
}
|
||||
|
||||
impl std::error::Error for ReadNullTerminatedStringError {
|
||||
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
|
||||
match self {
|
||||
Self::NoNull => None,
|
||||
Self::Utf8(err) => Some(err),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Error type for `write_null_terminated_string`
|
||||
#[derive(Debug, derive_more::Display)]
|
||||
#[display(fmt = "The string was too long to write to the buffer ({0} / {1})", string_size, buf_size)]
|
||||
@ -72,6 +81,9 @@
|
||||
/// The buffer size
|
||||
buf_size: usize,
|
||||
}
|
||||
|
||||
// No source
|
||||
impl std::error::Error for WriteNullTerminatedStringError { }
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
|
||||
// Impl
|
||||
|
||||
@ -45,6 +45,7 @@
|
||||
clippy::unreadable_literal, // More important to be able to copy the number with no formatting than it being readable
|
||||
clippy::multiple_inherent_impl, // We prefer to separate certain methods by type and insert error types in between methods
|
||||
clippy::identity_op, // Makes sense sometimes for symmetry
|
||||
clippy::items_after_statements, // Sometimes we only introduce items when we first use them.
|
||||
|
||||
// TODO: Deal with casts eventually
|
||||
clippy::cast_possible_wrap,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user