147 lines
3.9 KiB
Rust
147 lines
3.9 KiB
Rust
use std::io::{Read, Write, self, Seek};
|
|
|
|
use byteorder::{WriteBytesExt, BE, ReadBytesExt};
|
|
|
|
pub const IS_FUEL: u8 = 1;
|
|
pub const IS_WDRF: u8 = 2;
|
|
pub const IS_NEUT: u8 = 4;
|
|
|
|
#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
|
|
pub struct Point(pub i32, pub i32, pub i32);
|
|
#[derive(Copy, Clone, Debug)]
|
|
pub struct Box(pub Point, pub Point);
|
|
|
|
const fn isortp(a: i32, b: i32) -> (i32, i32) {
|
|
if a < b { (a,b) } else { (b,a) }
|
|
}
|
|
|
|
impl Box {
|
|
pub const fn from_corners(x: Point, y: Point) -> Box {
|
|
let (ax, bx) = isortp(x.0, y.0);
|
|
let (ay, by) = isortp(x.1, y.1);
|
|
let (az, bz) = isortp(x.2, y.2);
|
|
|
|
let pt1 = Point(ax, ay, az);
|
|
let pt2 = Point(bx, by, bz);
|
|
|
|
Box(pt1, pt2)
|
|
}
|
|
|
|
pub fn contains(&self, x: Point) -> bool {
|
|
return
|
|
(self.0 .0 .. self.1 .0).contains(&x.0) &&
|
|
(self.0 .1 .. self.1 .1).contains(&x.1) &&
|
|
(self.0 .2 .. self.1 .2).contains(&x.2);
|
|
}
|
|
|
|
}
|
|
|
|
#[derive(Default)]
|
|
pub struct System {
|
|
pub coords: Point,
|
|
pub name: String,
|
|
pub name_off: usize,
|
|
pub star_flags: u8,
|
|
}
|
|
|
|
impl System {
|
|
pub fn write_name(&self, writer: &mut dyn Write) -> io::Result<usize> {
|
|
let name_len = self.name.len().min(255);
|
|
writer.write_u8(name_len as u8)?;
|
|
writer.write(&self.name.as_bytes()[..name_len])?;
|
|
|
|
return Ok(name_len + 1);
|
|
}
|
|
pub fn write_to(&self, writer: &mut dyn Write) -> io::Result<()> {
|
|
writer.write_i32::<BE>(self.coords.0)?;
|
|
writer.write_i32::<BE>(self.coords.1)?;
|
|
writer.write_i32::<BE>(self.coords.2)?;
|
|
let rest = self.star_flags as u32 + ((self.name_off as u32) << 4);
|
|
writer.write_u32::<BE>(rest)?;
|
|
Ok(())
|
|
}
|
|
|
|
pub fn read_from(r: &mut dyn Read) -> io::Result<Self> {
|
|
let x = r.read_i32::<BE>()?;
|
|
let y = r.read_i32::<BE>()?;
|
|
let z = r.read_i32::<BE>()?;
|
|
let rest = r.read_u32::<BE>()?;
|
|
let name_off = (rest >> 4) as usize;
|
|
let star_flags = (rest & 0xF) as u8;
|
|
Ok(System{
|
|
coords: Point(x,y,z),
|
|
name: String::new(),
|
|
name_off,
|
|
star_flags,
|
|
})
|
|
}
|
|
|
|
pub fn read_name<R: Read + Seek>(&mut self, r: &mut R) -> io::Result<()> {
|
|
//eprint!(".");
|
|
r.seek(io::SeekFrom::Start(self.name_off as u64))?;
|
|
let mut buf = vec![];
|
|
let len = r.read_u8()? as usize;
|
|
//eprintln!("Reading {len} bytes from {}", self.name_off);
|
|
buf.resize(len, 0);
|
|
r.read_exact(buf.as_mut_slice())?;
|
|
self.name = String::from_utf8(buf)
|
|
.map_err(|err| io::Error::new(io::ErrorKind::InvalidData, err))?;
|
|
|
|
Ok(())
|
|
}
|
|
|
|
pub fn jump_scale(&self) -> f32 {
|
|
if self.star_flags & IS_NEUT != 0 {
|
|
4.0
|
|
} else if self.star_flags & IS_WDRF != 0 {
|
|
1.5
|
|
} else {
|
|
0.
|
|
}
|
|
}
|
|
}
|
|
|
|
impl rstar::Point for Point {
|
|
type Scalar = i32;
|
|
const DIMENSIONS: usize = 3;
|
|
fn generate(mut gen: impl FnMut(usize) -> Self::Scalar) -> Self {
|
|
let x = gen(0);
|
|
let y = gen(1);
|
|
let z = gen(2);
|
|
Self(x,y,z)
|
|
}
|
|
|
|
fn nth(&self, index: usize) -> Self::Scalar {
|
|
match index {
|
|
0 => self.0,
|
|
1 => self.1,
|
|
2 => self.2,
|
|
_ => 0 as Self::Scalar,
|
|
}
|
|
}
|
|
|
|
fn nth_mut(&mut self, index: usize) -> &mut Self::Scalar {
|
|
match index {
|
|
0 => &mut self.0,
|
|
1 => &mut self.1,
|
|
_ => &mut self.2,
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
impl Point {
|
|
pub fn distance_sq(&self, other: Self) -> f32 {
|
|
let Point(sx, sy, sz) = *self;
|
|
let Point(tx, ty, tz) = other;
|
|
let dx = sx as f32 - tx as f32;
|
|
let dy = sy as f32 - ty as f32;
|
|
let dz = sz as f32 - tz as f32;
|
|
(dx*dx) + (dy*dy) + (dz*dz)
|
|
}
|
|
|
|
pub fn distance(&self, other: Self) -> f32 {
|
|
self.distance_sq(other).sqrt()
|
|
}
|
|
}
|