Update
This commit is contained in:
		
							parent
							
								
									717a389a22
								
							
						
					
					
						commit
						35a0c40d14
					
				
					 8 changed files with 3359 additions and 0 deletions
				
			
		
							
								
								
									
										19
									
								
								rust/cargo_check.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								rust/cargo_check.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,19 @@ | |||
| import toml | ||||
| import subprocess as SP | ||||
| import os | ||||
| 
 | ||||
| 
 | ||||
| def set_version(rev=None): | ||||
|     with open("Cargo.toml") as fh: | ||||
|         cargo = toml.loads(fh.read()) | ||||
|     cargo["dependencies"]["pyo3"]["rev"] = rev | ||||
|     if rev is None: | ||||
|         del cargo["dependencies"]["pyo3"]["rev"] | ||||
|     with open("Cargo.toml", "w") as fh: | ||||
|         toml.dump(cargo, fh) | ||||
| 
 | ||||
| 
 | ||||
| for commit in open("ch.txt").readlines(): | ||||
|     set_version(commit.strip()) | ||||
|     if os.system("cargo check") == 0: | ||||
|         break | ||||
							
								
								
									
										2203
									
								
								rust/ch.txt
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										2203
									
								
								rust/ch.txt
									
										
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										19
									
								
								rust/rustup_check.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								rust/rustup_check.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,19 @@ | |||
| import subprocess as SP | ||||
| import os | ||||
| from datetime import timedelta | ||||
| from datetime import datetime | ||||
| 
 | ||||
| dt = timedelta(days=1) | ||||
| d = datetime.today().date() | ||||
| 
 | ||||
