Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Development 0.7.0 #110

Draft
wants to merge 13 commits into
base: master
Choose a base branch
from
12 changes: 6 additions & 6 deletions src/modules/ship/models/ship_module/ship_kit_module.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ use crate::modules::ship::{ShipType, ShipTypeError};
#[derive(Debug, Serialize, Clone, PartialEq)]
pub struct ShipKitModule {
pub ship: ShipType,
pub kit_nr: u8,
pub name: String,
pub piece: String,
}

#[derive(Debug, Error)]
Expand All @@ -30,7 +30,7 @@ pub enum ShipKitModuleError {

lazy_static! {
static ref SHIP_KIT_MODULE_REGEX: Regex =
Regex::new(r#"^([a-z0-9_]+?)_shipkit(\d)(\w+)$"#).unwrap();
Regex::new(r#"^([a-z0-9_]+?)_shipkit([a-z0-9]+)_([a-z0-9]+)$"#).unwrap();
}

impl FromStr for ShipKitModule {
Expand All @@ -47,19 +47,19 @@ impl FromStr for ShipKitModule {
.as_str()
.parse()?;

let kit_nr = captures
let name = captures
.get(2)
.expect("Should have been captured already")
.as_str()
.parse()?;
.to_string();

let name = captures
let piece = captures
.get(3)
.expect("Should have been captured already")
.as_str()
.to_string();

Ok(ShipKitModule { ship, kit_nr, name })
Ok(ShipKitModule { ship, name, piece })
}
}

Expand Down
1 change: 1 addition & 0 deletions src/modules/state/models/resolvers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ pub mod game_state_resolver;
pub mod journal_state_resolver;
pub mod live_state_resolver;
pub mod log_state_resolver;
pub mod materials_state_resolver;
pub mod mission_state_resolver;
pub mod planet_state_resolver;
pub mod shipyard_state_resolver;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ impl JournalCommanderEntry {
&(planet_status.latitude, planet_status.longitude),
)
})
.min_by(|a, b| a.partial_cmp(b).unwrap_or(Ordering::Equal))
.min_by(|a, b| b.partial_cmp(a).unwrap_or(Ordering::Equal))
}

/// Returns true when the player is far enough from previous scans for the current organic.
Expand Down
87 changes: 49 additions & 38 deletions src/modules/state/models/resolvers/log_state_resolver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,19 @@ use serde::Serialize;

use crate::civilization::LocationInfo;
use crate::exploration::calculate_estimated_worth;
use crate::logs::loadout_event::LoadoutEvent;
use crate::logs::rank_event::RankEvent;
use crate::logs::reputation_event::ReputationEvent;
use crate::logs::scan_event::ScanEvent;
use crate::logs::scan_organic_event::ScanOrganicEventScanType;
use crate::logs::statistics_event::StatisticsEvent;
use crate::logs::touchdown_event::TouchdownEvent;
use crate::logs::{LogEvent, LogEventContent};
use crate::state::models::feed_result::FeedResult;
use crate::state::models::state::carrier_state::CarrierState;
use crate::state::models::state::materials_state::MaterialsState;
use crate::state::traits::state_resolver::StateResolver;
use crate::state::{MissionState, SystemState};
use crate::state::SystemState;
use crate::state::{MaterialsState, ShipyardState};
use current_organic_progress::CurrentOrganicProgress;

pub mod current_organic_progress;
Expand All @@ -28,15 +30,41 @@ pub mod current_organic_progress;
/// does.
#[derive(Serialize, Default)]
pub struct LogStateResolver {
/// Systems that the player has visited.
pub systems: HashMap<u64, SystemState>,

/// The system address the player is currently in.
pub current_system: Option<u64>,

/// Information about the current exobiology scans the player is performing.
pub current_organic_progress: Option<CurrentOrganicProgress>,

/// List of scans that have been performed since the last time the player has sold data or died.
pub current_exploration_data: Vec<ScanEvent>,

/// Keeps track of the current materials the player has.
pub material_state: MaterialsState,
pub mission_state: MissionState,

/// Information about the player's stored ships.
pub shipyard_state: ShipyardState,

/// Current touchdown event. Is set back to none when the player lifts off or dies.
pub touchdown: Option<TouchdownEvent>,

/// State regarding the player's carrier if they own one. `None` means that the player does
/// not own one or that their carrier has been scrapped.
pub carrier_state: Option<CarrierState>,

/// The lastest loadout event fired for the player.
pub current_loadout: Option<LoadoutEvent>,

/// The lastest rank event fired for the player.
pub rank: Option<RankEvent>,

/// The lastest reputation event fired for the player.
pub reputation: Option<ReputationEvent>,

/// The lastest statistics event fired for the player.
pub statistics: Option<StatisticsEvent>,
}

