update for v7
This commit is contained in:
parent
ef9cce0d68
commit
a341491bf8
9 changed files with 315 additions and 59 deletions
7
.gitignore
vendored
7
.gitignore
vendored
|
|
@ -1,3 +1,8 @@
|
||||||
/target
|
/target
|
||||||
Cargo.lock
|
Cargo.lock
|
||||||
.vscode
|
.vscode
|
||||||
|
|
||||||
|
# Local dir names for temporary data
|
||||||
|
/data
|
||||||
|
/work
|
||||||
|
/tmp
|
||||||
|
|
|
||||||
11
README.md
11
README.md
|
|
@ -6,15 +6,16 @@ Blotter file format parser and Logic World sandbox editor in Rust.
|
||||||
|
|
||||||
This is the version that is supported for loading/saving and high-level editing:
|
This is the version that is supported for loading/saving and high-level editing:
|
||||||
|
|
||||||
- **Blotter v6** (Logic World 0.91 beta)
|
- [**Blotter v7**][spec-v7] (Logic World 0.92)
|
||||||
- Not formalized yet, mostly same as v5, but component positions are
|
|
||||||
integers and custom data formats changed for some components
|
|
||||||
|
|
||||||
## Legacy versions
|
## Legacy versions
|
||||||
|
|
||||||
There are no high-level APIs for these versions, but converting the savefile to
|
There are no high-level APIs for these versions, but converting the savefile to
|
||||||
newer versions is supported:
|
newer versions is supported:
|
||||||
|
|
||||||
- [**Blotter v5**][v5] (Logic World 0.90)
|
- [**Blotter v5**][spec-v5] (Logic World 0.90)
|
||||||
|
- [**Blotter v6**][spec-v6] (Logic World 0.91)
|
||||||
|
|
||||||
[v5]: https://gist.github.com/JimmyCushnie/bebea37a21acbb6e669589967f9512a2
|
[spec-v5]: https://gist.github.com/JimmyCushnie/bebea37a21acbb6e669589967f9512a2/f3023f8ea859d1326c50ab71ac1a76cecabb3386
|
||||||
|
[spec-v6]: https://gist.github.com/JimmyCushnie/bebea37a21acbb6e669589967f9512a2/d02f96a57d72d6116321e4884e34551f65d3d342
|
||||||
|
[spec-v7]: https://wiki.logic.world/wiki/Blotter_File_Format/v7
|
||||||
|
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
mod v5v6;
|
|
||||||
|
|
@ -1,39 +0,0 @@
|
||||||
use crate::{v5, v6};
|
|
||||||
|
|
||||||
impl From<v5::BlotterFile> for v6::BlotterFile {
|
|
||||||
fn from(file: v5::BlotterFile) -> Self {
|
|
||||||
Self {
|
|
||||||
game_version: file.game_version,
|
|
||||||
save_type: file.save_type,
|
|
||||||
mods: file.mods,
|
|
||||||
component_types: file.component_types,
|
|
||||||
components: file.components.into_iter().map(Into::into).collect(),
|
|
||||||
wires: file.wires,
|
|
||||||
circuit_states: file.circuit_states,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<v5::Component> for v6::Component {
|
|
||||||
fn from(component: v5::Component) -> Self {
|
|
||||||
Self {
|
|
||||||
address: component.address,
|
|
||||||
parent: component.parent,
|
|
||||||
type_id: component.type_id,
|
|
||||||
position: floating_to_fixed_position(component.position),
|
|
||||||
rotation: component.rotation,
|
|
||||||
inputs: component.inputs,
|
|
||||||
outputs: component.outputs,
|
|
||||||
custom_data: component.custom_data,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn floating_to_fixed_position([x, y, z]: [f32; 3]) -> [i32; 3] {
|
|
||||||
const CONVERSION_FACTOR: f32 = 1000.0;
|
|
||||||
[
|
|
||||||
(x * CONVERSION_FACTOR) as i32,
|
|
||||||
(y * CONVERSION_FACTOR) as i32,
|
|
||||||
(z * CONVERSION_FACTOR) as i32,
|
|
||||||
]
|
|
||||||
}
|
|
||||||
10
src/lib.rs
10
src/lib.rs
|
|
@ -1,4 +1,3 @@
|
||||||
mod convert;
|
|
||||||
pub mod custom_data;
|
pub mod custom_data;
|
||||||
pub mod error;
|
pub mod error;
|
||||||
pub(crate) mod io;
|
pub(crate) mod io;
|
||||||
|
|
@ -6,18 +5,20 @@ pub(crate) mod misc;
|
||||||
pub mod sandbox;
|
pub mod sandbox;
|
||||||
pub mod v5;
|
pub mod v5;
|
||||||
pub mod v6;
|
pub mod v6;
|
||||||
|
pub mod v7;
|
||||||
|
|
||||||
use std::io::{Read, Write};
|
use std::io::{Read, Write};
|
||||||
|
|
||||||
use crate::error::Error;
|
use crate::error::Error;
|
||||||
use crate::io::{read_magic, ReadFrom};
|
use crate::io::{read_magic, ReadFrom};
|
||||||
|
|
||||||
pub use v6 as latest;
|
pub use v7 as latest;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum BlotterFile {
|
pub enum BlotterFile {
|
||||||
V5(v5::BlotterFile),
|
V5(v5::BlotterFile),
|
||||||
V6(v6::BlotterFile),
|
V6(v6::BlotterFile),
|
||||||
|
V7(v7::BlotterFile),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BlotterFile {
|
impl BlotterFile {
|
||||||
|
|
@ -27,6 +28,7 @@ impl BlotterFile {
|
||||||
match save_version {
|
match save_version {
|
||||||
v5::SAVE_VERSION => v5::BlotterFile::read_after_save_version(reader).map(Self::V5),
|
v5::SAVE_VERSION => v5::BlotterFile::read_after_save_version(reader).map(Self::V5),
|
||||||
v6::SAVE_VERSION => v6::BlotterFile::read_after_save_version(reader).map(Self::V6),
|
v6::SAVE_VERSION => v6::BlotterFile::read_after_save_version(reader).map(Self::V6),
|
||||||
|
v7::SAVE_VERSION => v7::BlotterFile::read_after_save_version(reader).map(Self::V7),
|
||||||
_ => Err(Error::IncompatibleVersion(save_version)),
|
_ => Err(Error::IncompatibleVersion(save_version)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -35,6 +37,7 @@ impl BlotterFile {
|
||||||
match self {
|
match self {
|
||||||
Self::V5(file) => file.write(writer),
|
Self::V5(file) => file.write(writer),
|
||||||
Self::V6(file) => file.write(writer),
|
Self::V6(file) => file.write(writer),
|
||||||
|
Self::V7(file) => file.write(writer),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -42,7 +45,8 @@ impl BlotterFile {
|
||||||
pub fn migrate(self) -> latest::BlotterFile {
|
pub fn migrate(self) -> latest::BlotterFile {
|
||||||
match self {
|
match self {
|
||||||
Self::V5(file) => Self::V6(file.into()).migrate(),
|
Self::V5(file) => Self::V6(file.into()).migrate(),
|
||||||
Self::V6(file) => file,
|
Self::V6(file) => Self::V7(file.into()).migrate(),
|
||||||
|
Self::V7(file) => file,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ use crate::latest as blotter;
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
|
|
||||||
/// The current game version that this save is compatible with.
|
/// The current game version that this save is compatible with.
|
||||||
const GAME_VERSION: [i32; 4] = [0, 91, 0, 510];
|
const GAME_VERSION: [i32; 4] = [0, 92, 4, 18];
|
||||||
|
|
||||||
/// Serialization context, mainly tracks ID mappings
|
/// Serialization context, mainly tracks ID mappings
|
||||||
struct Serializer {
|
struct Serializer {
|
||||||
|
|
|
||||||
16
src/v5.rs
16
src/v5.rs
|
|
@ -9,7 +9,7 @@ pub const SAVE_FOOTER: &[u8; 16] = b"redstone sux lol";
|
||||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||||
pub enum SaveType {
|
pub enum SaveType {
|
||||||
World,
|
World,
|
||||||
Subassembly,
|
PartialWorld,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ReadFrom for SaveType {
|
impl ReadFrom for SaveType {
|
||||||
|
|
@ -17,7 +17,7 @@ impl ReadFrom for SaveType {
|
||||||
let id = u8::read_from(reader)?;
|
let id = u8::read_from(reader)?;
|
||||||
match id {
|
match id {
|
||||||
1 => Ok(Self::World),
|
1 => Ok(Self::World),
|
||||||
2 => Ok(Self::Subassembly),
|
2 => Ok(Self::PartialWorld),
|
||||||
_ => Err(Error::InvalidSave),
|
_ => Err(Error::InvalidSave),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -27,7 +27,7 @@ impl WriteTo for SaveType {
|
||||||
fn write_to<W: Write>(&self, writer: &mut W) -> Result<(), Error> {
|
fn write_to<W: Write>(&self, writer: &mut W) -> Result<(), Error> {
|
||||||
let id: u8 = match self {
|
let id: u8 = match self {
|
||||||
Self::World => 1,
|
Self::World => 1,
|
||||||
Self::Subassembly => 2,
|
Self::PartialWorld => 2,
|
||||||
};
|
};
|
||||||
id.write_to(writer)?;
|
id.write_to(writer)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
@ -291,7 +291,7 @@ impl WriteTo for Wire {
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum CircuitStates {
|
pub enum CircuitStates {
|
||||||
WorldFormat { circuit_states: Vec<u8> },
|
WorldFormat { circuit_states: Vec<u8> },
|
||||||
SubassemblyFormat { on_states: Vec<i32> },
|
PartialWorldFormat { on_states: Vec<i32> },
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ReadFromSeed<SaveType> for CircuitStates {
|
impl ReadFromSeed<SaveType> for CircuitStates {
|
||||||
|
|
@ -303,10 +303,10 @@ impl ReadFromSeed<SaveType> for CircuitStates {
|
||||||
reader.read_exact(&mut circuit_states)?;
|
reader.read_exact(&mut circuit_states)?;
|
||||||
Ok(Self::WorldFormat { circuit_states })
|
Ok(Self::WorldFormat { circuit_states })
|
||||||
}
|
}
|
||||||
SaveType::Subassembly => {
|
SaveType::PartialWorld => {
|
||||||
let num_on_states = usize::read_from(reader)?;
|
let num_on_states = usize::read_from(reader)?;
|
||||||
let on_states = Vec::read_from_seed(reader, Length(num_on_states))?;
|
let on_states = Vec::read_from_seed(reader, Length(num_on_states))?;
|
||||||
Ok(Self::SubassemblyFormat { on_states })
|
Ok(Self::PartialWorldFormat { on_states })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -319,7 +319,7 @@ impl WriteTo for CircuitStates {
|
||||||
circuit_states.len().write_to(writer)?;
|
circuit_states.len().write_to(writer)?;
|
||||||
writer.write_all(&circuit_states)?;
|
writer.write_all(&circuit_states)?;
|
||||||
}
|
}
|
||||||
Self::SubassemblyFormat { on_states } => {
|
Self::PartialWorldFormat { on_states } => {
|
||||||
on_states.len().write_to(writer)?;
|
on_states.len().write_to(writer)?;
|
||||||
on_states.write_to(writer)?;
|
on_states.write_to(writer)?;
|
||||||
}
|
}
|
||||||
|
|
@ -416,7 +416,7 @@ impl BlotterFile {
|
||||||
|
|
||||||
match (self.save_type, &self.circuit_states) {
|
match (self.save_type, &self.circuit_states) {
|
||||||
(SaveType::World, CircuitStates::WorldFormat { .. }) => {}
|
(SaveType::World, CircuitStates::WorldFormat { .. }) => {}
|
||||||
(SaveType::Subassembly, CircuitStates::SubassemblyFormat { .. }) => {}
|
(SaveType::PartialWorld, CircuitStates::PartialWorldFormat { .. }) => {}
|
||||||
_ => {
|
_ => {
|
||||||
return Err(Error::InvalidSave);
|
return Err(Error::InvalidSave);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
41
src/v6.rs
41
src/v6.rs
|
|
@ -1,5 +1,6 @@
|
||||||
use crate::error::Error;
|
use crate::error::Error;
|
||||||
use crate::io::*;
|
use crate::io::*;
|
||||||
|
use crate::v5;
|
||||||
use std::io::{Read, Write};
|
use std::io::{Read, Write};
|
||||||
|
|
||||||
pub const SAVE_VERSION: u8 = 6;
|
pub const SAVE_VERSION: u8 = 6;
|
||||||
|
|
@ -85,6 +86,30 @@ impl WriteTo for Component {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<v5::Component> for Component {
|
||||||
|
fn from(component: v5::Component) -> Self {
|
||||||
|
Self {
|
||||||
|
address: component.address,
|
||||||
|
parent: component.parent,
|
||||||
|
type_id: component.type_id,
|
||||||
|
position: v5_position_to_v6(component.position),
|
||||||
|
rotation: component.rotation,
|
||||||
|
inputs: component.inputs,
|
||||||
|
outputs: component.outputs,
|
||||||
|
custom_data: component.custom_data,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn v5_position_to_v6([x, y, z]: [f32; 3]) -> [i32; 3] {
|
||||||
|
const CONVERSION_FACTOR: f32 = 1000.0;
|
||||||
|
[
|
||||||
|
(x * CONVERSION_FACTOR) as i32,
|
||||||
|
(y * CONVERSION_FACTOR) as i32,
|
||||||
|
(z * CONVERSION_FACTOR) as i32,
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct BlotterFile {
|
pub struct BlotterFile {
|
||||||
pub game_version: [i32; 4],
|
pub game_version: [i32; 4],
|
||||||
|
|
@ -173,7 +198,7 @@ impl BlotterFile {
|
||||||
|
|
||||||
match (self.save_type, &self.circuit_states) {
|
match (self.save_type, &self.circuit_states) {
|
||||||
(SaveType::World, CircuitStates::WorldFormat { .. }) => {}
|
(SaveType::World, CircuitStates::WorldFormat { .. }) => {}
|
||||||
(SaveType::Subassembly, CircuitStates::SubassemblyFormat { .. }) => {}
|
(SaveType::PartialWorld, CircuitStates::PartialWorldFormat { .. }) => {}
|
||||||
_ => {
|
_ => {
|
||||||
return Err(Error::InvalidSave);
|
return Err(Error::InvalidSave);
|
||||||
}
|
}
|
||||||
|
|
@ -184,3 +209,17 @@ impl BlotterFile {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<v5::BlotterFile> for BlotterFile {
|
||||||
|
fn from(file: v5::BlotterFile) -> Self {
|
||||||
|
Self {
|
||||||
|
game_version: file.game_version,
|
||||||
|
save_type: file.save_type,
|
||||||
|
mods: file.mods,
|
||||||
|
component_types: file.component_types,
|
||||||
|
components: file.components.into_iter().map(Into::into).collect(),
|
||||||
|
wires: file.wires,
|
||||||
|
circuit_states: file.circuit_states,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
247
src/v7.rs
Normal file
247
src/v7.rs
Normal file
|
|
@ -0,0 +1,247 @@
|
||||||
|
use crate::error::Error;
|
||||||
|
use crate::io::*;
|
||||||
|
use crate::v6;
|
||||||
|
use std::io::{Read, Write};
|
||||||
|
|
||||||
|
pub const SAVE_VERSION: u8 = 7;
|
||||||
|
|
||||||
|
// Unchanged from previous version:
|
||||||
|
pub use crate::v6::{
|
||||||
|
CircuitStates, Component, ComponentType, Input, ModInfo, Output, SaveType, SAVE_FOOTER,
|
||||||
|
SAVE_HEADER,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub enum PegType {
|
||||||
|
Input,
|
||||||
|
Output,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ReadFrom for PegType {
|
||||||
|
fn read_from<R: Read>(reader: &mut R) -> Result<Self, Error> {
|
||||||
|
let id = u8::read_from(reader)?;
|
||||||
|
match id {
|
||||||
|
1 => Ok(Self::Input),
|
||||||
|
2 => Ok(Self::Output),
|
||||||
|
_ => Err(Error::InvalidSave),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WriteTo for PegType {
|
||||||
|
fn write_to<W: Write>(&self, writer: &mut W) -> Result<(), Error> {
|
||||||
|
let id: u8 = match self {
|
||||||
|
Self::Input => 1,
|
||||||
|
Self::Output => 2,
|
||||||
|
};
|
||||||
|
id.write_to(writer)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<v6::PegType> for PegType {
|
||||||
|
fn from(x: v6::PegType) -> Self {
|
||||||
|
match x {
|
||||||
|
v6::PegType::Input => Self::Input,
|
||||||
|
v6::PegType::Output => Self::Output,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub struct PegAddress {
|
||||||
|
pub peg_type: PegType,
|
||||||
|
pub component_address: u32,
|
||||||
|
pub peg_index: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ReadFrom for PegAddress {
|
||||||
|
fn read_from<R: Read>(reader: &mut R) -> Result<Self, Error> {
|
||||||
|
let peg_type = ReadFrom::read_from(reader)?;
|
||||||
|
let component_address = ReadFrom::read_from(reader)?;
|
||||||
|
let peg_index = ReadFrom::read_from(reader)?;
|
||||||
|
|
||||||
|
Ok(Self {
|
||||||
|
peg_type,
|
||||||
|
component_address,
|
||||||
|
peg_index,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WriteTo for PegAddress {
|
||||||
|
fn write_to<W: Write>(&self, writer: &mut W) -> Result<(), Error> {
|
||||||
|
self.peg_type.write_to(writer)?;
|
||||||
|
self.component_address.write_to(writer)?;
|
||||||
|
self.peg_index.write_to(writer)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<v6::PegAddress> for PegAddress {
|
||||||
|
fn from(x: v6::PegAddress) -> Self {
|
||||||
|
Self {
|
||||||
|
peg_type: x.peg_type.into(),
|
||||||
|
component_address: x.component_address,
|
||||||
|
peg_index: x.peg_index,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Wire {
|
||||||
|
pub start_peg: PegAddress,
|
||||||
|
pub end_peg: PegAddress,
|
||||||
|
pub circuit_state_id: i32,
|
||||||
|
pub rotation: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ReadFrom for Wire {
|
||||||
|
fn read_from<R: Read>(reader: &mut R) -> Result<Self, Error> {
|
||||||
|
let start_peg = ReadFrom::read_from(reader)?;
|
||||||
|
let end_peg = ReadFrom::read_from(reader)?;
|
||||||
|
let circuit_state_id = ReadFrom::read_from(reader)?;
|
||||||
|
let rotation = ReadFrom::read_from(reader)?;
|
||||||
|
Ok(Self {
|
||||||
|
start_peg,
|
||||||
|
end_peg,
|
||||||
|
circuit_state_id,
|
||||||
|
rotation,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WriteTo for Wire {
|
||||||
|
fn write_to<W: Write>(&self, writer: &mut W) -> Result<(), Error> {
|
||||||
|
self.start_peg.write_to(writer)?;
|
||||||
|
self.end_peg.write_to(writer)?;
|
||||||
|
self.circuit_state_id.write_to(writer)?;
|
||||||
|
self.rotation.write_to(writer)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<v6::Wire> for Wire {
|
||||||
|
fn from(x: v6::Wire) -> Self {
|
||||||
|
Self {
|
||||||
|
start_peg: x.start_peg.into(),
|
||||||
|
end_peg: x.end_peg.into(),
|
||||||
|
circuit_state_id: x.circuit_state_id,
|
||||||
|
rotation: x.rotation,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct BlotterFile {
|
||||||
|
pub game_version: [i32; 4],
|
||||||
|
pub save_type: SaveType,
|
||||||
|
pub mods: Vec<ModInfo>,
|
||||||
|
pub component_types: Vec<ComponentType>,
|
||||||
|
pub components: Vec<Component>,
|
||||||
|
pub wires: Vec<Wire>,
|
||||||
|
pub circuit_states: CircuitStates,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BlotterFile {
|
||||||
|
pub fn new(game_version: [i32; 4]) -> Self {
|
||||||
|
Self {
|
||||||
|
game_version,
|
||||||
|
save_type: SaveType::World,
|
||||||
|
mods: Vec::new(),
|
||||||
|
component_types: Vec::new(),
|
||||||
|
components: Vec::new(),
|
||||||
|
wires: Vec::new(),
|
||||||
|
circuit_states: CircuitStates::WorldFormat {
|
||||||
|
circuit_states: Vec::new(),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn read<R: Read>(reader: &mut R) -> Result<Self, Error> {
|
||||||
|
read_magic(reader, SAVE_HEADER)?;
|
||||||
|
|
||||||
|
let save_version = u8::read_from(reader)?;
|
||||||
|
if save_version != SAVE_VERSION {
|
||||||
|
return Err(Error::IncompatibleVersion(save_version));
|
||||||
|
}
|
||||||
|
Self::read_after_save_version(reader)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn read_after_save_version<R: Read>(reader: &mut R) -> Result<Self, Error> {
|
||||||
|
let game_version = ReadFrom::read_from(reader)?;
|
||||||
|
|
||||||
|
let save_type = SaveType::read_from(reader)?;
|
||||||
|
let num_components = usize::read_from(reader)?;
|
||||||
|
let num_wires = usize::read_from(reader)?;
|
||||||
|
|
||||||
|
let num_mods = usize::read_from(reader)?;
|
||||||
|
let mods = Vec::read_from_seed(reader, Length(num_mods))?;
|
||||||
|
|
||||||
|
let num_component_types: usize = usize::read_from(reader)?;
|
||||||
|
let component_types = Vec::read_from_seed(reader, Length(num_component_types))?;
|
||||||
|
|
||||||
|
let components = Vec::read_from_seed(reader, Length(num_components))?;
|
||||||
|
let wires = Vec::read_from_seed(reader, Length(num_wires))?;
|
||||||
|
|
||||||
|
let circuit_states = CircuitStates::read_from_seed(reader, save_type)?;
|
||||||
|
|
||||||
|
read_magic(reader, SAVE_FOOTER)?;
|
||||||
|
|
||||||
|
Ok(Self {
|
||||||
|
game_version,
|
||||||
|
save_type,
|
||||||
|
mods,
|
||||||
|
component_types,
|
||||||
|
components,
|
||||||
|
wires,
|
||||||
|
circuit_states,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn write<W: Write>(&self, writer: &mut W) -> Result<(), Error> {
|
||||||
|
writer.write_all(SAVE_HEADER)?;
|
||||||
|
|
||||||
|
SAVE_VERSION.write_to(writer)?;
|
||||||
|
self.game_version.write_to(writer)?;
|
||||||
|
self.save_type.write_to(writer)?;
|
||||||
|
|
||||||
|
self.components.len().write_to(writer)?;
|
||||||
|
self.wires.len().write_to(writer)?;
|
||||||
|
|
||||||
|
self.mods.len().write_to(writer)?;
|
||||||
|
self.mods.write_to(writer)?;
|
||||||
|
|
||||||
|
self.component_types.len().write_to(writer)?;
|
||||||
|
self.component_types.write_to(writer)?;
|
||||||
|
|
||||||
|
self.components.write_to(writer)?;
|
||||||
|
self.wires.write_to(writer)?;
|
||||||
|
|
||||||
|
match (self.save_type, &self.circuit_states) {
|
||||||
|
(SaveType::World, CircuitStates::WorldFormat { .. }) => {}
|
||||||
|
(SaveType::PartialWorld, CircuitStates::PartialWorldFormat { .. }) => {}
|
||||||
|
_ => {
|
||||||
|
return Err(Error::InvalidSave);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.circuit_states.write_to(writer)?;
|
||||||
|
|
||||||
|
writer.write_all(SAVE_FOOTER)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<v6::BlotterFile> for BlotterFile {
|
||||||
|
fn from(x: v6::BlotterFile) -> Self {
|
||||||
|
Self {
|
||||||
|
game_version: x.game_version,
|
||||||
|
save_type: x.save_type,
|
||||||
|
mods: x.mods,
|
||||||
|
component_types: x.component_types,
|
||||||
|
components: x.components,
|
||||||
|
wires: x.wires.into_iter().map(Into::into).collect(),
|
||||||
|
circuit_states: x.circuit_states,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Reference in a new issue