| while True: | ||||
|     toolchain="nightly-{}".format(d.isoformat()) | ||||
|     ret = os.system( | ||||
|         f"rustup default {toolchain}" | ||||
|     ) | ||||
|     if ret==0: | ||||
|         os.system("cargo +{} clean".format(toolchain)) | ||||
|         if os.system("cargo +{} check".format(toolchain))==0: | ||||
|             print(d) | ||||
|             break | ||||
|     d = d - dt | ||||
							
								
								
									
										289
									
								
								rust/src/data.json
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										289
									
								
								rust/src/data.json
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,289 @@ | |||
| { | ||||
|     "timestamp": "2019-09-25T21:29:51Z", | ||||
|     "event": "Loadout", | ||||
|     "Ship": "asp", | ||||
|     "ShipID": 0, | ||||
|     "ShipName": "Nightmaregreen_N", | ||||
|     "ShipIdent": "NMGR_N", | ||||
|     "HullValue": 6144793, | ||||
|     "ModulesValue": 33042643, | ||||
|     "HullHealth": 1.000000, | ||||
|     "UnladenMass": 347.200012, | ||||
|     "CargoCapacity": 0, | ||||
|     "MaxJumpRange": 56.372398, | ||||
|     "FuelCapacity": { | ||||
|         "Main": 64.000000, | ||||
|         "Reserve": 0.630000 | ||||
|     }, | ||||
|     "Rebuy": 1959374, | ||||
|     "Modules": [ | ||||
|         { | ||||
|             "Slot": "ShipCockpit", | ||||
|             "Item": "asp_cockpit", | ||||
|             "On": true, | ||||
|             "Priority": 1, | ||||
|             "Health": 1.000000 | ||||
|         }, | ||||
|         { | ||||
|             "Slot": "CargoHatch", | ||||
|             "Item": "modularcargobaydoor", | ||||
|             "On": true, | ||||
|             "Priority": 0, | ||||
|             "Health": 1.000000 | ||||
|         }, | ||||
|         { | ||||
|             "Slot": "TinyHardpoint1", | ||||
|             "Item": "hpt_heatsinklauncher_turret_tiny", | ||||
|             "On": true, | ||||
|             "Priority": 0, | ||||
|             "AmmoInClip": 1, | ||||
|             "AmmoInHopper": 2, | ||||
|             "Health": 1.000000 | ||||
|         }, | ||||
|         { | ||||
|             "Slot": "TinyHardpoint2", | ||||
|             "Item": "hpt_heatsinklauncher_turret_tiny", | ||||
|             "On": true, | ||||
|             "Priority": 0, | ||||
|             "AmmoInClip": 1, | ||||
|             "AmmoInHopper": 2, | ||||
|             "Health": 1.000000 | ||||
|         }, | ||||
|         { | ||||
|             "Slot": "TinyHardpoint3", | ||||
|             "Item": "hpt_heatsinklauncher_turret_tiny", | ||||
|             "On": true, | ||||
|             "Priority": 0, | ||||
|             "AmmoInClip": 1, | ||||
|             "AmmoInHopper": 2, | ||||
|             "Health": 1.000000 | ||||
|         }, | ||||
|         { | ||||
|             "Slot": "TinyHardpoint4", | ||||
|             "Item": "hpt_heatsinklauncher_turret_tiny", | ||||
|             "On": true, | ||||
|             "Priority": 0, | ||||
|             "AmmoInClip": 1, | ||||
|             "AmmoInHopper": 2, | ||||
|             "Health": 1.000000 | ||||
|         }, | ||||
|         { | ||||
|             "Slot": "PaintJob", | ||||
|             "Item": "paintjob_asp_operator_red", | ||||
|             "On": true, | ||||
|             "Priority": 1, | ||||
|             "Health": 1.000000 | ||||
|         }, | ||||
|         { | ||||
|             "Slot": "Armour", | ||||
|             "Item": "asp_armour_grade1", | ||||
|             "On": true, | ||||
|             "Priority": 1, | ||||
|             "Health": 1.000000 | ||||
|         }, | ||||
|         { | ||||
|             "Slot": "PowerPlant", | ||||
|             "Item": "int_powerplant_size5_class2", | ||||
|             "On": true, | ||||
|             "Priority": 1, | ||||
|             "Health": 1.000000 | ||||
|         }, | ||||
|         { | ||||
|             "Slot": "MainEngines", | ||||
|             "Item": "int_engine_size4_class2", | ||||
|             "On": true, | ||||
|             "Priority": 0, | ||||
|             "Health": 1.000000 | ||||
|         }, | ||||
|         { | ||||
|             "Slot": "FrameShiftDrive", | ||||
|             "Item": "int_hyperdrive_size5_class5", | ||||
|             "On": true, | ||||
|             "Priority": 0, | ||||
|             "Health": 1.000000, | ||||
|             "Engineering": { | ||||
|                 "Engineer": "Felicity Farseer", | ||||
|                 "EngineerID": 300100, | ||||
|                 "BlueprintID": 128673694, | ||||
|                 "BlueprintName": "FSD_LongRange", | ||||
|                 "Level": 5, | ||||
|                 "Quality": 1.000000, | ||||
|                 "ExperimentalEffect": "special_fsd_heavy", | ||||
|                 "ExperimentalEffect_Localised": "Mass Manager", | ||||
|                 "Modifiers": [ | ||||
|                     { | ||||
|                         "Label": "Mass", | ||||
|                         "Value": 26.000000, | ||||
|                         "OriginalValue": 20.000000, | ||||
|                         "LessIsGood": 1 | ||||
|                     }, | ||||
|                     { | ||||
|                         "Label": "Integrity", | ||||
|                         "Value": 93.840004, | ||||
|                         "OriginalValue": 120.000000, | ||||
|                         "LessIsGood": 0 | ||||
|                     }, | ||||
|                     { | ||||
|                         "Label": "PowerDraw", | ||||
|                         "Value": 0.690000, | ||||
|                         "OriginalValue": 0.600000, | ||||
|                         "LessIsGood": 1 | ||||
|                     }, | ||||
|                     { | ||||
|                         "Label": "FSDOptimalMass", | ||||
|                         "Value": 1692.599976, | ||||
|                         "OriginalValue": 1050.000000, | ||||
|                         "LessIsGood": 0 | ||||
|                     } | ||||
|                 ] | ||||
|             } | ||||
|         }, | ||||
|         { | ||||
|             "Slot": "LifeSupport", | ||||
|             "Item": "int_lifesupport_size4_class2", | ||||
|             "On": true, | ||||
|             "Priority": 0, | ||||
|             "Health": 1.000000 | ||||
|         }, | ||||
|         { | ||||
|             "Slot": "PowerDistributor", | ||||
|             "Item": "int_powerdistributor_size4_class2", | ||||
|             "On": true, | ||||
|             "Priority": 0, | ||||
|             "Health": 1.000000 | ||||
|         }, | ||||
|         { | ||||
|             "Slot": "Radar", | ||||
|             "Item": "int_sensors_size5_class2", | ||||
|             "On": true, | ||||
|             "Priority": 0, | ||||
|             "Health": 1.000000 | ||||
|         }, | ||||
|         { | ||||
|             "Slot": "FuelTank", | ||||
|             "Item": "int_fueltank_size5_class3", | ||||
|             "On": true, | ||||
|             "Priority": 1, | ||||
|             "Health": 1.000000 | ||||
|         }, | ||||
|         { | ||||
|             "Slot": "Decal1", | ||||
|             "Item": "decal_explorer_starblazer", | ||||
|             "On": true, | ||||
|             "Priority": 1, | ||||
|             "Health": 1.000000 | ||||
|         }, | ||||
|         { | ||||
|             "Slot": "Decal2", | ||||
|             "Item": "decal_explorer_starblazer", | ||||
|             "On": true, | ||||
|             "Priority": 1, | ||||
|             "Health": 1.000000 | ||||
|         }, | ||||
|         { | ||||
|             "Slot": "Decal3", | ||||
|             "Item": "decal_explorer_starblazer", | ||||
|             "On": true, | ||||
|             "Priority": 1, | ||||
|             "Health": 1.000000 | ||||
|         }, | ||||
|         { | ||||
|             "Slot": "ShipName0", | ||||
|             "Item": "nameplate_shipname_white", | ||||
|             "On": true, | ||||
|             "Priority": 1, | ||||
|             "Health": 1.000000 | ||||
|         }, | ||||
|         { | ||||
|             "Slot": "ShipName1", | ||||
|             "Item": "nameplate_shipname_white", | ||||
|             "On": true, | ||||
|             "Priority": 1, | ||||
|             "Health": 1.000000 | ||||
|         }, | ||||
|         { | ||||
|             "Slot": "ShipID0", | ||||
|             "Item": "nameplate_shipid_white", | ||||
|             "On": true, | ||||
|             "Priority": 1, | ||||
|             "Health": 1.000000 | ||||
|         }, | ||||
|         { | ||||
|             "Slot": "ShipID1", | ||||
|             "Item": "nameplate_shipid_white", | ||||
|             "On": true, | ||||
|             "Priority": 1, | ||||
|             "Health": 1.000000 | ||||
|         }, | ||||
|         { | ||||
|             "Slot": "Slot01_Size6", | ||||
|             "Item": "int_fuelscoop_size6_class5", | ||||
|             "On": true, | ||||
|             "Priority": 0, | ||||
|             "Health": 1.000000 | ||||
|         }, | ||||
|         { | ||||
|             "Slot": "Slot02_Size5", | ||||
|             "Item": "int_fueltank_size5_class3", | ||||
|             "On": true, | ||||
|             "Priority": 1, | ||||
|             "Health": 1.000000 | ||||
|         }, | ||||
|         { | ||||
|             "Slot": "Slot03_Size3", | ||||
|             "Item": "int_repairer_size3_class5", | ||||
|             "On": false, | ||||
|             "Priority": 0, | ||||
|             "Health": 1.000000 | ||||
|         }, | ||||
|         { | ||||
|             "Slot": "Slot04_Size3", | ||||
|             "Item": "int_shieldgenerator_size3_class2", | ||||
|             "On": true, | ||||
|             "Priority": 0, | ||||
|             "Health": 1.000000 | ||||
|         }, | ||||
|         { | ||||
|             "Slot": "Slot05_Size3", | ||||
|             "Item": "int_buggybay_size2_class2", | ||||
|             "On": true, | ||||
|             "Priority": 0, | ||||
|             "Health": 1.000000 | ||||
|         }, | ||||
|         { | ||||
|             "Slot": "Slot06_Size2", | ||||
|             "Item": "int_detailedsurfacescanner_tiny", | ||||
|             "On": true, | ||||
|             "Priority": 0, | ||||
|             "Health": 1.000000 | ||||
|         }, | ||||
|         { | ||||
|             "Slot": "Slot07_Size2", | ||||
|             "Item": "int_dockingcomputer_standard", | ||||
|             "On": true, | ||||
|             "Priority": 0, | ||||
|             "Health": 1.000000 | ||||
|         }, | ||||
|         { | ||||
|             "Slot": "Slot08_Size1", | ||||
|             "Item": "int_supercruiseassist", | ||||
|             "On": true, | ||||
|             "Priority": 0, | ||||
|             "Health": 1.000000 | ||||
|         }, | ||||
|         { | ||||
|             "Slot": "PlanetaryApproachSuite", | ||||
|             "Item": "int_planetapproachsuite", | ||||
|             "On": true, | ||||
|             "Priority": 1, | ||||
|             "Health": 1.000000 | ||||
|         }, | ||||
|         { | ||||
|             "Slot": "VesselVoice", | ||||
|             "Item": "voicepack_eden", | ||||
|             "On": true, | ||||
|             "Priority": 1, | ||||
|             "Health": 1.000000 | ||||
|         } | ||||
|     ] | ||||
| } | ||||
							
								
								
									
										193
									
								
								rust/src/data_guardian.json
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										193
									
								
								rust/src/data_guardian.json
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,193 @@ | |||
| { | ||||
|     "timestamp": "2019-09-25T21:29:51Z", | ||||
|     "event": "Loadout", | ||||
|     "Ship": "asp", | ||||
|     "ShipName": "Nightmaregreen_G", | ||||
|     "ShipIdent": "NMGR_G", | ||||
|     "HullValue": 6144793, | ||||
|     "ModulesValue": 33181682, | ||||
|     "UnladenMass": 348.500061, | ||||
|     "CargoCapacity": 0, | ||||
|     "MaxJumpRange": 60.164637, | ||||
|     "FuelCapacity": { | ||||
|         "Main": 64, | ||||
|         "Reserve": 0.63 | ||||
|     }, | ||||
|     "Rebuy": 1966323, | ||||
|     "Modules": [ | ||||
|         { | ||||
|             "Slot": "CargoHatch", | ||||
|             "Item": "modularcargobaydoor", | ||||
|             "On": true, | ||||
|             "Priority": 0 | ||||
|         }, | ||||
|         { | ||||
|             "Slot": "TinyHardpoint1", | ||||
|             "Item": "hpt_heatsinklauncher_turret_tiny", | ||||
|             "On": true, | ||||
|             "Priority": 0, | ||||
|             "Value": 3071 | ||||
|         }, | ||||
|         { | ||||
|             "Slot": "TinyHardpoint2", | ||||
|             "Item": "hpt_heatsinklauncher_turret_tiny", | ||||
|             "On": true, | ||||
|             "Priority": 0, | ||||
|             "Value": 3071 | ||||
|         }, | ||||
|         { | ||||
|             "Slot": "TinyHardpoint3", | ||||
|             "Item": "hpt_heatsinklauncher_turret_tiny", | ||||
|             "On": true, | ||||
|             "Priority": 0, | ||||
|             "Value": 3071 | ||||
|         }, | ||||
|         { | ||||
|             "Slot": "TinyHardpoint4", | ||||
|             "Item": "hpt_heatsinklauncher_turret_tiny", | ||||
|             "On": true, | ||||
|             "Priority": 0, | ||||
|             "Value": 3071 | ||||
|         }, | ||||
|         { | ||||
|             "Slot": "Armour", | ||||
|             "Item": "asp_armour_grade1", | ||||
|             "On": true, | ||||
|             "Priority": 1, | ||||
|             "Value": 0 | ||||
|         }, | ||||
|         { | ||||
|             "Slot": "PowerPlant", | ||||
|             "Item": "int_powerplant_size5_class2", | ||||
|             "On": true, | ||||
|             "Priority": 1, | ||||
|             "Value": 140523 | ||||
|         }, | ||||
|         { | ||||
|             "Slot": "MainEngines", | ||||
|             "Item": "int_engine_size4_class2", | ||||
|             "On": true, | ||||
|             "Priority": 0, | ||||
|             "Value": 52325 | ||||
|         }, | ||||
|         { | ||||
|             "Slot": "FrameShiftDrive", | ||||
|             "Item": "int_hyperdrive_size5_class5", | ||||
|             "On": true, | ||||
|             "Priority": 0, | ||||
|             "Value": 4478716, | ||||
|             "Engineering": { | ||||
|                 "BlueprintName": "FSD_LongRange", | ||||
|                 "Level": 5, | ||||
|                 "Quality": 1, | ||||
|                 "ExperimentalEffect": "special_fsd_heavy", | ||||
|                 "Modifiers": [ | ||||
|                     { | ||||
|                         "Label": "Mass", | ||||
|                         "Value": 26.000061, | ||||
|                         "OriginalValue": 20 | ||||
|                     }, | ||||
|                     { | ||||
|                         "Label": "Integrity", | ||||
|                         "Value": 93.839832, | ||||
|                         "OriginalValue": 120 | ||||
|                     }, | ||||
|                     { | ||||
|                         "Label": "PowerDraw", | ||||
|                         "Value": 0.690001, | ||||
|                         "OriginalValue": 0.6 | ||||
|                     }, | ||||
|                     { | ||||
|                         "Label": "FSDOptimalMass", | ||||
|                         "Value": 1692.58667, | ||||
|                         "OriginalValue": 1050 | ||||
|                     } | ||||
|                 ] | ||||
|             } | ||||
|         }, | ||||
|         { | ||||
|             "Slot": "LifeSupport", | ||||
|             "Item": "int_lifesupport_size4_class2", | ||||
|             "On": true, | ||||
|             "Priority": 0, | ||||
|             "Value": 24895 | ||||
|         }, | ||||
|         { | ||||
|             "Slot": "PowerDistributor", | ||||
|             "Item": "int_powerdistributor_size4_class2", | ||||
|             "On": true, | ||||
|             "Priority": 0, | ||||
|             "Value": 24895 | ||||
|         }, | ||||
|         { | ||||
|             "Slot": "Radar", | ||||
|             "Item": "int_sensors_size5_class2", | ||||
|             "On": true, | ||||
|             "Priority": 0, | ||||
|             "Value": 69709 | ||||
|         }, | ||||
|         { | ||||
|             "Slot": "FuelTank", | ||||
|             "Item": "int_fueltank_size5_class3", | ||||
|             "On": true, | ||||
|             "Priority": 1, | ||||
|             "Value": 85776 | ||||
|         }, | ||||
|         { | ||||
|             "Slot": "Slot01_Size6", | ||||
|             "Item": "int_fuelscoop_size6_class5", | ||||
|             "On": true, | ||||
|             "Priority": 0, | ||||
|             "Value": 25240068 | ||||
|         }, | ||||
|         { | ||||
|             "Slot": "Slot02_Size5", | ||||
|             "Item": "int_fueltank_size5_class3", | ||||
|             "On": true, | ||||
|             "Priority": 1, | ||||
|             "Value": 85776 | ||||
|         }, | ||||
|         { | ||||
|             "Slot": "Slot03_Size3", | ||||
|             "Item": "int_repairer_size3_class5", | ||||
|             "On": false, | ||||
|             "Priority": 0, | ||||
|             "Value": 2302911 | ||||
|         }, | ||||
|         { | ||||
|             "Slot": "Slot04_Size3", | ||||
|             "Item": "int_shieldgenerator_size3_class2", | ||||
|             "On": true, | ||||
|             "Priority": 0, | ||||
|             "Value": 16506 | ||||
|         }, | ||||
|         { | ||||
|             "Slot": "Slot05_Size3", | ||||
|             "Item": "int_buggybay_size2_class2", | ||||
|             "On": true, | ||||
|             "Priority": 0, | ||||
|             "Value": 18954 | ||||
|         }, | ||||
|         { | ||||
|             "Slot": "Slot06_Size2", | ||||
|             "Item": "int_detailedsurfacescanner_tiny", | ||||
|             "On": true, | ||||
|             "Priority": 0, | ||||
|             "Value": 219375 | ||||
|         }, | ||||
|         { | ||||
|             "Slot": "Slot07_Size2", | ||||
|             "Item": "int_dockingcomputer_standard", | ||||
|             "On": true, | ||||
|             "Priority": 0, | ||||
|             "Value": 3949 | ||||
|         }, | ||||
|         { | ||||
|             "Slot": "Slot08_Size1", | ||||
|             "Item": "int_guardianfsdbooster_size1", | ||||
|             "On": true, | ||||
|             "Priority": 0, | ||||
|             "Value": 405020 | ||||
|         } | ||||
|     ] | ||||
| } | ||||
							
								
								
									
										196
									
								
								rust/src/edsm.rs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										196
									
								
								rust/src/edsm.rs
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,196 @@ | |||
| use crate::common::get_mult; | ||||
| use crate::common::SystemSerde; | ||||
| use fnv::FnvHashMap; | ||||
| use pyo3::prelude::*; | ||||
| use serde::Deserialize; | ||||
| use serde_json::Result; | ||||
| use std::fs::File; | ||||
| use std::io::Seek; | ||||
| use std::io::{BufRead, BufReader, BufWriter, SeekFrom}; | ||||
| use std::path::PathBuf; | ||||
| use std::str; | ||||
| use std::time::Instant; | ||||
| 
 | ||||
