diff --git a/ic10emu/src/lib.rs b/ic10emu/src/lib.rs index 498507d..4e4ebd2 100644 --- a/ic10emu/src/lib.rs +++ b/ic10emu/src/lib.rs @@ -61,6 +61,16 @@ pub struct SlotOccupant { fields: HashMap, } +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct SlotOccupantTemplate { + pub id: Option, + pub prefab_hash: i32, + pub quantity: u32, + pub max_quantity: u32, + pub damage: f64, + fields: HashMap, +} + impl SlotOccupant { pub fn new(id: u32, prefab_hash: i32) -> Self { SlotOccupant { @@ -113,12 +123,18 @@ impl SlotOccupant { } } -#[derive(Debug, Default, Serialize, Deserialize)] +#[derive(Debug, Default, Clone, Serialize, Deserialize)] pub struct Slot { pub typ: SlotType, pub occupant: Option, } +#[derive(Debug, Default, Clone, Serialize, Deserialize)] +pub struct SlotTemplate { + pub typ: SlotType, + pub occupant: Option, +} + impl Slot { pub fn new(typ: SlotType) -> Self { Slot { @@ -380,35 +396,49 @@ pub struct Network { pub channels: [f64; 8], } -#[derive(Debug, Default)] -struct IdSequenceGenerator { +#[derive(Debug)] +struct IdSpace { next: u32, + in_use: Vec, } -impl IdSequenceGenerator { +impl Default for IdSpace { + fn default() -> Self { + IdSpace::new() + } +} + +impl IdSpace { + pub fn new() -> Self { + IdSpace { + next: 1, + in_use: Vec::new(), + } + } + pub fn next(&mut self) -> u32 { let val = self.next; self.next += 1; + self.in_use.push(val); val } - pub fn next_free<'a, I>(&mut self, in_use: I) -> u32 - where - I: IntoIterator, - { - let sorted_in_use = in_use.into_iter().sorted(); - let mut last = None; - for val in sorted_in_use.into_iter() { - if val > &self.next && last.is_some_and(|last| (val - last) > 1) { - break; - } - last = Some(val); - } - if let Some(last) = last { - self.next = u32::max(*last, self.next) + 1; - self.next + pub fn use_id(&mut self, id: u32) -> Result<(), VMError> { + if self.in_use.contains(&id) { + Err(VMError::IdInUse(id)) } else { - self.next() + self.in_use.push(id); + Ok(()) + } + } + + pub fn free_id(&mut self, id: u32) { + if let Some((index, _)) = self + .in_use + .iter() + .find_position(|in_use_id| *in_use_id == &id) + { + self.in_use.swap_remove(index); } } } @@ -419,8 +449,8 @@ pub struct VM { pub devices: HashMap>>, pub networks: HashMap>>, pub default_network: u32, - id_gen: IdSequenceGenerator, - network_id_gen: IdSequenceGenerator, + id_space: IdSpace, + network_id_gen: IdSpace, random: Rc>, /// list of device id's touched on the last operation @@ -809,11 +839,11 @@ impl Default for VM { impl VM { pub fn new() -> Self { - let id_gen = IdSequenceGenerator::default(); - let mut network_id_gen = IdSequenceGenerator::default(); + let id_gen = IdSpace::default(); + let mut network_id_space = IdSpace::default(); let default_network = Rc::new(RefCell::new(Network::default())); let mut networks = HashMap::new(); - let default_network_key = network_id_gen.next(); + let default_network_key = network_id_space.next(); networks.insert(default_network_key, default_network); let mut vm = VM { @@ -821,8 +851,8 @@ impl VM { devices: HashMap::new(), networks, default_network: default_network_key, - id_gen, - network_id_gen, + id_space: id_gen, + network_id_gen: network_id_space, random: Rc::new(RefCell::new(crate::rand_mscorlib::Random::new())), operation_modified: RefCell::new(Vec::new()), }; @@ -831,16 +861,12 @@ impl VM { } fn new_device(&mut self) -> Device { - Device::new(self.id_gen.next()) + Device::new(self.id_space.next()) } fn new_ic(&mut self) -> (Device, interpreter::IC) { - let id = self - .id_gen - .next_free(self.devices.keys().chain(self.ics.keys())); - let ic_id = self - .id_gen - .next_free(self.devices.keys().chain(self.ics.keys())); + let id = self.id_space.next(); + let ic_id = self.id_space.next(); let ic = interpreter::IC::new(ic_id, id); let device = Device::with_ic(id, ic_id); (device, ic) @@ -973,9 +999,7 @@ impl VM { } pub fn change_device_id(&mut self, old_id: u32, new_id: u32) -> Result<(), VMError> { - if self.devices.contains_key(&new_id) | self.ics.contains_key(&new_id) { - return Err(VMError::IdInUse(new_id)); - } + self.id_space.use_id(new_id)?; let device = self .devices .remove(&old_id) @@ -998,6 +1022,7 @@ impl VM { } } }); + self.id_space.free_id(old_id); Ok(()) } @@ -1399,14 +1424,14 @@ impl BatchMode { pub fn apply(&self, samples: &[f64]) -> f64 { match self { BatchMode::Sum => samples.iter().sum(), - /// Both c-charp and rust return NaN for 0.0/0.0 so we're good here + // Both c-charp and rust return NaN for 0.0/0.0 so we're good here BatchMode::Average => samples.iter().copied().sum::() / samples.len() as f64, - /// Game uses a default of Positive INFINITY for Minimum + // Game uses a default of Positive INFINITY for Minimum BatchMode::Minimum => *samples .iter() .min_by(|a, b| a.partial_cmp(b).unwrap()) .unwrap_or(&f64::INFINITY), - /// Game uses default of NEG_INFINITY for Maximum + // Game uses default of NEG_INFINITY for Maximum BatchMode::Maximum => *samples .iter() .max_by(|a, b| a.partial_cmp(b).unwrap())