Support for schematics file format#263
Conversation
|
I think would be good to have an example schematic in |
I agree 👍. Will do once I get back at it |
dyc3
left a comment
There was a problem hiding this comment.
Haven't given it a super hard look yet.
| let mut instance = world | ||
| .resource::<Server>() | ||
| .new_instance(DimensionId::default()); | ||
|
|
||
| match Schematic::load(path) { | ||
| Ok(schem) => { | ||
| schem.paste(&mut instance, SPAWN_POS, |_| BiomeId::default()); | ||
| } | ||
| Err(err) => { | ||
| eprintln!("Error loading schematic: {err}"); | ||
| world.send_event(AppExit); | ||
| } | ||
| } |
There was a problem hiding this comment.
It would be nice to include this kind of thing in doc comments so it's visible to people looking at the docs.
There was a problem hiding this comment.
What exactly do you think should be in doc comments?
There was a problem hiding this comment.
A short explanation of what schematics are, examples for basic usage with a little context. You can look at the doc comments in the inventory module for reference.
|
Question: do we want to support all spec versions? (1-3) |
That seems like the most reasonable thing to do now. |
8555e08 to
dddc967
Compare
c5e8674 to
12cc6b7
Compare
0679801 to
ae387ff
Compare
|
@rj00a ready for review |
|
Currently working on a redesign of the |
8d04394 to
b69399d
Compare
b69399d to
13e0594
Compare
|
I've (finally) finished the redesign in #402, so we can move forward with this. |
Ok, I updated the branch to main |
dyc3
left a comment
There was a problem hiding this comment.
I gave it a quick look over again. This might need to be updated to reference chunk layers instead of instances.
There was a problem hiding this comment.
I think this code would be a bit easier to follow if it was split into "save" and "load" modules.
There was a problem hiding this comment.
Some documentation on the public items here would be appreciated.
| # use valence_schem::Schematic; | ||
| use flate2::Compression; |
There was a problem hiding this comment.
| # use valence_schem::Schematic; | |
| use flate2::Compression; | |
| use valence_schem::Schematic; | |
| # use valence_schem::Schematic; | ||
| use valence_nbt::Compound; |
There was a problem hiding this comment.
| # use valence_schem::Schematic; | |
| use valence_nbt::Compound; | |
| use valence_schem::Schematic; | |
| use valence_nbt::Compound; | |
|
|
||
| Support for the [Sponge schematic file format](https://github.com/SpongePowered/Schematic-Specification). | ||
|
|
||
| This crate implements [Sponge schematics] |
| let width = u16::try_from(max.x - min.x + 1).expect("width too large"); | ||
| let height = u16::try_from(max.y - min.y + 1).expect("height too large"); | ||
| let length = u16::try_from(max.z - min.z + 1).expect("length too large"); | ||
| let offset = IVec3::new(min.x - origin.x, min.y - origin.y, min.z - origin.z); | ||
| let blocks: Vec<_> = (min.y..=max.y) | ||
| .flat_map(|y| { | ||
| (min.z..=max.z).flat_map(move |z| { | ||
| (min.x..=max.x).map(move |x| { | ||
| let Some(block) = layer.block([x, y, z]) else { | ||
| panic!("coordinates ({x} {y} {z}) are out of bounds"); |
There was a problem hiding this comment.
We should return an error instead of panicking in these situations.
| .map(map_biome) | ||
| .enumerate() | ||
| .flat_map(|(idx, biome)| { | ||
| let idx = u16::try_from(idx).unwrap(); |
| (min.y..=max.y).map(move |y| { | ||
| layer | ||
| .chunk(ChunkPos::from_block_pos(BlockPos::new(x, y, z))) | ||
| .unwrap() |
There was a problem hiding this comment.
I'm seeing a lot of unwraps that are making me nervous. Consider if the unwrapping can panic.
| struct VarIntReader<I: ExactSizeIterator<Item = u8>>(I); | ||
| impl<I: ExactSizeIterator<Item = u8>> Iterator for VarIntReader<I> { | ||
| type Item = Result<i32, VarIntDecodeError>; | ||
|
|
||
| fn next(&mut self) -> Option<Self::Item> { | ||
| struct ReadWrapper<I: ExactSizeIterator<Item = u8>>(I); | ||
| impl<I: ExactSizeIterator<Item = u8>> Read for ReadWrapper<I> { | ||
| fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { | ||
| for (idx, byte) in buf.iter_mut().enumerate() { | ||
| let Some(val) = self.0.next() else { | ||
| return Ok(idx); | ||
| }; | ||
| *byte = val; | ||
| } | ||
| Ok(buf.len()) | ||
| } | ||
| } | ||
|
|
||
| if self.0.len() == 0 { | ||
| None | ||
| } else { | ||
| Some(VarInt::decode_partial(ReadWrapper(&mut self.0))) | ||
| } | ||
| } | ||
| } | ||
|
|
||
| struct VarIntWriteWrapper<'a>(&'a mut Vec<i8>); | ||
| impl<'a> Write for VarIntWriteWrapper<'a> { | ||
| fn write(&mut self, buf: &[u8]) -> io::Result<usize> { | ||
| self.0.extend(buf.iter().map(|byte| *byte as i8)); | ||
| Ok(buf.len()) | ||
| } | ||
|
|
||
| fn flush(&mut self) -> io::Result<()> { | ||
| Ok(()) | ||
| } | ||
| } |
There was a problem hiding this comment.
I'm going to expose some functions in valence_nbt that should make these wrappers unnecessary.
| .run(); | ||
| } | ||
|
|
||
| fn setup( |
There was a problem hiding this comment.
Chunks aren't being initialized here so the example isn't quite working.
# Objective When using valence_nbt, it's often necessary to convert to and from slices and vecs of `i8` and `u8`. But this requires unsafe code if you want to avoid copying things. # Solution Expose the following functions in valence_nbt: - `u8_vec_into_i8_vec(vec: Vec<u8>) -> Vec<i8>` - `i8_vec_into_u8_vec(vec: Vec<i8>) -> Vec<u8>` - `u8_slice_as_i8_slice(slice: &[u8]) -> &[i8]` - `i8_slice_as_u8_slice(slice: &[i8]) -> &[u8]` We've also made use of these functions ourselves to reduce the total amount of unsafe code. Should also help in #263
| let Some(kind) = BlockKind::from_str(kind) else { | ||
| return Err(ParseBlockStateError::UnknownBlockKind(kind.to_string())); | ||
| }; | ||
| props[..props.len() - 1] |
There was a problem hiding this comment.
This will panic if props is empty. Also it doesn't check if the last char is actually a ].
Description
valence_schemthat supports copying and pasting schematics to anInstanceand also allows for parsing them from aCompoundand serializing it back to oneTest Plan
The examples
schem_loadingandschem_savingare sufficient for testing. Also, as for a third party created schematic, I used SimpleSpongeSchematics to do so.To test, either:
try the example schematic by running
cargo r --example schem_loading -- assets/example_schem.schemOR:
schem_loadingwith the path of your schematic, like so:cargo r --example schem_loading -- "my/path/to/something_cool.schem"Related
Closes #193