| #[derive(Debug, Deserialize)] | ||||
| #[allow(non_snake_case)] | ||||
| struct Body { | ||||
|     name: String, | ||||
|     subType: String, | ||||
|     #[serde(rename = "type")] | ||||
|     body_type: String, | ||||
|     systemId: i32, | ||||
|     systemId64: i64, | ||||
|     #[serde(rename = "distanceToArrival")] | ||||
|     distance: f32, | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, Deserialize)] | ||||
| struct Coords { | ||||
|     x: f32, | ||||
|     y: f32, | ||||
|     z: f32, | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, Deserialize)] | ||||
| struct System { | ||||
|     id: i32, | ||||
|     id64: i64, | ||||
|     name: String, | ||||
|     coords: Coords, | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug)] | ||||
| pub struct PreprocessState { | ||||
|     pub file: String, | ||||
|     pub message: String, | ||||
|     pub total: u64, | ||||
|     pub done: u64, | ||||
|     pub count: usize, | ||||
| } | ||||
| 
 | ||||
| fn process( | ||||
|     path: &PathBuf, | ||||
|     func: &mut dyn for<'r> FnMut(&'r str) -> (), | ||||
|     callback: &dyn Fn(&PreprocessState) -> PyResult<PyObject>, | ||||
| ) -> std::io::Result<()> { | ||||
|     let mut buffer = String::new(); | ||||
|     let fh = File::open(path)?; | ||||
|     let total_size = fh.metadata()?.len(); | ||||
|     let mut t_last = Instant::now(); | ||||
|     let mut reader = BufReader::new(fh); | ||||
|     let mut state = PreprocessState { | ||||
|         file: path.to_str().unwrap().to_owned(), | ||||
|         total: total_size, | ||||
|         done: 0, | ||||
|         count: 0, | ||||
|         message: format!("Processing {} ...", path.to_str().unwrap()), | ||||
|     }; | ||||
|     println!("Loading {} ...", path.to_str().unwrap()); | ||||
|     while let Ok(n) = reader.read_line(&mut buffer) { | ||||
|         if n == 0 { | ||||
|             break; | ||||
|         } | ||||
|         buffer = buffer.trim_end().trim_end_matches(|c| c == ',').to_string(); | ||||
|         if !buffer.is_empty() { | ||||
|             func(&buffer); | ||||
|         } | ||||
|         let pos = reader.seek(SeekFrom::Current(0)).unwrap(); | ||||
|         state.done = pos; | ||||
|         state.count += 1; | ||||
|         if t_last.elapsed().as_millis() > 100 { | ||||
|             callback(&state)?; | ||||
|             t_last = Instant::now(); | ||||
|         } | ||||
|         buffer.clear(); | ||||
|     } | ||||
|     Ok(()) | ||||
| } | ||||
| 
 | ||||
