Added various rustfmt configurations.

Revised documentation of the library and lint opt-out reasons.
Moved some module documentation to it's own file due to overflowing the line limit.
Fixed several spelling errors.
This commit is contained in:
2020-05-13 03:03:46 +01:00
parent 968a89fc0b
commit 63d312e845
24 changed files with 295 additions and 220 deletions

View File

@@ -1,6 +1,6 @@
//! Interface for converting various structures to and from bytes
/// Convertions to and from bytes for the game file
/// Conversions to and from bytes for the game file
pub trait Bytes
where
Self: Sized,

28
src/game/card/digimon.md Normal file
View File

@@ -0,0 +1,28 @@
A digimon card
This module contains the [`Digimon`] struct, which describes a digimon card.
# Layout
The digimon card has a size of `0x138` bytes, and it's layout is the following:
| Offset | Size | Type | Name | Location | Details |
| ------ | ---- | ------------------- | ------------------------ | ---------------------- | ----------------------------------------------------------------------------------- |
| 0x0 | 0x15 | `[char; 0x15]` | Name | `name` | Null-terminated |
| 0x15 | 0x2 | `u16` | Unknown | `unknown_15` | |
| 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_1a` | Is `0` for all digimon |
| 0x1b | 0x2 | `u16` | Health | `hp` | |
| 0x1d | 0x1c | [`Move`] | Circle Move | `move_circle` | |
| 0x39 | 0x1c | [`Move`] | Triangle move | `move_triangle` | |
| 0x55 | 0x1c | [`Move`] | Cross move | `move_cross` | |
| 0x71 | 0x20 | [`EffectCondition`] | First condition | `effect_conditions[0]` | |
| 0x91 | 0x20 | [`EffectCondition`] | Second condition | `effect_conditions[1]` | |
| 0xb1 | 0x10 | [`Effect`] | First effect | `effects[0]` | |
| 0xc1 | 0x10 | [`Effect`] | Second effect | `effects[1]` | |
| 0xd1 | 0x10 | [`Effect`] | Third effect | `effects[2]` | |
| 0xe1 | 0x1 | [`CrossMoveEffect`] | Cross move effect | `cross_move_effect` | |
| 0xe2 | 0x1 | `u8` | Unknown | `unknown_e2` | |
| 0xe3 | 0x1 | [`ArrowColor`] | Effect arrow color | `effect_arrow_color` | |
| 0xe4 | 0x54 | `[[char; 0x15]; 4]` | Effect description lines | `effect_description` | Each line is` 0x15` bytes, split over 4 lines, each null terminated |

View File

@@ -1,31 +1,4 @@
//! A digimon card
//!
//! This module contains the [`Digimon`] struct, which describes a digimon card.
//!
//! # Layout
//! The digimon card has a size of `0x138` bytes, and it's layout is the following:
//!
//! | Offset | Size | Type | Name | Location | Details |
//! |--------|------|---------------------|---------------------------|------------------------|-------------------------------------------------------------------------------------|
//! | 0x0 | 0x15 | `[char; 0x15]` | Name | `name` | Null-terminated |
//! | 0x15 | 0x2 | `u16` | Unknown | `unknown_15` | |
//! | 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_1a` | Is `0` for all digimon |
//! | 0x1b | 0x2 | `u16` | Health | `hp` | |
//! | 0x1d | 0x1c | [`Move`] | Circle Move | `move_circle` | |
//! | 0x39 | 0x1c | [`Move`] | Triangle move | `move_triangle` | |
//! | 0x55 | 0x1c | [`Move`] | Cross move | `move_cross` | |
//! | 0x71 | 0x20 | [`EffectCondition`] | First condition | `effect_conditions[0]` | |
//! | 0x91 | 0x20 | [`EffectCondition`] | Second condition | `effect_conditions[1]` | |
//! | 0xb1 | 0x10 | [`Effect`] | First effect | `effects[0]` | |
//! | 0xc1 | 0x10 | [`Effect`] | Second effect | `effects[1]` | |
//! | 0xd1 | 0x10 | [`Effect`] | Third effect | `effects[2]` | |
//! | 0xe1 | 0x1 | [`CrossMoveEffect`] | Cross move effect | `cross_move_effect` | |
//! | 0xe2 | 0x1 | `u8` | Unknown | `unknown_e2` | |
//! | 0xe3 | 0x1 | [`ArrowColor`] | Effect arrow color | `effect_arrow_color` | |
//! | 0xe4 | 0x54 | `[[char; 0x15]; 4]` | Effect description lines | `effect_description` | Each line is` 0x15` bytes, split over 4 lines, each null terminated |
#![doc(include = "digimon.md")]
// byteorder
use byteorder::{ByteOrder, LittleEndian};
@@ -275,9 +248,9 @@ impl Bytes for Digimon {
hp: LittleEndian::read_u16(bytes.hp),
// Moves
move_circle: Move::from_bytes(bytes.move_circle).map_err(FromBytesError::MoveCircle)?,
move_circle: Move::from_bytes(bytes.move_circle).map_err(FromBytesError::MoveCircle)?,
move_triangle: Move::from_bytes(bytes.move_triangle).map_err(FromBytesError::MoveTriangle)?,
move_cross: Move::from_bytes(bytes.move_cross).map_err(FromBytesError::MoveCross)?,
move_cross: Move::from_bytes(bytes.move_cross).map_err(FromBytesError::MoveCross)?,
// Effects
effect_conditions: [

View File

@@ -0,0 +1,12 @@
A digivolve card
This module contains the [`Digivolve`] struct, which describes a digivolve card.
# Layout
The digivolve card has a size of `0x6c` bytes, and it's layout is the following:
| Offset | Size | Type | Name | Location | Details |
| ------ | ---- | ------------------- | ------------------------ | -------------------- | ------------------------------------------------------------------- |
| 0x0 | 0x15 | `[char; 0x15]` | Name | `name` | Null-terminated |
| 0x15 | 0x3 | `[u8; 3]` | Unknown | `unknown_15` | Probably contains the card effect |
| 0x8a | 0x54 | `[[char; 0x15]; 4]` | Effect description lines | `effect_description` | Each line is` 0x15` bytes, split over 4 lines, each null terminated |

View File

@@ -1,15 +1,4 @@
//! A digivolve card
//!
//! This module contains the [`Digivolve`] struct, which describes a digivolve card.
//!
//! # Layout
//! The digivolve card has a size of `0x6c` bytes, and it's layout is the following:
//!
//! | Offset | Size | Type | Name | Location | Details |
//! |--------|------|---------------------|---------------------------|------------------------|---------------------------------------------------------------------|
//! | 0x0 | 0x15 | `[char; 0x15]` | Name | `name` | Null-terminated |
//! | 0x15 | 0x3 | `[u8; 3]` | Unknown | `unknown_15` | Probably contains the card effect |
//! | 0x8a | 0x54 | `[[char; 0x15]; 4]` | Effect description lines | `effect_description` | Each line is` 0x15` bytes, split over 4 lines, each null terminated |
#![doc(include = "digivolve.md")]
// Crate
use crate::game::{util, Bytes};

18
src/game/card/item.md Normal file
View File

@@ -0,0 +1,18 @@
An item card
This module contains the [`Item`] struct, which describes an item card.
# Layout
The item card has a size of `0xde` bytes, and it's layout is the following:
| Offset | Size | Type | Name | Location | Details |
| ------ | ---- | ------------------- | ------------------------ | ---------------------- | ------------------------------------------------------------------- |
| 0x0 | 0x15 | `[char; 0x15]` | Name | `name` | Null-terminated |
| 0x15 | 0x4 | `u32` | Unknown | `unknown_15` | |
| 0x19 | 0x20 | [`EffectCondition`] | First condition | `effect_conditions[0]` | |
| 0x39 | 0x20 | [`EffectCondition`] | Second condition | `effect_conditions[1]` | |
| 0x59 | 0x10 | [`Effect`] | First effect | `effects[0]` | |
| 0x69 | 0x10 | [`Effect`] | Second effect | `effects[1]` | |
| 0x79 | 0x10 | [`Effect`] | Third effect | `effects[2]` | |
| 0x89 | 0x1 | [`ArrowColor`] | Effect arrow color | `effect_arrow_color` | |
| 0x8a | 0x54 | `[[char; 0x15]; 4]` | Effect description lines | `effect_description` | Each line is` 0x15` bytes, split over 4 lines, each null terminated |

View File

@@ -1,21 +1,4 @@
//! An item card
//!
//! This module contains the [`Item`] struct, which describes an item card.
//!
//! # Layout
//! The item card has a size of `0xde` bytes, and it's layout is the following:
//!
//! | Offset | Size | Type | Name | Location | Details |
//! |--------|------|---------------------|---------------------------|------------------------|-------------------------------------------------------------------------------------|
//! | 0x0 | 0x15 | `[char; 0x15]` | Name | `name` | Null-terminated |
//! | 0x15 | 0x4 | `u32` | Unknown | `unknown_15` | |
//! | 0x19 | 0x20 | [`EffectCondition`] | First condition | `effect_conditions[0]` | |
//! | 0x39 | 0x20 | [`EffectCondition`] | Second condition | `effect_conditions[1]` | |
//! | 0x59 | 0x10 | [`Effect`] | First effect | `effects[0]` | |
//! | 0x69 | 0x10 | [`Effect`] | Second effect | `effects[1]` | |
//! | 0x79 | 0x10 | [`Effect`] | Third effect | `effects[2]` | |
//! | 0x89 | 0x1 | [`ArrowColor`] | Effect arrow color | `effect_arrow_color` | |
//! | 0x8a | 0x54 | `[[char; 0x15]; 4]` | Effect description lines | `effect_description` | Each line is` 0x15` bytes, split over 4 lines, each null terminated |
#![doc(include = "item.md")]
// byteorder
use byteorder::{ByteOrder, LittleEndian};

View File

@@ -27,7 +27,7 @@ macro_rules! generate_enum_property_mod
// Note: Must have no data
$enum_variant_name:ident
// `Display` convertion name
// `Display` conversion name
($enum_variant_rename:literal)
=>
@@ -121,7 +121,7 @@ macro_rules! generate_enum_property_mod
/// Implements [`Bytes`](crate::game::Bytes) for `Option<E>` where `E`
/// is the first argument of this macro and an enum.
///
/// This is done by suppling a sentinel value which is read/written as `None`.
/// This is done by supplying a sentinel value which is read/written as `None`.
macro generate_enum_property_option {
(
$( $enum_name:ty => $sentinel_value:literal ),* $(,)?

View File

@@ -0,0 +1,12 @@
A digimon's support effect
This module contains the [`Effect`] struct, which describes a support effect.
# Layout
Each support effect has a size of `0x10` bytes, and it's general layout is the following:
| Offset | Size | Type | Name | Location | Details |
| ------ | ---- | ------ | ----------- | -------- | ------------------------------------------------------ |
| 0x0 | 0x1 | `bool` | Exists | N/A | If `0`, the effect does not exist |
| 0x1 | 0x1 | N/A | Effect Type | N/A | Determines which [`Effect`] variant is used. |
| 0x2 | 0xe | N/A | Arguments | N/A | The arguments used for the current [`Effect`] variant. |

View File

@@ -1,15 +1,4 @@
//! A digimon's support effect
//!
//! This module contains the [`Effect`] struct, which describes a support effect.
//!
//! # Layout
//! Each support effect has a size of `0x10` bytes, and it's general layout is the following:
//!
//! | Offset | Size | Type | Name | Location | Details |
//! |--------|------|----------------------|---------------------------|------------------------|--------------------------------------------------------|
//! | 0x0 | 0x1 | `bool` | Exists | N/A | If `0`, the effect does not exist |
//! | 0x1 | 0x1 | N/A | Effect Type | N/A | Determines which [`Effect`] variant is used. |
//! | 0x2 | 0xe | N/A | Arguments | N/A | The arguments used for the current [`Effect`] variant. |
#![doc(include = "effect.md")]
// byteorder
use byteorder::{ByteOrder, LittleEndian};
@@ -23,13 +12,13 @@ use crate::game::{
/// A digimon's support effects
///
/// As this type is wildly volatile in which arguments it uses and from where,
/// it is an `enum` with struct variants instead of a struct. This simplifices argument
/// it is an `enum` with struct variants instead of a struct. This simplifies argument
/// verification and, from a language perspective, makes more sense as an implementation.
#[derive(PartialEq, Eq, Clone, Copy, Hash, Debug)]
#[derive(serde::Serialize, serde::Deserialize)]
#[serde(tag = "type")]
// TODO: Move this `allow` to the variant once clippy allows
#[allow(clippy::pub_enum_variant_names)] // `Effect` on `VoidOpponentSupportEffect` isn't refering to the enum
#[allow(clippy::pub_enum_variant_names)] // `Effect` on `VoidOpponentSupportEffect` isn't referring to the enum
pub enum Effect {
/// Changes a property of either digimon
///
@@ -75,10 +64,9 @@ pub enum Effect {
/// `<temp slot> = <A> + (<B> <op> <C>)`
#[serde(rename = "Set temp slot")]
SetTempSlot {
a: Option<DigimonProperty>,
b: Option<DigimonProperty>,
c: Option<DigimonProperty>,
a: Option<DigimonProperty>,
b: Option<DigimonProperty>,
c: Option<DigimonProperty>,
op: EffectOperation,
},
@@ -93,11 +81,10 @@ pub enum Effect {
/// - `Dp` -> `Offline`
#[serde(rename = "Move cards")]
MoveCards {
player: PlayerType,
source: Slot,
player: PlayerType,
source: Slot,
destination: Slot,
count: u16,
count: u16,
},
/// Shuffles a player's online deck

View File

@@ -0,0 +1,19 @@
A digimon's effect condition
This module contains the [`EffectCondition`] struct, which describes a condition for an effect.
# Layout
Each support condition has a size of `0x20` bytes, and it's layout is the following:
| Offset | Size | Type | Name | Location | Details |
| ------ | ---- | ---------------------------- | ----------------- | -------------- | ---------------------------------------------------------------------------------- |
| 0x0 | 0x1 | `bool` | Misfire | `misfire` | If the condition throws a misfire when false |
| 0x1 | 0x1 | `u8` | | `unknown_1` | Always zero |
| 0x2 | 0x1 | [`DigimonProperty`] | Property compare | `property_cmp` | The property to compare to for the condition (or 0 if the condition doesn't exist) |
| 0x3 | 0x5 | `[u8; 0x5]` | | `unknown_3` | Unknown |
| 0x8 | 0x1 | `DigimonProperty` | Property argument | `arg_property` | Property argument for the comparison |
| 0x9 | 0xb | `[u8; 0xb]` | | `unknown_9` | Unknown |
| 0x14 | 0x2 | `u16` | Number argument | `arg_num` | Number argument for the comparison |
| 0x16 | 0x4 | `[u8; 0x4]` | | `unknown_16` | Unknown |
| 0x1a | 0x1 | [`EffectConditionOperation`] | Operation | `operation` | Operation to use for the comparison |
| 0x1b | 0x5 | `[u8; 0x5]` | | `unknown_1b` | Unknown |

View File

@@ -1,22 +1,4 @@
//! A digimon's effect condition
//!
//! This module contains the [`EffectCondition`] struct, which describes a condition for an effect.
//!
//! # Layout
//! Each support condition has a size of `0x20` bytes, and it's layout is the following:
//!
//! | Offset | Size | Type | Name | Location | Details |
//! |--------|------|------------------------------|---------------------------|--------------- |------------------------------------------------------------------------------------|
//! | 0x0 | 0x1 | `bool` | Misfire | `misfire` | If the condition throws a misfire when false |
//! | 0x1 | 0x1 | `u8` | | `unknown_1` | Always zero |
//! | 0x2 | 0x1 | [`DigimonProperty`] | Property compare | `property_cmp` | The property to compare to for the condition (or 0 if the condition doesn't exist) |
//! | 0x3 | 0x5 | `[u8; 0x5]` | | `unknown_3` | Unknown |
//! | 0x8 | 0x1 | `DigimonProperty` | Property argument | `arg_property` | Property argument for the comparation |
//! | 0x9 | 0xb | `[u8; 0xb]` | | `unknown_9` | Unknown |
//! | 0x14 | 0x2 | `u16` | Number argument | `arg_num` | Number argument for the comparation |
//! | 0x16 | 0x4 | `[u8; 0x4]` | | `unknown_16` | Unknown |
//! | 0x1a | 0x1 | [`EffectConditionOperation`] | Operation | `operation` | Operation to use for the comparation |
//! | 0x1b | 0x5 | `[u8; 0x5]` | | `unknown_1b` | Unknown |
#![doc(include = "effect_condition.md")]
// byteorder
use byteorder::{ByteOrder, LittleEndian};
@@ -47,9 +29,9 @@ pub struct EffectCondition {
operation: EffectConditionOperation,
// Unknown
unknown_1: u8,
unknown_3: [u8; 0x5],
unknown_9: [u8; 0xb],
unknown_1: u8,
unknown_3: [u8; 0x5],
unknown_9: [u8; 0xb],
unknown_16: [u8; 0x4],
unknown_1b: [u8; 0x5],
}
@@ -91,7 +73,7 @@ impl Bytes for EffectCondition {
);
Ok(Self {
misfire: (*bytes.misfire != 0),
misfire: (*bytes.misfire != 0),
property_cmp: DigimonProperty::from_bytes(bytes.property_cmp).map_err(FromBytesError::Condition)?,
arg_property: Option::<DigimonProperty>::from_bytes(bytes.arg_property).map_err(FromBytesError::PropertyArgument)?,
@@ -100,9 +82,9 @@ impl Bytes for EffectCondition {
operation: EffectConditionOperation::from_bytes(bytes.operation).map_err(FromBytesError::Operation)?,
unknown_1: *bytes.unknown_1,
unknown_3: *bytes.unknown_3,
unknown_9: *bytes.unknown_9,
unknown_1: *bytes.unknown_1,
unknown_3: *bytes.unknown_3,
unknown_9: *bytes.unknown_9,
unknown_16: *bytes.unknown_16,
unknown_1b: *bytes.unknown_1b,
})
@@ -151,7 +133,7 @@ impl Bytes for Option<EffectCondition> {
type ToError = <EffectCondition as crate::game::Bytes>::ToError;
fn from_bytes(bytes: &Self::ByteArray) -> Result<Self, Self::FromError> {
// If we have no property comparation, return None
// If we have no property comparison, return None
if bytes[0x2] == 0 {
return Ok(None);
}

View File

@@ -63,8 +63,8 @@ impl Bytes for Move {
// Return the move
Ok(Self {
name: util::read_null_ascii_string(bytes.name).map_err(FromBytesError::Name)?.to_ascii_string(),
power: LittleEndian::read_u16(bytes.power),
name: util::read_null_ascii_string(bytes.name).map_err(FromBytesError::Name)?.to_ascii_string(),
power: LittleEndian::read_u16(bytes.power),
unknown: LittleEndian::read_u32(bytes.unknown),
})
}

34
src/game/card/table.md Normal file
View File

@@ -0,0 +1,34 @@
The table of all digimon in the game
# Details
At address [0x216d000](Table::START_ADDRESS) of the game file, the card table begins
with a small header of `0xb` and then the table itself.
# Table Layout
The digimon table has a max size of [0x14950](Table::MAX_BYTE_SIZE), but does not
necessary use all of this space, but it does follow this layout:
| Offset | Size | Type | Name | Details |
| ------ | -------- | --------------- | -------------------- | ----------------------------------------------------------------------- |
| 0x0 | 0x4 | u32 | Magic | Always contains the string "0ACD" (= [0x44434130](Table::HEADER_MAGIC)) |
| 0x4 | 0x2 | u16 | Number of digimon | |
| 0x6 | 0x1 | u8 | Number of items | |
| 0x7 | 0x1 | u8 | Number of digivolves | |
| 0x8 | variable | \[`CardEntry`\] | Card Entries | A contiguous array of [Card Entry](#card-entry-layout) |
# Card Entry Layout
Each card entry consists of a header of the card
| Offset | Size | Type | Name | Details |
| ------ | -------- | ------------------------------------ | --------------- | -------------------------------------------- |
| 0x0 | 0x3 | [`Card Header`](#card-header-layout) | Card Header | The card's header |
| 0x3 | variable | | Card | Either a [Digimon], [Item] or [Digivolve] |
| ... | 0x1 | u8 | Null terminator | A null terminator for the card (must be `0`) |
# Card Header Layout
The card header determines which type of card this card entry has.
| Offset | Size | Type | Name | Details |
| ------ | ---- | ------------ | --------- | ------------------------------------------------ |
| 0x0 | 0x2 | u16 | Card id | This card's ID |
| 0x2 | 0x1 | [`CardType`] | Card type | The card type ([Digimon], [Item] or [Digivolve]) |

View File

@@ -1,42 +1,4 @@
//! The table of all digimon in the game
//!
//! # Details
//! At address [0x216d000](Table::START_ADDRESS) of the game file, the card table begins
//! with a small header of `0xb` and then the table itself.
//!
//! # Table Layout
//! The digimon table has a max size of [0x14950](Table::MAX_BYTE_SIZE), but does not
//! necessary use all of this space, but it does follow this layout:
//!
//! | Offset | Size | Type | Name | Details |
//! |--------|----------|-----------------|----------------------|-------------------------------------------------------------------------|
//! | 0x0 | 0x4 | u32 | Magic | Always contains the string "0ACD" (= [0x44434130](Table::HEADER_MAGIC)) |
//! | 0x4 | 0x2 | u16 | Number of digimon | |
//! | 0x6 | 0x1 | u8 | Number of items | |
//! | 0x7 | 0x1 | u8 | Number of digivolves | |
//! | 0x8 | variable | \[`CardEntry`\] | Card Entries | A contigous array of [Card Entry](#card-entry-layout) |
//!
//! # Card Entry Layout
//! Each card entry consists of a header of the card
//!
//! | Offset | Size | Type | Name | Details |
//! |--------|----------|--------------------------------------|-----------------|----------------------------------------------|
//! | 0x0 | 0x3 | [`Card Header`](#card-header-layout) | Card Header | The card's header |
//! | 0x3 | variable | | Card | Either a [Digimon], [Item] or [Digivolve] |
//! | ... | 0x1 | u8 | Null terminator | A null terminator for the card (must be `0`) |
//!
//! # Card Header Layout
//! The card header determines which type of card this card entry has.
//!
//! | Offset | Size | Type | Name | Details |
//! |--------|------|--------------|-----------|--------------------------------------------------|
//! | 0x0 | 0x2 | u16 | Card id | This card's ID |
//! | 0x2 | 0x1 | [`CardType`] | Card type | The card type ([Digimon], [Item] or [Digivolve]) |
// Lints
// False positive, we don't use any `unsafe` in impls
// TODO: Remove this lint once it no longer triggers.
#![allow(clippy::unsafe_derive_deserialize)]
#![doc(include = "table.md")]
// Std
use std::io::{Read, Seek, Write};
@@ -121,15 +83,15 @@ pub enum DeserializeError {
Table::MAX_BYTE_SIZE
)]
TooManyCards {
digimon_cards: usize,
item_cards: usize,
digimon_cards: usize,
item_cards: usize,
digivolve_cards: usize,
},
/// Unable to read card header
#[display(fmt = "Unable to read card header for card id {}", id)]
ReadCardHeader {
id: usize,
id: usize,
#[error(source)]
err: std::io::Error,
},
@@ -137,7 +99,7 @@ pub enum DeserializeError {
/// An unknown card type was found
#[display(fmt = "Unknown card type for card id {}", id)]
UnknownCardType {
id: usize,
id: usize,
#[error(source)]
err: property::card_type::FromBytesError,
},
@@ -145,7 +107,7 @@ pub enum DeserializeError {
/// Unable to read a card
#[display(fmt = "Unable to read {} with id {}", card_type, id)]
ReadCard {
id: usize,
id: usize,
card_type: CardType,
#[error(source)]
@@ -155,7 +117,7 @@ pub enum DeserializeError {
/// Unable to deserialize a digimon card
#[display(fmt = "Unable to deserialize digimon card with id {}", id)]
DigimonCard {
id: usize,
id: usize,
#[error(source)]
err: card::digimon::FromBytesError,
},
@@ -163,7 +125,7 @@ pub enum DeserializeError {
/// Unable to deserialize an item card
#[display(fmt = "Unable to deserialize item card with id {}", id)]
ItemCard {
id: usize,
id: usize,
#[error(source)]
err: card::item::FromBytesError,
},
@@ -171,7 +133,7 @@ pub enum DeserializeError {
/// Unable to deserialize a digivolve card
#[display(fmt = "Unable to deserialize digivolve card with id {}", id)]
DigivolveCard {
id: usize,
id: usize,
#[error(source)]
err: card::digivolve::FromBytesError,
},
@@ -179,7 +141,7 @@ pub enum DeserializeError {
/// Unable to read card footer
#[display(fmt = "Unable to read card footer for card id {}", id)]
ReadCardFooter {
id: usize,
id: usize,
#[error(source)]
err: std::io::Error,
},
@@ -209,15 +171,15 @@ pub enum SerializeError {
Table::MAX_BYTE_SIZE
)]
TooManyCards {
digimon_cards: usize,
item_cards: usize,
digimon_cards: usize,
item_cards: usize,
digivolve_cards: usize,
},
/// Unable to write a digimon card
#[display(fmt = "Unable to write digimon card with id {}", id)]
WriteDigimonCard {
id: usize,
id: usize,
#[error(source)]
err: std::io::Error,
},
@@ -225,7 +187,7 @@ pub enum SerializeError {
/// Unable to write an item card
#[display(fmt = "Unable to write item card with id {}", id)]
WriteItemCard {
id: usize,
id: usize,
#[error(source)]
err: std::io::Error,
},
@@ -233,7 +195,7 @@ pub enum SerializeError {
/// Unable to write a digivolve card
#[display(fmt = "Unable to write digivolve card with id {}", id)]
WriteDigivolveCard {
id: usize,
id: usize,
#[error(source)]
err: std::io::Error,
},
@@ -241,7 +203,7 @@ pub enum SerializeError {
/// Unable to parse a digimon card
#[display(fmt = "Unable to parse digimon card with id {}", id)]
ParseDigimonCard {
id: usize,
id: usize,
#[error(source)]
err: card::digimon::ToBytesError,
},
@@ -249,7 +211,7 @@ pub enum SerializeError {
/// Unable to parse an item card
#[display(fmt = "Unable to parse item card with id {}", id)]
ParseItemCard {
id: usize,
id: usize,
#[error(source)]
err: card::item::ToBytesError,
},
@@ -257,7 +219,7 @@ pub enum SerializeError {
/// Unable to parse a digivolve card
#[display(fmt = "Unable to parse digivolve card with id {}", id)]
ParseDigivolveCard {
id: usize,
id: usize,
#[error(source)]
err: card::digivolve::ToBytesError,
},
@@ -373,8 +335,8 @@ impl Table {
// If the total table size is bigger than the max, return Err
if table_size > Self::MAX_BYTE_SIZE {
return Err(SerializeError::TooManyCards {
digimon_cards: self.digimons.len(),
item_cards: self.items.len(),
digimon_cards: self.digimons.len(),
item_cards: self.items.len(),
digivolve_cards: self.digivolves.len(),
});
}

View File

@@ -93,7 +93,7 @@ impl Bytes for Deck {
unknown: [0xc],
);
// Nanme / Owner
// Name / Owner
util::write_maybe_null_ascii_string(&self.name, bytes.name).map_err(ToBytesError::Name)?;
util::write_maybe_null_ascii_string(&self.owner, bytes.owner).map_err(ToBytesError::Owner)?;

View File

@@ -42,7 +42,7 @@ pub enum DeserializeError {
/// Could not read a deck entry
#[display(fmt = "Unable to read deck entry with id {}", "id")]
ReadDeck {
id: usize,
id: usize,
#[error(source)]
err: std::io::Error,
},
@@ -50,7 +50,7 @@ pub enum DeserializeError {
/// Could not deserialize a deck entry
#[display(fmt = "Unable to serialize deck entry with id {}", "id")]
DeserializeDeck {
id: usize,
id: usize,
#[error(source)]
err: deck::FromBytesError,
},
@@ -71,7 +71,7 @@ pub enum SerializeError {
/// Could not deserialize a deck entry
#[display(fmt = "Unable to deserialize deck entry with id {}", "id")]
SerializeDeck {
id: usize,
id: usize,
#[error(source)]
err: deck::ToBytesError,
},
@@ -79,7 +79,7 @@ pub enum SerializeError {
/// Could not write a deck entry
#[display(fmt = "Unable to read deck entry with id {}", "id")]
WriteDeck {
id: usize,
id: usize,
#[error(source)]
err: std::io::Error,
},

View File

@@ -3,7 +3,7 @@
//! This modules is used for miscellaneous macros, functions that have
//! not been moved to a more permanent location.
//!
//! All items in this module will eventually be depracated and moved
//! All items in this module will eventually be deprecated and moved
//! somewhere else, but this change might take some time.
pub macro array_split {
@@ -170,7 +170,7 @@ pub fn write_null_ascii_string<'a>(input: &ascii::AsciiStr, buf: &'a mut [u8]) -
// If the input string doesn't fit into the buffer (excluding the null byte), return Err
if input.len() >= buf.len() {
return Err(WriteNullAsciiStringError::TooLarge {
input_len: input.len(),
input_len: input.len(),
buffer_len: buf.len(),
});
}
@@ -198,7 +198,7 @@ pub fn write_maybe_null_ascii_string<'a>(input: &ascii::AsciiStr, buf: &'a mut [
// If the input string doesn't fit into the buffer, return Err
if input.len() > buf.len() {
return Err(WriteMaybeNullAsciiStringError::TooLarge {
input_len: input.len(),
input_len: input.len(),
buffer_len: buf.len(),
});
}

View File

@@ -2,7 +2,7 @@
//!
//! The Io module takes care of interacting with the game file itself, such
//! as ensuring that only the data sections in the game file are written to.
//! As well as making convertions between coordinates in data to real file
//! As well as making conversions between coordinates in data to real file
//! coordinates. (For more details, visit the [`address`] module)
// Modules

View File

@@ -39,10 +39,10 @@ impl std::convert::TryFrom<Real> for Data {
// The data address is just converting the real_sector
// to a data_sector and subtracting the header from the
// real offset to get the data offset
#[rustfmt::skip]
Ok(Self::from(
Real::SECTOR_BYTE_SIZE * real_sector + // Base of data sector
real_sector_offset -
Real::HEADER_BYTE_SIZE, // Data offset
Real::SECTOR_BYTE_SIZE * real_sector + // Base of data sector
real_sector_offset - Real::HEADER_BYTE_SIZE, // Data offset (skipping header)
))
}
}
@@ -54,12 +54,13 @@ impl From<Data> for Real {
let data_sector = data_address.sector();
let data_sector_offset = data_address.offset();
// Then the real address is just convering the data_sector
// Then the real address is just converting the data_sector
// to a real_sector and adding the header plus the offset
#[rustfmt::skip]
Self::from(
Self::SECTOR_BYTE_SIZE * data_sector + // Base of real sector
Self::HEADER_BYTE_SIZE + // Skip header
data_sector_offset, // Offset inside data sector
data_sector_offset, // Offset inside data sector
)
}
}

View File

@@ -47,6 +47,7 @@ impl Real {
let real_sector = self.sector();
// The end of the real data section is after the header and data sections
#[rustfmt::skip]
Self::from(
Self::SECTOR_BYTE_SIZE * real_sector + // Beginning of sector
Self::HEADER_BYTE_SIZE + // Skip Header

View File

@@ -69,7 +69,7 @@ impl<R: Read + Write + Seek> Read for GameFile<R> {
// While the buffer isn't empty
while !buf.is_empty() {
// Get the current real address we're at in the reader
// Note: If we can't get the position, we return immediatly
// Note: If we can't get the position, we return immediately
let cur_real_address = RealAddress::from(self.reader.stream_position()?);
// Get the data section end
@@ -77,7 +77,7 @@ impl<R: Read + Write + Seek> Read for GameFile<R> {
// If we're at the end of the data section, seek to the next data section
if cur_real_address == data_section_end {
// Seek ahead by skiping the footer and next header
// Seek ahead by skipping the footer and next header
self.reader.seek(std::io::SeekFrom::Current(
(RealAddress::FOOTER_BYTE_SIZE + RealAddress::HEADER_BYTE_SIZE) as i64,
))?;
@@ -106,7 +106,7 @@ impl<R: Read + Write + Seek> Read for GameFile<R> {
}
// Read either until the end of the data section or until buffer is full
// Note: If any fail, we immediatly return Err
// Note: If any fail, we immediately return Err
let bytes_read = self.reader.read(&mut buf[0..bytes_to_read])?;
// If 0 bytes were read, EOF was reached, so return with however many we've read
@@ -137,7 +137,7 @@ impl<R: Read + Write + Seek> Write for GameFile<R> {
// While the buffer isn't empty
while !buf.is_empty() {
// Get the current real address we're at in the reader
// Note: If we can't get the position, we return immediatly
// Note: If we can't get the position, we return immediately
let cur_real_address = RealAddress::from(self.reader.stream_position()?);
// Get the data section end
@@ -145,7 +145,7 @@ impl<R: Read + Write + Seek> Write for GameFile<R> {
// If we're at the end of the data section, seek to the next data section
if cur_real_address == data_section_end {
// Seek ahead by skiping the footer and next header
// Seek ahead by skipping the footer and next header
self.reader.seek(std::io::SeekFrom::Current(
(RealAddress::FOOTER_BYTE_SIZE + RealAddress::HEADER_BYTE_SIZE) as i64,
))?;
@@ -174,7 +174,7 @@ impl<R: Read + Write + Seek> Write for GameFile<R> {
}
// Write either until the end of the data section or until buffer runs out
// Note: If this fails, we immediatly return Err
// Note: If this fails, we immediately return Err
let bytes_written = self.reader.write(&buf[0..bytes_to_write])?;
// If 0 bytes were written, EOF was reached, so return with however many we've read

View File

@@ -1,10 +1,16 @@
//! `dcb` is a library for interacting with the game file of `Digimon Digital Card Battle`,
//! a PSX game.
//! `dcb` is a library for interacting with the game file of `Digimon Digital Card Battle`.
//!
//! # Modules
//! `dcb` splits itself into 2 main modules, [`io`], which interacts with the game file
//! as well as general input / output operations and [`game`], where most of the game's
//! data types are defined.
//! `dcb` is split across 2 main modules, [`io`] and [`game`].
//!
//! ## Io
//! The Io module is responsible for interacting with the game file. In the future it may be responsible
//! for also interacting with the game extracted database, once work on that is complete.
//!
//! ## Game
//! The game module is responsible for representing in-game structures such as cards, sprites, text, and
//! others. The trait has various interfaces to be able to deserialize these structures from both the game
//! file, database or even other sources, depending on the structure.
//!
//! # Example
//!
@@ -32,36 +38,65 @@
stmt_expr_attributes,
unwrap_infallible,
const_if_match,
exclusive_range_pattern
exclusive_range_pattern,
external_doc
)]
// Lints
#![warn(clippy::restriction, clippy::pedantic, clippy::nursery)]
// Necessary items may be inlined using `LTO`, so we don't need to mark them as inline
#![allow(clippy::missing_inline_in_public_items)]
// We prefer tail returns where possible, as they help with code readability in most cases.
#![allow(clippy::implicit_return)]
// Very useful for arguments such as `arg: impl Into<U>`, then used
// with `let arg = arg.into()`. As well as just going from `Option<T>`
// to `T` without needing to change their names.
#![allow(clippy::shadow_reuse, clippy::shadow_same)]
// We use `.expect("...")` when we either know we cannot panic or it
// is the safest alternative, as proceeding would corrupt the program state.
#![allow(clippy::result_expect_used, clippy::option_expect_used)]
// Like-wise with `.expect()`, we use `unreachable!` when we know a branch
// if unreachable, and if it ever does get reached, panicking would be the
// safest option
#![allow(clippy::unreachable)]
// We find it more important to be able to copy paste literals such as `0xabcd1234` than
// being able to read them, which does not provide many benefits
#![allow(clippy::unreadable_literal, clippy::unseparated_literal_suffix)]
// We separate implementations per their functionality usually, such as constructors, getters, setters, and others.
#![allow(clippy::multiple_inherent_impl)]
// Many operations we need to repeat, and to keep symmetry
#![allow(clippy::identity_op)]
// We only introduce items before their first usage, which sometimes is half-way through the code
#![allow(clippy::items_after_statements)]
// Useful for when they either change a lot with new variants / data,
// or for symmetry purposes
#![allow(clippy::match_same_arms)]
// In this library we have very grain-level error types, each function
// will have it's own error type ideally, so any errors are explicit
// by the type, without needing a section for them
#![allow(clippy::missing_errors_doc)]
// Incomplete code should be tagged as `todo`. In future versions of the library,
// this lint may be removed, as incomplete code should not lie on a master branch.
#![allow(clippy::todo)]
// Although we generally try to avoid this, this can happen due to our module organization.
// In the future, this lint should be removed globally and only enabled for modules which
// actually require the use of it.
#![allow(clippy::module_inception)]
// False positives:
// TODO: Remove them in the future once they are no longer triggered.
// We only slice arrays, which are verified at compile time. This
// lint currently triggers for `&[T; N]`, which we pass around a lot.
#![allow(clippy::indexing_slicing)]
// We don't have any `unsafe` impl for types that derive `Deserialize`.
#![allow(clippy::unsafe_derive_deserialize)]
// Banning arithmetic is too strict for this project
#![allow(clippy::integer_arithmetic)]
// TODO: Remove once fixed
#![allow(
clippy::missing_inline_in_public_items, // Dubious lint
clippy::implicit_return, // We prefer tail returns where possible
clippy::shadow_reuse, // Very useful for arguments `arg: impl Into<U>; let arg = arg.into()`
clippy::if_not_else, // Sometimes it's easier to read with a negation
clippy::result_expect_used,
clippy::option_expect_used, // We use `.expect` when there is no safe alternative and the program is corrupt
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.
clippy::unseparated_literal_suffix, // We only separate them when they are long
clippy::match_same_arms, // Sometimes we separate them for clarify and order
clippy::missing_errors_doc, // We provide documentation on errors on the error type itself
clippy::todo, // Code that is incomplete should be tagged as such.
clippy::unreachable, // Some code should be unreachable and panic when reached.
clippy::integer_arithmetic, // Come on now, we need to use numbers to program
clippy::shadow_same, // Useful when taking arguments such as `value: impl AsRef<T>` / `let value = value.as_ref();`
clippy::module_inception, // Sometimes module organization causes this
clippy::missing_docs_in_private_items, // Not all private items are documented on purpose
clippy::indexing_slicing, // False-positives on arrays
// TODO: Deal with casts eventually
clippy::missing_docs_in_private_items,
clippy::as_conversions,
clippy::cast_possible_wrap,
clippy::cast_sign_loss,
clippy::cast_possible_truncation,
clippy::cast_possible_truncation
)]
// Modules