From 1251d07c6059b2f6996dad4b0bfb724d64011b88 Mon Sep 17 00:00:00 2001 From: griffi-gh Date: Wed, 11 Sep 2024 14:18:44 +0200 Subject: [PATCH] implement more item functions --- kubi-server/src/main.rs | 2 +- kubi-shared/src/item.rs | 175 ++++++++++++++++++++++++++++++++++++++-- 2 files changed, 171 insertions(+), 6 deletions(-) diff --git a/kubi-server/src/main.rs b/kubi-server/src/main.rs index eca8753..f9358c0 100644 --- a/kubi-server/src/main.rs +++ b/kubi-server/src/main.rs @@ -1,4 +1,4 @@ -use shipyard::{IntoWorkload, SystemModificator, Workload, WorkloadModificator, World}; +use shipyard::{IntoWorkload, Workload, WorkloadModificator, World}; use std::{thread, time::Duration}; use kubi_shared::fixed_timestamp::{FixedTimestamp, init_fixed_timestamp_storage}; diff --git a/kubi-shared/src/item.rs b/kubi-shared/src/item.rs index bd16f61..5a3664d 100644 --- a/kubi-shared/src/item.rs +++ b/kubi-shared/src/item.rs @@ -38,29 +38,194 @@ impl Item { pub struct ItemCollection(Option<(Item, NonZeroU8)>); impl ItemCollection { - pub const fn new(item: Item, amount: NonZeroU8) -> Self { + /// Create a new item collection with `amount` of `item` + /// + /// If `amount` is 0, the slot will be empty, and the item will be ignored + pub const fn new(item: Item, amount: u8) -> Self { + if amount == 0 { + return Self::new_empty() + } + // SAFETY: `amount` guaranteed to be non-zero + let amount = unsafe { NonZeroU8::new_unchecked(amount) }; + Self::new_nonzero(item, amount) + } + + /// Create a new item collection with `amount` of `item` + pub const fn new_nonzero(item: Item, amount: NonZeroU8) -> Self { Self(Some((item, amount))) } + /// Create a new item collection with a single item pub const fn new_single(item: Item) -> Self { Self(Some((item, nz::u8!(1)))) } + /// Create a new empty item collection pub const fn new_empty() -> Self { Self(None) } - pub const fn with_amount(&self, amount: NonZeroU8) -> Self { + /// Set the amount of items in the slot to `amount`\ + /// + /// If `amount` is 0, the slot will be emptied\ + /// If slot is empty, this will do nothing, even if `amount` is non-zero + pub const fn with_amount(&self, amount: u8) -> Self { + if amount == 0 { + return Self::new_empty() + } + // SAFETY: `amount` guaranteed to be non-zero + let amount = unsafe { NonZeroU8::new_unchecked(amount) }; + self.with_amount_nonzero(amount) + } + + /// Set the amount of items in the slot to `amount` + /// + /// If slot is empty, this will do nothing + pub const fn with_amount_nonzero(&self, amount: NonZeroU8) -> Self { Self(match self.0 { Some((item, _)) => Some((item, amount)), None => None, }) } + /// Check if the slot is empty (contains no items) + pub const fn is_empty(&self) -> bool { + self.0.is_none() + } + + /// Check if the slot is full (contains the maximum stack size) + pub const fn is_full(&self) -> bool { + match self.0 { + Some((item, amount)) => { + amount.get() >= item.descriptor().stack_size.get() + }, + None => false, + } + } + + /// Get the item in the slot + /// + /// If the slot is empty, returns None + pub const fn item(&self) -> Option { + match self.0 { + Some((item, _)) => Some(item), + None => None, + } + } + + /// Get the amount of items in the slot + /// + /// If the slot is empty, returns 0 + pub const fn amount(&self) -> u8 { + match self.0 { + Some((_, amount)) => amount.get(), + None => 0, + } + } + + /// Get the amount of items in the slot + /// + /// If the slot is empty, returns None + pub const fn amount_nonzero(&self) -> Option { + match self.0 { + Some((_, amount)) => Some(amount), + None => None, + } + } + /// Add items from another slot, copying them\ - /// Returns the leftover items + /// Returns the leftover items (items that could not be added) pub fn add(&mut self, from: &Self) -> Self { - let Some((item, count)) = from.0 else { return Self::new_empty() }; - todo!() //TODO finish item slot system + // If there are no items to add, return + let Some((add_item, add_count)) = from.0 else { + return Self::new_empty() + }; + let item_stack_size = add_item.descriptor().stack_size; + + // Add items to the slot + let (this_slot, leftovers) = match self.0 { + None => ( + ( + add_item, + add_count.min(item_stack_size) + ), + match add_count > item_stack_size { + true => Self::new_nonzero( + add_item, + NonZeroU8::new( + add_count.get() - item_stack_size.get() + ).unwrap(), + ), + false => Self::new_empty() + } + ), + Some((cur_item, cur_count)) if cur_item == add_item => { + let total_count = cur_count.checked_add(add_count.get()).unwrap(); + ( + ( + cur_item, + total_count.min(item_stack_size), + ), + match total_count > item_stack_size { + true => Self::new_nonzero( + add_item, + NonZeroU8::new( + total_count.get() - item_stack_size.get() + ).unwrap() + ), + false => Self::new_empty() + } + ) + }, + // If items are different, do not add anything, everything is leftovers + _ => return *from, + }; + + self.0 = Some(this_slot); + leftovers + } + + /// Move as much as possible items from another slot, removing them + /// + /// This may not be possible if the slot is full or contains a different item + pub fn move_all(&mut self, to: &mut Self) { + let leftovers = to.add(self); + *self = leftovers; + } + + /// Move up to `amount` items from another slot, removing them + /// + /// If `amount` is 0, nothing will be moved + pub fn move_up_to(&mut self, to: &mut Self, limit: u8) { + + if self.is_empty() { return } + // SAFETY: slot is guaranteed to be non-empty + let amount = unsafe { self.amount_nonzero().unwrap_unchecked() } ; + + if limit == 0 { return } + // SAFETY: `limit` guaranteed to be non-zero + let limit = unsafe { NonZeroU8::new_unchecked(limit) }; + + let amount_with_limit = amount.min(limit); + let self_with_limit = self.with_amount_nonzero(amount_with_limit); + + let mut leftovers = to.add(&self_with_limit); + + // Compensate for the amount of items that were not moved + let amount_difference = amount.get() - amount_with_limit.get(); + if amount_difference > 0 { + let correct_item = self.item().unwrap(); + let correct_amount = leftovers.amount() + amount_difference; + leftovers = Self::new(correct_item, correct_amount); + } + + *self = leftovers; + } + + /// Try to move a single item from another slot, removing it + /// + /// This may not be possible if the slot is full or contains a different item + pub fn move_single(&mut self, to: &mut Self) { + self.move_up_to(to, 1); } }