| fn process_systems( | ||||
|     path: &PathBuf, | ||||
|     callback: &dyn Fn(&PreprocessState) -> PyResult<PyObject>, | ||||
| ) -> FnvHashMap<i32, System> { | ||||
|     let mut ret = FnvHashMap::default(); | ||||
|     process( | ||||
|         path, | ||||
|         &mut |line| { | ||||
|             let sys_res: Result<System> = serde_json::from_str(&line); | ||||
|             if let Ok(sys) = sys_res { | ||||
|                 ret.insert(sys.id, sys); | ||||
|             } else { | ||||
|                 eprintln!("\nError parsing: {}\n\t{:?}\n", line, sys_res.unwrap_err()); | ||||
|             } | ||||
|         }, | ||||
|         callback, | ||||
|     ) | ||||
|     .unwrap(); | ||||
|     ret | ||||
| } | ||||
| 
 | ||||
| pub fn build_index(path: &PathBuf) -> std::io::Result<()> { | ||||
|     let mut wtr = BufWriter::new(File::create(path.with_extension("idx"))?); | ||||
|     let mut idx: Vec<u64> = Vec::new(); | ||||
|     let mut records = (csv::Reader::from_path(path)?).into_deserialize::<SystemSerde>(); | ||||
|     loop { | ||||
|         idx.push(records.reader().position().byte()); | ||||
|         if records.next().is_none() { | ||||
|             break; | ||||
|         } | ||||
|     } | ||||
|     bincode::serialize_into(&mut wtr, &idx).unwrap(); | ||||
|     Ok(()) | ||||
| } | ||||
| 
 | ||||