Expand All @@ -48,6 +76,7 @@ impl StateResolver<LogEvent> for LogStateResolver {
}
LogEventContent::Died(_) => {
self.current_exploration_data.clear();
self.touchdown = None;
}
LogEventContent::Rank(ranks) => {
self.rank = Some(ranks.clone());
Expand All @@ -73,13 +102,13 @@ impl StateResolver<LogEvent> for LogStateResolver {
LogEventContent::Location(location) => {
self.current_system = Some(location.location_info.system_address);

let system = self.upset_system(&location.location_info);
let system = self.upsert_system(&location.location_info);
system.visit(&input.timestamp);
}
LogEventContent::FSDJump(fsd_jump) => {
self.current_system = Some(fsd_jump.system_info.system_address);

let system = self.upset_system(&fsd_jump.system_info);
let system = self.upsert_system(&fsd_jump.system_info);
system.visit(&input.timestamp);
}
LogEventContent::ScanOrganic(scan_organic) => match &scan_organic.scan_type {
Expand All @@ -98,37 +127,6 @@ impl StateResolver<LogEvent> for LogStateResolver {
}
},

LogEventContent::Materials(event) => {
for material in &event.raw {
self.material_state
.set_material_count(material.name.clone(), material.count);
}

for material in &event.encoded {
self.material_state
.set_material_count(material.name.clone(), material.count);
}

for material in &event.manufactured {
self.material_state
.set_material_count(material.name.clone(), material.count);
}
}
LogEventContent::MaterialCollected(event) => {
self.material_state
.add_material_count(event.name.clone(), event.count);
}
LogEventContent::MaterialDiscarded(event) => {
self.material_state
.remove_material_count(event.name.clone(), event.count);
}
LogEventContent::MaterialTrade(event) => {
self.material_state
.remove_material_count(event.paid.material.clone(), event.paid.quantity);
self.material_state
.add_material_count(event.received.material.clone(), event.received.quantity);
}

LogEventContent::CarrierStats(stats) => {
if self.carrier_state.is_none() {
let mut state: CarrierState = stats.clone().into();
Expand All @@ -138,6 +136,16 @@ impl StateResolver<LogEvent> for LogStateResolver {
}
}

LogEventContent::Loadout(event) => {
self.current_loadout = Some(event.clone());
}
LogEventContent::Touchdown(event) => {
self.touchdown = Some(event.clone());
}
LogEventContent::Liftoff(_) => {
self.touchdown = None;
}

LogEventContent::CarrierJump(_)
| LogEventContent::CarrierBuy(_)
| LogEventContent::CarrierJumpRequest(_)
Expand All @@ -154,7 +162,7 @@ impl StateResolver<LogEvent> for LogStateResolver {
| LogEventContent::CarrierNameChange(_)
| LogEventContent::CarrierJumpCancelled(_) => {
if let LogEventContent::CarrierJump(carrier_jump) = &input.content {
let system = self.upset_system(&carrier_jump.system_info);
let system = self.upsert_system(&carrier_jump.system_info);
system.carrier_visit(&input.timestamp);
}

Expand Down Expand Up @@ -183,6 +191,9 @@ impl StateResolver<LogEvent> for LogStateResolver {
system.feed(input);
}

self.material_state.feed(input);
self.shipyard_state.feed(input);

FeedResult::Accepted
}

Expand All @@ -194,7 +205,7 @@ impl StateResolver<LogEvent> for LogStateResolver {
}

impl LogStateResolver {
pub fn upset_system(&mut self, location_info: &LocationInfo) -> &mut SystemState {
pub fn upsert_system(&mut self, location_info: &LocationInfo) -> &mut SystemState {
self.systems
.entry(location_info.system_address)
.or_insert_with(|| location_info.into());
Expand Down
156 changes: 156 additions & 0 deletions src/modules/state/models/resolvers/materials_state_resolver.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
use crate::logs::{LogEvent, LogEventContent};
use crate::materials::Material;
use crate::state::models::feed_result::FeedResult;
use crate::state::traits::state_resolver::StateResolver;
use serde::Serialize;
use std::collections::HashMap;

#[derive(Serialize, Default)]
pub struct MaterialsStateResolver {
pub materials: HashMap<Material, u16>,
}

impl MaterialsStateResolver {
pub fn set_material_count(&mut self, material: Material, count: u16) {
let count = count.min(material.grade().grade_storage_limit());

self.materials
.entry(material)
.and_modify(|current| *current = count)
.or_insert(count);
}

pub fn add_material_count(&mut self, material: Material, count: u16) {
self.materials
.entry(material.clone())
.and_modify(|current| {
*current = (*current + count).min(material.grade().grade_storage_limit())
})
.or_insert(count.min(material.grade().grade_storage_limit()));
}

pub fn remove_material_count(&mut self, materials: Material, count: u16) {
self.materials
.entry(materials.clone())
.and_modify(|current| *current = current.saturating_sub(count))
.or_insert(0);
}

pub fn get_count(&self, material: &Material) -> u16 {
let Some(count) = self.materials.get(material) else {
return 0;
};

*count
}

pub fn is_full(&self, material: &Material) -> bool {
let Some(count) = self.materials.get(material) else {
return false;
};

count >= &material.grade().grade_storage_limit()
}
}

impl StateResolver<LogEvent> for MaterialsStateResolver {
fn feed(&mut self, input: &LogEvent) -> FeedResult {
match &input.content {
LogEventContent::Materials(event) => {
for material in &event.raw {
self.set_material_count(material.name.clone(), material.count);
}

for material in &event.encoded {
self.set_material_count(material.name.clone(), material.count);
}

for material in &event.manufactured {
self.set_material_count(material.name.clone(), material.count);
}
}
LogEventContent::MaterialCollected(event) => {
self.add_material_count(event.name.clone(), event.count);
}
LogEventContent::MaterialDiscarded(event) => {
self.remove_material_count(event.name.clone(), event.count);
}
LogEventContent::MaterialTrade(event) => {
self.remove_material_count(event.paid.material.clone(), event.paid.quantity);
self.add_material_count(event.received.material.clone(), event.received.quantity);
}

LogEventContent::EngineerCraft(event) => {
for ingredient in &event.ingredients {
self.remove_material_count(ingredient.name.clone(), ingredient.count);
}
}

_ => return FeedResult::Skipped,
}

FeedResult::Accepted
}
}

#[cfg(test)]
mod tests {
use crate::materials::Material;
use crate::modules::state::models::resolvers::materials_state_resolver::MaterialsStateResolver;

#[test]
fn material_state_is_modified_correctly() {
let mut state = MaterialsStateResolver::default();

state.set_material_count(Material::Carbon, 10);
assert_eq!(state.get_count(&Material::Carbon), 10);

state.set_material_count(Material::Carbon, 10000);
assert_eq!(state.get_count(&Material::Carbon), 300);

state.remove_material_count(Material::Carbon, 20);
assert_eq!(state.get_count(&Material::Carbon), 280);

state.remove_material_count(Material::Carbon, 1000);
assert_eq!(state.get_count(&Material::Carbon), 0);

state.add_material_count(Material::Carbon, 20);
assert_eq!(state.get_count(&Material::Carbon), 20);

state.add_material_count(Material::Carbon, 10);
assert_eq!(state.get_count(&Material::Carbon), 30);

state.add_material_count(Material::Carbon, 1000);
assert_eq!(state.get_count(&Material::Carbon), 300);
}

#[test]
fn set_materials_without_entry_is_done_correctly() {
let mut state = MaterialsStateResolver::default();

state.set_material_count(Material::Carbon, 10);
assert_eq!(state.get_count(&Material::Carbon), 10);

state.set_material_count(Material::Iron, 10000);
assert_eq!(state.get_count(&Material::Iron), 300);
}

#[test]
fn add_materials_without_entry_is_done_correctly() {
let mut state = MaterialsStateResolver::default();

state.add_material_count(Material::Carbon, 10);
assert_eq!(state.get_count(&Material::Carbon), 10);

state.add_material_count(Material::Iron, 10000);
assert_eq!(state.get_count(&Material::Iron), 300);
}

#[test]
fn remove_materials_without_entry_is_done_correctly() {
let mut state = MaterialsStateResolver::default();

state.remove_material_count(Material::Carbon, 10);
assert_eq!(state.get_count(&Material::Carbon), 0);
}
}
Loading
Loading