| fn process_bodies( | ||||
|     path: &PathBuf, | ||||
|     out_path: &PathBuf, | ||||
|     systems: &mut FnvHashMap<i32, System>, | ||||
|     callback: &dyn Fn(&PreprocessState) -> PyResult<PyObject>, | ||||
| ) -> std::io::Result<()> { | ||||
|     println!( | ||||
|         "Processing {} into {} ...", | ||||
|         path.to_str().unwrap(), | ||||
|         out_path.to_str().unwrap(), | ||||
|     ); | ||||
|     let mut n: u32 = 0; | ||||
|     let mut wtr = csv::Writer::from_path(out_path)?; | ||||
|     process( | ||||
|         path, | ||||
|         &mut |line| { | ||||
|             if !line.contains("Star") { | ||||
|                 return; | ||||
|             } | ||||
|             let body_res: Result<Body> = serde_json::from_str(&line); | ||||
|             if let Ok(body) = body_res { | ||||
|                 if !body.body_type.contains("Star") { | ||||
|                     return; | ||||
|                 } | ||||
|                 if let Some(sys) = systems.get(&body.systemId) { | ||||
|                     let sub_type = body.subType; | ||||
|                     let mult = get_mult(&sub_type); | ||||
|                     let sys_name = sys.name.clone(); | ||||
|                     let rec = SystemSerde { | ||||
|                         id: n, | ||||
|                         star_type: sub_type, | ||||
|                         system: sys_name, | ||||
|                         body: body.name, | ||||
|                         mult, | ||||
|                         distance: body.distance, | ||||
|                         x: sys.coords.x, | ||||
|                         y: sys.coords.y, | ||||
|                         z: sys.coords.z, | ||||
|                     }; | ||||
|                     wtr.serialize(rec).unwrap(); | ||||
|                     n += 1; | ||||
|                 }; | ||||
|             } else { | ||||
|                 eprintln!("\nError parsing: {}\n\t{:?}\n", line, body_res.unwrap_err()); | ||||
|             } | ||||
|         }, | ||||
|         callback, | ||||
|     ) | ||||
|     .unwrap(); | ||||
|     println!("Total Systems: {}", n); | ||||
|     systems.clear(); | ||||
|     Ok(()) | ||||
| } | ||||
| 
 | ||||
| pub fn preprocess_files( | ||||
|     bodies: &PathBuf, | ||||
|     systems: &PathBuf, | ||||
|     out_path: &PathBuf, | ||||
|     callback: &dyn Fn(&PreprocessState) -> PyResult<PyObject>, | ||||
| ) -> std::io::Result<()> { | ||||
|     if !out_path.exists() { | ||||
|         let mut systems = process_systems(systems, &callback); | ||||
|         process_bodies(bodies, out_path, &mut systems, &callback)?; | ||||
|     } else { | ||||
|         println!( | ||||
|             "File '{}' exists, not overwriting it", | ||||
|             out_path.to_str().unwrap() | ||||
|         ); | ||||
|     } | ||||
|     println!("Building index..."); | ||||
|     println!("Index result: {:?}", build_index(&out_path)); | ||||
|     Ok(()) | ||||
| } | ||||
							
								
								
									
										169
									
								
								rust/src/journal.rs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										169
									
								
								rust/src/journal.rs
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,169 @@ | |||
| use crate::common::get_fsd_info; | ||||
| use crate::ship::Ship; | ||||
| 
 | ||||
| use regex::Regex; | ||||
| use serde::Deserialize; | ||||
| use std::collections::HashMap; | ||||
| 
 | ||||
| #[derive(Clone, Debug, PartialEq, Deserialize)] | ||||
| pub struct Event { | ||||
|     #[serde(flatten)] | ||||
|     pub event: EventData, | ||||
| } | ||||
| 
 | ||||
| #[serde(tag = "event")] | ||||
| #[derive(Clone, Debug, PartialEq, Deserialize)] | ||||
| pub enum EventData { | ||||
|     Loadout(Loadout), | ||||
|     #[serde(other)] | ||||
|     Unknown, | ||||
| } | ||||
| 
 | ||||
| #[serde(rename_all = "PascalCase")] | ||||
| #[derive(Clone, Debug, PartialEq, Deserialize)] | ||||
| pub struct Modifier { | ||||
|     label: String, | ||||
|     value: f32, | ||||
| } | ||||
| 
 | ||||
| #[serde(rename_all = "PascalCase")] | ||||
| #[derive(Clone, Debug, PartialEq, Deserialize)] | ||||
| pub struct Engineering { | ||||
|     modifiers: Vec<Modifier>, | ||||
| } | ||||
| 
 | ||||
| #[derive(Clone, Debug, PartialEq, Deserialize)] | ||||
| #[serde(rename_all = "PascalCase")] | ||||
| pub struct Module { | ||||
|     engineering: Option<Engineering>, | ||||
|     item: String, | ||||
|     slot: String, | ||||
| } | ||||
| 
 | ||||
| #[derive(Clone, Debug, PartialEq, Deserialize)] | ||||
| #[serde(rename_all = "PascalCase")] | ||||
| pub struct FuelCapacity { | ||||
|     main: f32, | ||||
|     reserve: f32, | ||||
| } | ||||
| 
 | ||||
| #[derive(Clone, Debug, PartialEq, Deserialize)] | ||||
| #[serde(rename_all = "PascalCase")] | ||||
| pub struct Loadout { | ||||
|     #[serde(rename = "timestamp")] | ||||
|     timestamp: String, | ||||
|     ship: String, | ||||
|     ship_name: String, | ||||
|     ship_ident: String, | ||||
|     fuel_capacity: FuelCapacity, | ||||
|     unladen_mass: f32, | ||||
|     modules: Vec<Module>, | ||||
| } | ||||
| 
 | ||||
| impl Engineering { | ||||
|     fn to_hashmap(&self) -> HashMap<String, f32> { | ||||
|         let mut h = HashMap::new(); | ||||
|         for v in &self.modifiers { | ||||
|             h.insert(v.label.clone(), v.value); | ||||
|         } | ||||
|         return h; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl Loadout { | ||||
|     fn get_booster(&self) -> Option<usize> { | ||||
|         self.modules | ||||
|             .iter() | ||||
|             .cloned() | ||||
|             .filter_map(|m| { | ||||
|                 let Module { item, .. } = m; | ||||
|                 if item.starts_with("int_guardianfsdbooster") { | ||||
|                     return item | ||||
|                         .chars() | ||||
|                         .last() | ||||
|                         .unwrap() | ||||
|                         .to_digit(10) | ||||
|                         .map(|v| v as usize); | ||||
|                 } | ||||
|                 return None; | ||||
|             }) | ||||
|             .next() | ||||
|     } | ||||
| 
 | ||||
|     fn get_fsd(&self) -> Option<(String, Option<Engineering>)> { | ||||
|         self.modules | ||||
|             .iter() | ||||
|             .cloned() | ||||
|             .filter_map(|m| { | ||||
|                 let Module { | ||||
|                     slot, | ||||
|                     engineering, | ||||
|                     item, | ||||
|                 } = m; | ||||
|                 if slot == "FrameShiftDrive" { | ||||
|                     return Some((item, engineering)); | ||||
|                 } | ||||
|                 return None; | ||||
|             }) | ||||
|             .next() | ||||
|     } | ||||
| 
 | ||||
|     pub fn try_into_ship(self) -> Result<Ship, String> { | ||||
|         let fsd = self.get_fsd().ok_or("No FSD found!")?; | ||||
|         let booster = self.get_booster().unwrap_or(0); | ||||
|         let fsd_type = Regex::new(r"^int_hyperdrive_size(\d+)_class(\d+)$") | ||||
|             .unwrap() | ||||
|             .captures(&fsd.0); | ||||
|         let fsd_type: (usize, usize) = fsd_type | ||||
|             .map(|m| { | ||||
|                 let s = m.get(1)?.as_str().to_owned().parse().ok()?; | ||||
|                 let c = m.get(2)?.as_str().to_owned().parse().ok()?; | ||||
|                 return Some((c, s)); | ||||
|             }) | ||||
|             .flatten() | ||||
|             .ok_or(format!("Invalid FSD found: {}", &fsd.0))?; | ||||
|         let eng = fsd | ||||
|             .1 | ||||
|             .map(|eng| eng.to_hashmap()) | ||||
|             .unwrap_or_else(HashMap::new); | ||||
|         let mut fsd_info = get_fsd_info(fsd_type.0, fsd_type.1)?; | ||||
|         let fsd_type = ( | ||||
|             "_EDCBA" | ||||
|                 .chars() | ||||
|                 .nth(fsd_type.0) | ||||
|                 .ok_or(format!("Invalid FSD found: {}", &fsd.0))?, | ||||
|             fsd_type.1 as u8, | ||||
|         ); | ||||
|         fsd_info.extend(eng); | ||||
|         let max_fuel = fsd_info | ||||
|             .get("MaxFuel") | ||||
|             .ok_or(format!("Unknwon MaxFuelPerJump for FSD: {}", &fsd.0))?; | ||||
|         let opt_mass = fsd_info | ||||
|             .get("FSDOptimalMass") | ||||
|             .ok_or(format!("Unknwon FSDOptimalMass for FSD: {}", &fsd.0))?; | ||||
|         return Ship::new( | ||||
|             self.ship_name, | ||||
|             self.ship_ident, | ||||
|             self.ship, | ||||
|             self.unladen_mass, | ||||
|             self.fuel_capacity.main, | ||||
|             self.fuel_capacity.main, | ||||
|             fsd_type, | ||||
|             *max_fuel, | ||||
|             *opt_mass, | ||||
|             booster, | ||||
|         ); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl Event { | ||||
|     pub fn get_loadout(self) -> Option<Loadout> { | ||||
|         if let Event { | ||||
|             event: EventData::Loadout(loadout), | ||||
|         } = self | ||||
|         { | ||||
|             return Some(loadout); | ||||
|         } | ||||
|         None | ||||
|     } | ||||
| } | ||||
							
								
								
									
										271
									
								
								rust/src/ship.rs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										271
									
								
								rust/src/ship.rs
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,271 @@ | |||
| use crate::common::get_fsd_booster_info; | ||||
| use crate::journal::*; | ||||
| use pyo3::conversion::ToPyObject; | ||||
| use pyo3::prelude::*; | ||||
| use pyo3::types::PyDict; | ||||
| use regex::Regex; | ||||
| use serde::{Deserialize, Serialize}; | ||||
| use std::collections::HashMap; | ||||
| use std::fs::File; | ||||
| use std::io::{BufRead, BufReader}; | ||||
| use std::path::PathBuf; | ||||
| 
 | ||||
| #[derive(Debug, Clone, Serialize, Deserialize)] | ||||
| pub struct FSD { | ||||
|     pub rating_val: f32, | ||||
|     pub class_val: f32, | ||||
|     pub opt_mass: f32, | ||||
|     pub max_fuel: f32, | ||||
|     pub boost: f32, | ||||
|     pub guardian_booster: f32, | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, Clone, Serialize, Deserialize)] | ||||
| pub struct Ship { | ||||
|     pub name: String, | ||||
|     pub ident: String, | ||||
|     pub ship_type: String, | ||||
|     pub base_mass: f32, | ||||
|     pub fuel_mass: f32, | ||||
|     pub fuel_capacity: f32, | ||||
|     pub fsd: FSD, | ||||
| } | ||||
| 
 | ||||
| impl Ship { | ||||
|     pub fn new( | ||||
|         name: String, | ||||
|         ident: String, | ||||
|         ship_type: String, | ||||
|         base_mass: f32, | ||||
|         fuel_mass: f32, | ||||
|         fuel_capacity: f32, | ||||
|         fsd_type: (char, u8), | ||||
|         max_fuel: f32, | ||||
|         opt_mass: f32, | ||||
|         guardian_booster: usize, | ||||
|     ) -> Result<Self, String> { | ||||
|         let rating_val: f32 = match fsd_type.0 { | ||||
|             'A' => 12.0, | ||||
|             'B' => 10.0, | ||||
|             'C' => 8.0, | ||||
|             'D' => 10.0, | ||||
|             'E' => 11.0, | ||||
|             err => { | ||||
|                 return Err(format!("Invalid rating: {}", err)); | ||||
|             } | ||||
|         }; | ||||
|         if fsd_type.1 < 2 || fsd_type.1 > 8 { | ||||
|             return Err(format!("Invalid class: {}", fsd_type.1)); | ||||
|         }; | ||||
|         
 | ||||
|         if guardian_booster!=0 { | ||||
|             return Err("Guardian booster not yet implemented!".to_owned()) | ||||
|         } | ||||
| 
 | ||||
|         let ret = Self { | ||||
|             name, | ||||
|             ident, | ||||
|             ship_type, | ||||
|             fuel_capacity, | ||||
|             fuel_mass, | ||||
|             base_mass, | ||||
|             fsd: FSD { | ||||
|                 rating_val, | ||||
|                 class_val: 2.0 + (0.15 * ((fsd_type.1 - 2) as f32)), | ||||
|                 opt_mass, | ||||
|                 max_fuel, | ||||
|                 boost: 1.0, | ||||
|                 guardian_booster: get_fsd_booster_info(guardian_booster)?, | ||||
|             }, | ||||
|         }; | ||||
|         Ok(ret) | ||||
|     } | ||||
| 
 | ||||
|     pub fn new_from_json(data: &str) -> Result<Self, String> { | ||||
|         match serde_json::from_str::<Event>(&data) { | ||||
|             Ok(Event { | ||||
|                 event: EventData::Unknown, | ||||
|             }) => { | ||||
|                 return Err(format!("Invalid Loadout event: {}", data)); | ||||
|             } | ||||
|             Ok(ev) => { | ||||
|                 if let Some(loadout) = ev.get_loadout() { | ||||
|                     return loadout.try_into_ship(); | ||||
|                 } else { | ||||
|                     return Err(format!("Invalid Loadout event: {}", data)); | ||||
|                 } | ||||
|             } | ||||
|             Err(msg) => { | ||||
|                 return Err(format!("{}", msg)); | ||||
|             } | ||||
|         }; | ||||
|     } | ||||
| 
 | ||||
|     pub fn new_from_journal() -> Result<HashMap<String, Self>, String> { | ||||
|         let mut ret = HashMap::new(); | ||||
|         let re = Regex::new(r"^Journal\.\d{12}\.\d{2}\.log$").unwrap(); | ||||
|         let mut journals: Vec<PathBuf> = Vec::new(); | ||||
|         let mut userprofile = PathBuf::from(std::env::var("Userprofile").unwrap()); | ||||
|         userprofile.push("Saved Games"); | ||||
|         userprofile.push("Frontier Developments"); | ||||
|         userprofile.push("Elite Dangerous"); | ||||
|         if let Ok(iter) = userprofile.read_dir() { | ||||
|             for entry in iter { | ||||
|                 if let Ok(entry) = entry { | ||||
|                     if re.is_match(&entry.file_name().to_string_lossy()) { | ||||
|                         journals.push(entry.path()); | ||||
|                     }; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         journals.sort(); | ||||
| 
 | ||||
|         for journal in &journals { | ||||
|             let mut fh = BufReader::new(File::open(journal).unwrap()); | ||||
|             let mut line = String::new(); | ||||
|             while let Ok(n) = fh.read_line(&mut line) { | ||||
|                 if n == 0 { | ||||
|                     break; | ||||
|                 } | ||||
|                 match serde_json::from_str::<Event>(&line) { | ||||
|                     Ok(Event { | ||||
|                         event: EventData::Unknown, | ||||
|                     }) => {} | ||||
|                     Ok(ev) => { | ||||
|                         if let Some(loadout) = ev.get_loadout() { | ||||
|                             let mut ship = loadout.try_into_ship()?; | ||||
|                             if ship.name == "" { | ||||
|                                 ship.name = "<NO NAME>".to_owned(); | ||||
|                             } | ||||
|                             let key = format!( | ||||
|                                 "[{}] {} ({})", | ||||
|                                 ship.ident, | ||||
|                                 ship.name, | ||||
|                                 ship.ship_type.to_ascii_lowercase() | ||||
|                             ); | ||||
|                             ret.insert(key, ship); | ||||
|                         } | ||||
|                     } | ||||
|                     Err(_) => {} | ||||
|                 }; | ||||
|                 line.clear(); | ||||
|             } | ||||
|         } | ||||
|         if ret.is_empty() { | ||||
|             return Err("No ships loaded!".to_owned()); | ||||
|         } | ||||
|         return Ok(ret); | ||||
|     } | ||||
| 
 | ||||
|     pub fn can_jump(&self, d: f32) -> bool { | ||||
|         self.fuel_cost(d) <= self.fsd.max_fuel.min(self.fuel_mass) | ||||
|     } | ||||
| 
 | ||||
|     pub fn boost(&mut self, boost: f32) { | ||||
|         self.fsd.boost = boost; | ||||
|     } | ||||
| 
 | ||||
|     pub fn refuel(&mut self) { | ||||
|         self.fuel_mass = self.fuel_capacity; | ||||
|     } | ||||
| 
 | ||||
|     pub fn make_jump(&mut self, d: f32) -> Option<f32> { | ||||
|         let cost = self.fuel_cost(d); | ||||
|         if cost > self.fsd.max_fuel.min(self.fuel_mass) { | ||||
|             return None; | ||||
|         } | ||||
|         self.fuel_mass -= cost; | ||||
|         self.fsd.boost = 1.0; | ||||
|         Some(cost) | ||||
|     } | ||||
| 
 | ||||
|     fn jump_range(&self, fuel: f32, booster: bool) -> f32 { | ||||
|         let mass = self.base_mass + fuel; | ||||
|         let mut fuel = self.fsd.max_fuel.min(fuel); | ||||
|         if booster { | ||||
|             fuel *= self.boost_fuel_mult(); | ||||
|         } | ||||
|         let opt_mass = self.fsd.opt_mass * self.fsd.boost; | ||||
|         return opt_mass * ((1000.0 * fuel) / self.fsd.rating_val).powf(self.fsd.class_val.recip()) | ||||
|             / mass; | ||||
|     } | ||||
| 
 | ||||
|     pub fn max_range(&self) -> f32 { | ||||
|         return self.jump_range(self.fsd.max_fuel, true); | ||||
|     } | ||||
| 
 | ||||
|     pub fn range(&self) -> f32 { | ||||
|         return self.jump_range(self.fuel_mass, true); | ||||
|     } | ||||
| 
 | ||||
|     fn boost_fuel_mult(&self) -> f32 { | ||||
|         if self.fsd.guardian_booster == 0.0 { | ||||
|             return 1.0; | ||||
|         } | ||||
| 
 | ||||
|         let base_range = self.jump_range(self.fuel_mass, false); // current range without booster
 | ||||
| 
 | ||||
|         return ((base_range + self.fsd.guardian_booster) / base_range).powf(self.fsd.class_val); | ||||
|     } | ||||
| 
 | ||||
|     pub fn fuel_cost(&self, d: f32) -> f32 { | ||||
|         if d == 0.0 { | ||||
|             return 0.0; | ||||
|         } | ||||
|         let mass = self.base_mass + self.fuel_mass; | ||||
|         let opt_mass = self.fsd.opt_mass * self.fsd.boost; | ||||
|         let base_cost = (d * mass) / opt_mass; | ||||
|         return (self.fsd.rating_val * 0.001 * base_cost.powf(self.fsd.class_val)) | ||||
|             / self.boost_fuel_mult(); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| /* | ||||
| #[derive(Debug,Clone, Serialize, Deserialize, ToPyObject)] | ||||
| pub struct FSD { | ||||
|     pub rating_val: f32, | ||||
|     pub class_val: f32, | ||||
|     pub opt_mass: f32, | ||||
|     pub max_fuel: f32, | ||||
|     pub boost: f32, | ||||
|     pub guardian_booster: f32, | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug,Clone, Serialize, Deserialize, ToPyObject)] | ||||
| pub struct Ship { | ||||
|     pub name: String, | ||||
|     pub ident: String, | ||||
|     pub ship_type: String, | ||||
|     pub base_mass: f32, | ||||
|     pub fuel_mass: f32, | ||||
|     pub fuel_capacity: f32, | ||||
|     pub fsd: FSD, | ||||
| } | ||||
| */ | ||||
| 
 | ||||
| impl FSD { | ||||
|     pub fn to_object(&self, py: Python) -> PyResult<PyObject> { | ||||
|         let elem = PyDict::new(py); | ||||
|         elem.set_item("rating_val", self.rating_val)?; | ||||
|         elem.set_item("class_val", self.class_val)?; | ||||
|         elem.set_item("opt_mass", self.opt_mass)?; | ||||
|         elem.set_item("max_fuel", self.max_fuel)?; | ||||
|         elem.set_item("boost", self.boost)?; | ||||
|         elem.set_item("guardian_booster", self.guardian_booster)?; | ||||
|         Ok(elem.to_object(py)) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl Ship { | ||||
|     pub fn to_object(&self, py: Python) -> PyResult<PyObject> { | ||||
|         let elem = PyDict::new(py); | ||||
|         elem.set_item("name", self.name.clone())?; | ||||
|         elem.set_item("ident", self.ident.clone())?; | ||||
|         elem.set_item("ship_type", self.ship_type.clone())?; | ||||
|         elem.set_item("base_mass", self.base_mass)?; | ||||
|         elem.set_item("fuel_mass", self.fuel_mass)?; | ||||
|         elem.set_item("fuel_capacity", self.fuel_capacity)?; | ||||
|         elem.set_item("fsd", self.fsd.to_object(py)?)?; | ||||
|         Ok(elem.to_object(py)) | ||||
|     } | ||||
| } | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue