1
0
mirror of https://git.ngram.ca/OpenJam/rc-servers synced 2026-08-23 23:08:52 +00:00

Implement loading of cube data from JSON file

This commit is contained in:
NGnius (Graham)
2025-03-09 16:28:03 -04:00
parent 303f72f010
commit 9b87b25131
20 changed files with 9541 additions and 64 deletions

2
Cargo.lock generated
View File

@@ -1781,6 +1781,8 @@ dependencies = [
"polariton",
"polariton_auth",
"polariton_server",
"serde",
"serde_json",
"tokio",
]

View File

@@ -21,3 +21,5 @@ env_logger = "0.11"
clap = { version = "4.5", features = [ "derive" ] }
polariton = { version = "0.2", path = "../polariton", features = [ "tokio-async" ] }
polariton_server = { version = "0.2", path = "../polariton/server", features = [ "tokio-async" ] }
serde = { version = "1.0", features = [ "derive" ] }
serde_json = "1.0"

View File

@@ -0,0 +1,9 @@
# Asset Retrieval
[UABE](https://github.com/SeriousCache/UABE) is pretty great for this.
## Cubes
Cube data is contained in `cubetypelist_steam` as a sub-asset (UABE dumps the actual asset as `unnamed asset-CAB_e94be3f69d8179602fb05811b2ba5579-4300557138948789011`).
I've written a Python script to process that asset (exported as JSON) into the JSON format I've designed.

8271
assets/robocraft/cubes.json Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -13,3 +13,5 @@ polariton_auth = { version = "*", path = "../polariton_auth" }
polariton_server.workspace = true
base64 = "0.22"
hex = "0.4"
serde.workspace = true
serde_json.workspace = true

View File

@@ -14,6 +14,10 @@ pub struct CliArgs {
/// Socket read tries before giving up (0 to never give up)
#[arg(long, default_value_t = 5)]
pub retries: usize,
/// Assets root
#[arg(long, default_value_t = {"../assets/robocraft".to_string()})]
pub assets: String,
}
impl CliArgs {

View File

@@ -2,7 +2,7 @@
use std::collections::HashMap;
use polariton::operation::Typed;
pub struct CubeInfo {
pub struct CubeInfo<C: Clone> {
pub cpu: u32,
pub health: u32,
pub health_boost: f32,
@@ -14,7 +14,7 @@ pub struct CubeInfo {
pub protonium: bool,
pub unlocked_by_league: bool,
pub league_unlock_index: i32,
pub stats: HashMap<String, Typed>,
pub stats: HashMap<String, Typed<C>>,
pub description: String,
pub size: ItemTier,
pub type_: ItemType,
@@ -24,8 +24,8 @@ pub struct CubeInfo {
pub ignore_in_weapon_list: bool,
}
impl CubeInfo {
pub fn as_transmissible(&self) -> Typed {
impl <C: Clone> CubeInfo<C> {
pub fn as_transmissible(&self) -> Typed<C> {
Typed::HashMap(vec![
(Typed::Str("cpuRating".into()), Typed::Int(self.cpu as i32)),
(Typed::Str("health".into()), Typed::Int(self.health as i32)),
@@ -39,7 +39,7 @@ impl CubeInfo {
(Typed::Str("UnlockedByLeague".into()), Typed::Bool(self.unlocked_by_league.into())),
(Typed::Str("LeagueUnlockIndex".into()), Typed::Int(self.league_unlock_index)),
(Typed::Str("DisplayStats".into()), {
let items: Vec<(Typed, Typed)> = self.stats.iter().map(|(key, val)| (Typed::Str(key.into()), val.to_owned())).collect();
let items: Vec<(Typed<C>, Typed<C>)> = self.stats.iter().map(|(key, val)| (Typed::<C>::Str(key.into()), val.to_owned())).collect();
Typed::HashMap(items.into())
}),
(Typed::Str("Description".into()), Typed::Str(self.description.clone().into())),
@@ -52,7 +52,7 @@ impl CubeInfo {
].into())
}
pub fn as_transmissible_key_val(&self, cube_id: u32) -> (Typed, Typed) {
pub fn as_transmissible_key_val(&self, cube_id: u32) -> (Typed<C>, Typed<C>) {
(Typed::Str(hex::encode(cube_id.to_be_bytes()).into()), self.as_transmissible())
}
}

View File

@@ -19,7 +19,7 @@ pub struct MovementCategoryData {
}
impl MovementCategoryData {
pub fn as_transmissible(&self) -> Typed {
pub fn as_transmissible<C>(&self) -> Typed<C> {
let mut out = Vec::new();
self.horizontal_top_speed.map(|x| out.push((Typed::Str("horizontalTopSpeed".into()), Typed::Float(x))));
self.vertical_top_speed.map(|x| out.push((Typed::Str("verticalTopSpeed".into()), Typed::Float(x))));
@@ -57,7 +57,7 @@ pub enum MovementCategorySpecificData {
}
impl MovementCategorySpecificData {
pub fn as_transmissible(&self) -> Vec<(Typed, Typed)> {
pub fn as_transmissible<C>(&self) -> Vec<(Typed<C>, Typed<C>)> {
match self {
Self::Wheel => Vec::default(),
Self::Hover(x) => x.as_transmissible(),
@@ -86,7 +86,7 @@ pub struct HoverCategoryData {
}
impl HoverCategoryData {
pub fn as_transmissible(&self) -> Vec<(Typed, Typed)> {
pub fn as_transmissible<C>(&self) -> Vec<(Typed<C>, Typed<C>)> {
vec![
(Typed::Str("heightTolerance".into()), Typed::Float(self.height_tolerance)),
(Typed::Str("forceYOffset".into()), Typed::Float(self.force_y_offset)),
@@ -105,7 +105,7 @@ pub struct MechLegCategoryData {
}
impl MechLegCategoryData {
pub fn as_transmissible(&self) -> Vec<(Typed, Typed)> {
pub fn as_transmissible<C>(&self) -> Vec<(Typed<C>, Typed<C>)> {
vec![
(Typed::Str("decelerationMultiplier".into()), Typed::Float(self.deceleration_multiplier)),
]
@@ -118,7 +118,7 @@ pub struct RotorCategoryData {
impl RotorCategoryData {
pub fn as_transmissible(&self) -> Vec<(Typed, Typed)> {
pub fn as_transmissible<C>(&self) -> Vec<(Typed<C>, Typed<C>)> {
vec![
(Typed::Str("maxTurnRate".into()), Typed::Float(self.max_turn_rate)),
]
@@ -134,7 +134,7 @@ pub struct MovementData {
}
impl MovementData {
pub fn as_transmissible(&self) -> Typed {
pub fn as_transmissible<C>(&self) -> Typed<C> {
let mut out = Vec::new();
self.speed_boost.map(|x| out.push((Typed::Str("speedBoost".into()), Typed::Float(x))));
self.max_carry_mass.map(|x| out.push((Typed::Str("maxCarryMass".into()), Typed::Float(x))));
@@ -164,7 +164,7 @@ pub enum MovementSpecificData {
}
impl MovementSpecificData {
pub fn as_transmissible(&self) -> Vec<(Typed, Typed)> {
pub fn as_transmissible<C>(&self) -> Vec<(Typed<C>, Typed<C>)> {
match self {
Self::Wheel(x) => x.as_transmissible(),
Self::Hover(x) => x.as_transmissible(),
@@ -195,7 +195,7 @@ pub struct WheelData {
}
impl WheelData {
pub fn as_transmissible(&self) -> Vec<(Typed, Typed)> {
pub fn as_transmissible<C>(&self) -> Vec<(Typed<C>, Typed<C>)> {
vec![
(Typed::Str("steeringSpeedLight".into()), Typed::Float(self.steering_speed_light)),
(Typed::Str("steeringSpeedHeavy".into()), Typed::Float(self.steering_speed_heavy)),
@@ -227,7 +227,7 @@ pub struct HoverData {
}
impl HoverData {
pub fn as_transmissible(&self) -> Vec<(Typed, Typed)> {
pub fn as_transmissible<C>(&self) -> Vec<(Typed<C>, Typed<C>)> {
vec![
(Typed::Str("maxHoverHeightLight".into()), Typed::Float(self.max_hover_height_light)),
(Typed::Str("maxHoverHeightHeavy".into()), Typed::Float(self.max_hover_height_heaver)),
@@ -261,7 +261,7 @@ pub struct AerofoilData {
}
impl AerofoilData {
pub fn as_transmissible(&self) -> Vec<(Typed, Typed)> {
pub fn as_transmissible<C>(&self) -> Vec<(Typed<C>, Typed<C>)> {
vec![
(Typed::Str("barrelSpeedLight".into()), Typed::Float(self.barrel_speed_light)),
(Typed::Str("barrelSpeedHeavy".into()), Typed::Float(self.barrel_speed_heavy)),
@@ -285,7 +285,7 @@ pub struct ThrusterData {
}
impl ThrusterData {
pub fn as_transmissible(&self) -> Vec<(Typed, Typed)> {
pub fn as_transmissible<C>(&self) -> Vec<(Typed<C>, Typed<C>)> {
vec![
(Typed::Str("accelerationDelayLight".into()), Typed::Float(self.acceleration_delay_light)),
(Typed::Str("accelerationDelayHeavy".into()), Typed::Float(self.acceleration_delay_heavy)),
@@ -323,7 +323,7 @@ pub struct InsectLegData {
}
impl InsectLegData {
pub fn as_transmissible(&self) -> Vec<(Typed, Typed)> {
pub fn as_transmissible<C>(&self) -> Vec<(Typed<C>, Typed<C>)> {
vec![
(Typed::Str("idealHeightLight".into()), Typed::Float(self.ideal_height_light)),
(Typed::Str("idealHeightHeavy".into()), Typed::Float(self.ideal_height_heavy)),
@@ -373,7 +373,7 @@ pub struct MechLegData {
}
impl MechLegData {
pub fn as_transmissible(&self) -> Vec<(Typed, Typed)> {
pub fn as_transmissible<C>(&self) -> Vec<(Typed<C>, Typed<C>)> {
vec![
(Typed::Str("timeGroundedAfterJumpLight".into()), Typed::Float(self.time_grounded_after_jump_light)),
(Typed::Str("timeGroundedAfterJumpHeavy".into()), Typed::Float(self.time_grounded_after_jump_heavy)),
@@ -405,7 +405,7 @@ pub struct TankTrackData {
}
impl TankTrackData {
pub fn as_transmissible(&self) -> Vec<(Typed, Typed)> {
pub fn as_transmissible<C>(&self) -> Vec<(Typed<C>, Typed<C>)> {
vec![
(Typed::Str("maxTurnRateMovingLight".into()), Typed::Float(self.max_turn_rate_moving_light)),
(Typed::Str("maxTurnRateMovingHeavy".into()), Typed::Float(self.max_turn_rate_moving_heavy)),
@@ -434,7 +434,7 @@ pub struct RotorData {
impl RotorData {
pub fn as_transmissible(&self) -> Vec<(Typed, Typed)> {
pub fn as_transmissible<C>(&self) -> Vec<(Typed<C>, Typed<C>)> {
vec![
(Typed::Str("heightAccelerationLight".into()), Typed::Float(self.height_acceleration_light)),
(Typed::Str("heightAccelerationHeavy".into()), Typed::Float(self.height_acceleration_heavy)),

View File

@@ -68,7 +68,7 @@ pub struct WeaponData {
}
impl WeaponData {
pub fn as_transmissible(&self) -> Typed {
pub fn as_transmissible<C>(&self) -> Typed<C> {
let mut out = Vec::new();
self.damage_inflicted.map(|x| out.push((Typed::Str("damageInflicted".into()), Typed::Int(x))));
@@ -114,7 +114,7 @@ impl WeaponData {
self.spin_initial_cooldown.map(|x| out.push((Typed::Str("spinInitialCooldown".into()), Typed::Float(x))));
if !self.group_fire_scales.is_empty() {
let typed_arr: Vec<Typed> = self.group_fire_scales.iter().map(|x| Typed::Float(*x)).collect();
let typed_arr: Vec<Typed<C>> = self.group_fire_scales.iter().map(|x| Typed::Float(*x)).collect();
out.push((Typed::Str("groupFireScales".into()), Typed::ObjArr(typed_arr.into())));
}
@@ -156,7 +156,7 @@ pub enum ItemCategory {
Ski = 8,
TankTrack = 9,
Rotor = 10,
SrpinterLeg = 11,
SprinterLeg = 11,
Propeller = 12,
Laser = 100,
Plasma = 200,
@@ -190,7 +190,7 @@ impl ItemCategory {
ItemCategory::Ski => "Ski",
ItemCategory::TankTrack => "TankTrack",
ItemCategory::Rotor => "Rotor",
ItemCategory::SrpinterLeg => "SrpinterLeg",
ItemCategory::SprinterLeg => "SprinterLeg",
ItemCategory::Propeller => "Propeller",
ItemCategory::Laser => "Laser",
ItemCategory::Plasma => "Plasma",

View File

@@ -4,6 +4,7 @@ mod state;
mod data;
mod events;
mod operations;
mod persist;
use polariton_auth::Handshake;
use tokio::net;
@@ -13,13 +14,21 @@ use polariton::operation::{OperationResponse, Typed};
pub type UserTy = std::sync::RwLock<state::UserState>;
pub struct InitConfig {
pub cubes: persist::config::CubeConfig,
}
#[tokio::main]
async fn main() -> std::io::Result<()> {
env_logger::init();
let args = cli::CliArgs::get();
log::debug!("Got cli args {:?}", args);
let server = polariton_server::Server::new(operations::handler());
let init_ctx = InitConfig {
cubes: persist::config::CubeConfig::load(&args.assets).expect("Bad cube config data"),
};
let server = polariton_server::Server::new(operations::handler(&init_ctx));
let ip_addr: std::net::IpAddr = args.ip.parse().expect("Invalid IP address");

View File

@@ -1,17 +1,18 @@
use std::collections::HashMap;
//use std::collections::HashMap;
use polariton_server::operations::SimpleFunc;
use polariton::{operation::{Dict, ParameterTable, Typed}, serdes::TypePrefix};
use polariton_server::operations::Immediate;
//use polariton::{operation::{Dict, ParameterTable, Typed}, serdes::TypePrefix};
use crate::data::cube_list::*;
//use crate::data::cube_list::*;
const PARAM_KEY: u8 = 1;
const DEFAULT_CUBE_ID: u32 = 227205318;
//const DEFAULT_CUBE_ID: u32 = 227205318;
pub(super) fn cube_list_provider() -> SimpleFunc<2, crate::UserTy, impl (Fn(ParameterTable, &crate::UserTy) -> Result<ParameterTable, i16>) + Sync + Sync> {
SimpleFunc::new(|params, _| {
let mut params = params.to_dict();
params.insert(PARAM_KEY, Typed::Dict(Dict {
pub(super) fn cube_list_provider(cubes: &crate::persist::config::CubeConfig) -> Immediate<2, crate::UserTy> {
Immediate::new(|| {
let mut params = std::collections::HashMap::with_capacity(2);
params.insert(PARAM_KEY, cubes.cube_list());
/*params.insert(PARAM_KEY, Typed::Dict(Dict {
key_ty: TypePrefix::Str, // str
val_ty: TypePrefix::HashMap, // hashtable
items: vec![
@@ -164,7 +165,7 @@ pub(super) fn cube_list_provider() -> SimpleFunc<2, crate::UserTy, impl (Fn(Para
ignore_in_weapon_list: true,
}.as_transmissible_key_val(3209000021),
].into(),
}));
Ok(params.into())
}));*/
params.into()
})
}

View File

@@ -75,7 +75,7 @@ mod reconnect_game;
use polariton_server::operations::OperationsHandler;
pub fn handler() -> OperationsHandler<crate::UserTy> {
pub fn handler(init_ctx: &crate::InitConfig) -> OperationsHandler<crate::UserTy> {
OperationsHandler::new()
.without_state(eac::EacChallengeIgnorer)
.without_state(more_auth::MoreLobbyAuth)
@@ -88,14 +88,14 @@ pub fn handler() -> OperationsHandler<crate::UserTy> {
.without_state(polariton_server::operations::Ack::<131, _>::default()) // analytics updated notification
.without_state(platform_config::platform_config_provider())
.without_state(tier_banding::tiers_banding_provider())
.without_state(cube_list::cube_list_provider())
.without_state(cube_list::cube_list_provider(&init_ctx.cubes))
.without_state(special_items::special_item_list_provider())
.without_state(premium_config::premium_config_provider())
.without_state(palette_town::kanto())
.without_state(client_config::client_config_provider())
.without_state(crf_config::crf_config_provider())
.without_state(weapon_stats::weapon_config_provider())
.without_state(movement_stats::movement_config_provider())
.without_state(weapon_stats::weapon_config_provider(&init_ctx.cubes))
.without_state(movement_stats::movement_config_provider(&init_ctx.cubes))
.without_state(power_bar_stats::power_bar_provider())
.without_state(damage_boost_stats::damage_boost_provider())
.without_state(battle_arena_config::battle_arena_config_provider())

View File

@@ -1,17 +1,18 @@
use polariton::serdes::TypePrefix;
use polariton_server::operations::SimpleFunc;
use polariton::operation::{ParameterTable, Typed, Dict};
//use polariton::serdes::TypePrefix;
use polariton_server::operations::Immediate;
//use polariton::operation::{ParameterTable, Typed, Dict};
use crate::data::movement_list::*;
use crate::data::cube_list::ItemTier;
use crate::data::weapon_list::ItemCategory;
//use crate::data::movement_list::*;
//use crate::data::cube_list::ItemTier;
//use crate::data::weapon_list::ItemCategory;
const PARAM_KEY: u8 = 1;
pub(super) fn movement_config_provider() -> SimpleFunc<62, crate::UserTy, impl (Fn(ParameterTable, &crate::UserTy) -> Result<ParameterTable, i16>) + Sync + Sync> {
SimpleFunc::new(|params, _| {
let mut params = params.to_dict();
params.insert(PARAM_KEY, Typed::Dict(Dict {
pub(super) fn movement_config_provider(cubes: &crate::persist::config::CubeConfig) -> Immediate<62, crate::UserTy> {
Immediate::new(|| {
let mut params = std::collections::HashMap::with_capacity(2);
params.insert(PARAM_KEY, cubes.movement_list());
/*params.insert(PARAM_KEY, Typed::Dict(Dict {
key_ty: TypePrefix::Str, // str
val_ty: TypePrefix::HashMap, // hashtable
items: vec![
@@ -137,7 +138,7 @@ pub(super) fn movement_config_provider() -> SimpleFunc<62, crate::UserTy, impl (
}.as_transmissible()),
].into())),
].into(),
}));
Ok(params.into())
}));*/
params.into()
})
}

View File

@@ -1,16 +1,17 @@
use polariton::serdes::TypePrefix;
use polariton_server::operations::SimpleFunc;
use polariton::operation::{ParameterTable, Typed, Dict};
//use polariton::serdes::TypePrefix;
use polariton_server::operations::Immediate;
//use polariton::operation::{Typed, Dict};
use crate::data::weapon_list::*;
use crate::data::cube_list::ItemTier;
//use crate::data::weapon_list::*;
//use crate::data::cube_list::ItemTier;
const PARAM_KEY: u8 = 57;
pub(super) fn weapon_config_provider() -> SimpleFunc<47, crate::UserTy, impl (Fn(ParameterTable, &crate::UserTy) -> Result<ParameterTable, i16>) + Sync + Sync> {
SimpleFunc::new(|params, _| {
let mut params = params.to_dict();
params.insert(PARAM_KEY, Typed::Dict(Dict {
pub(super) fn weapon_config_provider(cubes: &crate::persist::config::CubeConfig) -> Immediate<47, crate::UserTy> {
Immediate::new(|| {
let mut params = std::collections::HashMap::with_capacity(2);
params.insert(PARAM_KEY, cubes.weapon_list());
/*params.insert(PARAM_KEY, Typed::Dict(Dict {
key_ty: TypePrefix::Str, // str
val_ty: TypePrefix::HashMap, // hashtable
items: vec![
@@ -42,7 +43,7 @@ pub(super) fn weapon_config_provider() -> SimpleFunc<47, crate::UserTy, impl (Fn
}.as_transmissible()),
].into()))
].into(),
}));
Ok(params.into())
}));*/
params.into()
})
}

View File

@@ -0,0 +1,347 @@
use std::collections::HashMap;
use serde::{Serialize, Deserialize};
use polariton::operation::{Typed, Dict};
use polariton::serdes::TypePrefix;
use super::{MovementCategoryData, MovementData, WeaponData};
const CUBE_CONFIG_FILENAME: &str = "cubes.json";
#[derive(Serialize, Deserialize, Debug)]
pub struct CubeConfig {
cubes: HashMap<String, Cube>,
movement: HashMap<ItemCategory, MovementCategoryData>,
lerp_value: f32,
}
impl CubeConfig {
pub fn load(root: impl AsRef<std::path::Path>) -> std::io::Result<Self> {
let file = std::fs::File::open(root.as_ref().join(CUBE_CONFIG_FILENAME))?;
let buffered = std::io::BufReader::new(file);
let result = serde_json::from_reader(buffered)?;
Ok(result)
}
pub fn cube_list<C: Clone>(&self) -> Typed<C> {
Typed::Dict(Dict {
key_ty: TypePrefix::Str,
val_ty: TypePrefix::HashMap,
items: self.cubes.values().map(|cube| {
let cube_d: crate::data::cube_list::CubeInfo<C> = cube.info.clone().into();
cube_d.as_transmissible_key_val(cube.id)
}).collect(),
})
}
pub fn movement_list<C: Clone>(&self) -> Typed<C> {
let mut movements_stats = HashMap::<ItemCategory, HashMap<ItemTier, MovementData>>::new();
for cube in self.cubes.values() {
if let Some(movement_data) = &cube.movement {
let category_map = if let Some(x) = movements_stats.get_mut(&cube.info.category) {
x
} else {
movements_stats.insert(cube.info.category, HashMap::new());
movements_stats.get_mut(&cube.info.category).unwrap()
};
category_map.insert(cube.info.size, movement_data.to_owned());
}
}
let mut movement_cat_stats = Vec::with_capacity(self.movement.len());
for (k, v) in self.movement.iter() {
let stats: Vec<_> = if let Some(stats) = movements_stats.get(&k) {
stats.iter().map(|(k, v)| (k.to_owned(), v.to_owned())).collect()
} else {
Vec::default()
};
let key: crate::data::weapon_list::ItemCategory = k.to_owned().into();
let key_typed = Typed::<C>::Str(key.as_str().into());
let value_data = v.to_owned().into_data(stats);
movement_cat_stats.push((key_typed, value_data.as_transmissible()));
}
Typed::Dict(Dict {
key_ty: TypePrefix::Str,
val_ty: TypePrefix::HashMap,
items: vec![
(Typed::Str("Global".into()), Typed::HashMap(vec![
(Typed::Str("lerpValue".into()), Typed::Float(self.lerp_value)),
].into())),
(Typed::Str("Movements".into()), Typed::HashMap(movement_cat_stats.into())),
],
})
}
pub fn weapon_list<C: Clone>(&self) -> Typed<C> {
let mut weapon_stats = HashMap::new();
for cube in self.cubes.values() {
if let Some(weapon_data) = &cube.weapon {
let category_map = if let Some(x) = weapon_stats.get_mut(&cube.info.category) {
x
} else {
weapon_stats.insert(cube.info.category, HashMap::new());
weapon_stats.get_mut(&cube.info.category).unwrap()
};
category_map.insert(cube.info.size, weapon_data.to_owned());
}
}
let mut weapons_vec: Vec<(Typed<C>, Typed<C>)> = Vec::with_capacity(weapon_stats.len());
for (k, v) in weapon_stats {
let cat_data: crate::data::weapon_list::ItemCategory = k.into();
let mut tiers_vec = Vec::with_capacity(v.len());
for (k, v) in v {
let tier_data: crate::data::cube_list::ItemTier = k.into();
let val_data: crate::data::weapon_list::WeaponData = v.into();
tiers_vec.push((Typed::Str(tier_data.as_str().into()), val_data.as_transmissible()));
}
weapons_vec.push((Typed::Str(cat_data.as_str().into()), Typed::HashMap(tiers_vec.into())));
}
Typed::Dict(Dict {
key_ty: TypePrefix::Str,
val_ty: TypePrefix::HashMap,
items: weapons_vec,
})
}
}
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct Cube {
pub id: u32,
pub info: CubeInfo,
pub weapon: Option<WeaponData>,
pub movement: Option<MovementData>,
}
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct CubeInfo {
#[serde(default = "default_1")]
pub cpu: u32,
#[serde(default = "default_1")]
pub health: u32,
#[serde(default = "default_1_0")]
pub health_boost: f32,
#[serde(default)]
pub grey_out_in_tutorial: bool,
#[serde(default)]
pub visibility: VisibilityMode,
#[serde(default)]
pub indestructible: bool,
#[serde(default)]
pub category: ItemCategory,
#[serde(default = "default_63")]
pub placements: u32,
#[serde(default)]
pub protonium: bool,
#[serde(default)]
pub unlocked_by_league: bool,
#[serde(default)]
pub league_unlock_index: i32,
pub stats: HashMap<String, serde_json::Value>,
pub description: String,
pub size: ItemTier,
#[serde(rename = "type", alias = "type_")]
pub type_: ItemType,
#[serde(default)]
pub ranking: i32,
#[serde(default)]
pub cosmetic: bool,
#[serde(default)]
pub variant_of: u32, // cube id (in hex)
#[serde(default = "default_true")]
pub ignore_in_weapon_list: bool,
}
fn default_1() -> u32 {
1
}
fn default_1_0() -> f32 {
1.0
}
fn default_63() -> u32 {
63
}
fn default_true() -> bool {
true
}
impl <C: Clone> std::convert::Into<crate::data::cube_list::CubeInfo<C>> for CubeInfo {
fn into(self) -> crate::data::cube_list::CubeInfo<C> {
crate::data::cube_list::CubeInfo {
cpu: self.cpu,
health: self.health,
health_boost: self.health_boost,
grey_out_in_tutorial: self.grey_out_in_tutorial,
visibility: self.visibility.into(),
indestructible: self.indestructible,
category: self.category.into(),
placements: self.placements, // default 63
protonium: self.protonium,
unlocked_by_league: self.unlocked_by_league,
league_unlock_index: self.league_unlock_index,
stats: self.stats.into_iter().map(|(k, v)| {
let new_v = match v {
serde_json::Value::Bool(b) => Typed::Bool(b),
serde_json::Value::Number(n) => if let Some(n_i64) = n.as_i64() {
Typed::Long(n_i64)
} else if let Some(n_f64) = n.as_f64() {
Typed::Double(n_f64)
} else {
panic!("Invalid json number")
},
serde_json::Value::String(s) => Typed::Str(s.into()),
_ => Typed::Null, // TODO is support for Object/Array/Null necessary?
};
(k, new_v)
}).collect(),
description: self.description,
size: self.size.into(),
type_: self.type_.into(),
ranking: self.ranking,
cosmetic: self.cosmetic,
variant_of: hex::encode(self.variant_of.to_be_bytes()).into(),
ignore_in_weapon_list: self.ignore_in_weapon_list,
}
}
}
#[derive(Serialize, Deserialize, Clone, Copy, Debug, Default)]
pub enum VisibilityMode {
Mothership,
#[default]
All,
Tutorial,
None,
}
impl std::convert::Into<crate::data::cube_list::VisibilityMode> for VisibilityMode {
fn into(self) -> crate::data::cube_list::VisibilityMode {
match self {
Self::Mothership => crate::data::cube_list::VisibilityMode::Mothership,
Self::All => crate::data::cube_list::VisibilityMode::All,
Self::Tutorial => crate::data::cube_list::VisibilityMode::Tutorial,
Self::None => crate::data::cube_list::VisibilityMode::None,
}
}
}
#[derive(Serialize, Deserialize, Clone, Copy, Debug, Default, Hash, PartialEq, Eq)]
pub enum ItemTier {
#[default]
NoTier = 0,
T0 = 100,
T1 = 200,
T2 = 300,
T3 = 400,
T4 = 500,
T5 = 600,
}
impl std::convert::Into<crate::data::cube_list::ItemTier> for ItemTier {
fn into(self) -> crate::data::cube_list::ItemTier {
match self {
Self::NoTier => crate::data::cube_list::ItemTier::NoTier,
Self::T0 => crate::data::cube_list::ItemTier::T0,
Self::T1 => crate::data::cube_list::ItemTier::T1,
Self::T2 => crate::data::cube_list::ItemTier::T2,
Self::T3 => crate::data::cube_list::ItemTier::T3,
Self::T4 => crate::data::cube_list::ItemTier::T4,
Self::T5 => crate::data::cube_list::ItemTier::T5,
}
}
}
#[derive(Serialize, Deserialize, Clone, Copy, Debug, Default)]
pub enum ItemType {
#[default]
NotAFunctionalItem,
Weapon,
Module,
Movement,
Cosmetic,
}
impl std::convert::Into<crate::data::cube_list::ItemType> for ItemType {
fn into(self) -> crate::data::cube_list::ItemType {
match self {
Self::NotAFunctionalItem => crate::data::cube_list::ItemType::NoFunction,
Self::Weapon => crate::data::cube_list::ItemType::Weapon,
Self::Module => crate::data::cube_list::ItemType::Module,
Self::Movement => crate::data::cube_list::ItemType::Movement,
Self::Cosmetic => crate::data::cube_list::ItemType::Cosmetic,
}
}
}
#[derive(Serialize, Deserialize, Clone, Copy, Debug, Default, Hash, PartialEq, Eq)]
pub enum ItemCategory {
#[default]
NotAFunctionalItem = 0,
Wheel = 1,
Hover = 2,
Wing = 3,
Rudder = 4,
Thruster = 5,
InsectLeg = 6,
MechLeg = 7,
Ski = 8,
TankTrack = 9,
Rotor = 10,
SprinterLeg = 11,
Propeller = 12,
Laser = 100,
Plasma = 200,
Mortar = 250,
Rail = 300,
Nano = 400,
Tesla = 500,
Aeroflak = 600,
Ion = 650,
Seeker = 701,
Chaingun = 750,
ShieldModule = 800,
GhostModule = 801,
BlinkModule = 802,
EmpModule = 803,
WindowmakerModule = 804,
EnergyModule = 900,
}
impl std::convert::Into<crate::data::weapon_list::ItemCategory> for ItemCategory {
fn into(self) -> crate::data::weapon_list::ItemCategory {
match self {
Self::NotAFunctionalItem => crate::data::weapon_list::ItemCategory::NoFunction,
Self::Wheel => crate::data::weapon_list::ItemCategory::Wheel,
Self::Hover => crate::data::weapon_list::ItemCategory::Hover,
Self::Wing => crate::data::weapon_list::ItemCategory::Wing,
Self::Rudder => crate::data::weapon_list::ItemCategory::Rudder,
Self::Thruster => crate::data::weapon_list::ItemCategory::Thruster,
Self::InsectLeg => crate::data::weapon_list::ItemCategory::InsectLeg,
Self::MechLeg => crate::data::weapon_list::ItemCategory::MechLeg,
Self::Ski => crate::data::weapon_list::ItemCategory::Ski,
Self::TankTrack => crate::data::weapon_list::ItemCategory::TankTrack,
Self::Rotor => crate::data::weapon_list::ItemCategory::Rotor,
Self::SprinterLeg => crate::data::weapon_list::ItemCategory::SprinterLeg,
Self::Propeller => crate::data::weapon_list::ItemCategory::Propeller,
Self::Laser => crate::data::weapon_list::ItemCategory::Laser,
Self::Plasma => crate::data::weapon_list::ItemCategory::Plasma,
Self::Mortar => crate::data::weapon_list::ItemCategory::Mortar,
Self::Rail => crate::data::weapon_list::ItemCategory::Rail,
Self::Nano => crate::data::weapon_list::ItemCategory::Nano,
Self::Tesla => crate::data::weapon_list::ItemCategory::Tesla,
Self::Aeroflak => crate::data::weapon_list::ItemCategory::Aeroflak,
Self::Ion => crate::data::weapon_list::ItemCategory::Ion,
Self::Seeker => crate::data::weapon_list::ItemCategory::Seeker,
Self::Chaingun => crate::data::weapon_list::ItemCategory::Chaingun,
Self::ShieldModule => crate::data::weapon_list::ItemCategory::ShieldModule,
Self::GhostModule => crate::data::weapon_list::ItemCategory::GhostModule,
Self::BlinkModule => crate::data::weapon_list::ItemCategory::BlinkModule,
Self::EmpModule => crate::data::weapon_list::ItemCategory::EmpModule,
Self::WindowmakerModule => crate::data::weapon_list::ItemCategory::WindowmakerModule,
Self::EnergyModule => crate::data::weapon_list::ItemCategory::EnergyModule,
}
}
}

View File

@@ -0,0 +1,9 @@
mod cubes;
pub use cubes::{CubeConfig, ItemTier};
//pub use cubes::{Cube, ItemCategory, VisibilityMode, ItemType};
mod movement;
pub use movement::{MovementCategoryData, MovementData};
mod weapon;
pub use weapon::WeaponData;

View File

@@ -0,0 +1,448 @@
use serde::{Serialize, Deserialize};
use super::ItemTier;
#[derive(Serialize, Deserialize, Clone, Debug, Default)]
pub struct MovementCategoryData {
pub horizontal_top_speed: Option<f32>,
pub vertical_top_speed: Option<f32>,
pub min_required_items: Option<i32>,
pub min_item_modifier: Option<f32>,
pub max_hover_height: Option<f32>,
pub light_machine_mass: Option<f32>,
pub heavy_machine_mass: Option<f32>,
pub specifics: MovementCategorySpecificData,
}
impl MovementCategoryData {
pub fn into_data(self, stats: Vec<(ItemTier, MovementData)>) -> crate::data::movement_list::MovementCategoryData {
crate::data::movement_list::MovementCategoryData {
horizontal_top_speed: self.horizontal_top_speed,
vertical_top_speed: self.vertical_top_speed,
min_required_items: self.min_required_items,
min_item_modifier: self.min_item_modifier,
max_hover_height: self.max_hover_height,
light_machine_mass: self.light_machine_mass,
heavy_machine_mass: self.heavy_machine_mass,
specifics: self.specifics.into(),
stats: stats.into_iter().map(|(t, m)| (t.into(), m.into())).collect(),
}
}
}
#[derive(Serialize, Deserialize, Clone, Debug, Default)]
pub enum MovementCategorySpecificData {
#[default]
Wheel,
Hover(HoverCategoryData),
Wing,
Rudder, // same as wing
Thruster,
Propeller, // same as thruster
InsectLeg,
MechLeg(MechLegCategoryData),
SprinterLeg(MechLegCategoryData), // same as mech leg
TankTrack,
Rotor(RotorCategoryData),
}
impl std::convert::Into<crate::data::movement_list::MovementCategorySpecificData> for MovementCategorySpecificData {
fn into(self) -> crate::data::movement_list::MovementCategorySpecificData {
match self {
Self::Wheel => crate::data::movement_list::MovementCategorySpecificData::Wheel,
Self::Hover(x) => crate::data::movement_list::MovementCategorySpecificData::Hover(x.into()),
Self::Wing => crate::data::movement_list::MovementCategorySpecificData::Wing,
Self::Rudder => crate::data::movement_list::MovementCategorySpecificData::Rudder,
Self::Thruster => crate::data::movement_list::MovementCategorySpecificData::Thruster,
Self::Propeller => crate::data::movement_list::MovementCategorySpecificData::Propeller,
Self::InsectLeg => crate::data::movement_list::MovementCategorySpecificData::InsectLeg,
Self::MechLeg(x) => crate::data::movement_list::MovementCategorySpecificData::MechLeg(x.into()),
Self::SprinterLeg(x) => crate::data::movement_list::MovementCategorySpecificData::SprinterLeg(x.into()),
Self::TankTrack => crate::data::movement_list::MovementCategorySpecificData::TankTrack,
Self::Rotor(x) => crate::data::movement_list::MovementCategorySpecificData::Rotor(x.into()),
}
}
}
#[derive(Serialize, Deserialize, Clone, Debug, Default)]
pub struct HoverCategoryData {
pub height_tolerance: f32,
pub force_y_offset: f32,
pub turning_scale: f32,
pub small_angle_turning_scale: f32,
pub max_vertical_velocity: f32,
pub hover_damping: f32,
pub angular_damping: f32,
pub deceleration_multiplier: f32,
}
impl std::convert::Into<crate::data::movement_list::HoverCategoryData> for HoverCategoryData {
fn into(self) -> crate::data::movement_list::HoverCategoryData {
crate::data::movement_list::HoverCategoryData {
height_tolerance: self.height_tolerance,
force_y_offset: self.force_y_offset,
turning_scale: self.turning_scale,
small_angle_turning_scale: self.small_angle_turning_scale,
max_vertical_velocity: self.max_vertical_velocity,
hover_damping: self.hover_damping,
angular_damping: self.angular_damping,
deceleration_multiplier: self.deceleration_multiplier,
}
}
}
#[derive(Serialize, Deserialize, Clone, Debug, Default)]
pub struct MechLegCategoryData {
pub deceleration_multiplier: f32,
}
impl std::convert::Into<crate::data::movement_list::MechLegCategoryData> for MechLegCategoryData {
fn into(self) -> crate::data::movement_list::MechLegCategoryData {
crate::data::movement_list::MechLegCategoryData {
deceleration_multiplier: self.deceleration_multiplier,
}
}
}
#[derive(Serialize, Deserialize, Clone, Debug, Default)]
pub struct RotorCategoryData {
pub max_turn_rate: f32,
}
impl std::convert::Into<crate::data::movement_list::RotorCategoryData> for RotorCategoryData {
fn into(self) -> crate::data::movement_list::RotorCategoryData {
crate::data::movement_list::RotorCategoryData {
max_turn_rate: self.max_turn_rate,
}
}
}
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct MovementData {
pub speed_boost: Option<f32>,
pub max_carry_mass: Option<f32>,
pub horizontal_top_speed: Option<f32>,
pub vertical_top_speed: Option<f32>,
pub specifics: MovementSpecificData,
}
impl std::convert::Into<crate::data::movement_list::MovementData> for MovementData {
fn into(self) -> crate::data::movement_list::MovementData {
crate::data::movement_list::MovementData {
speed_boost: self.speed_boost,
max_carry_mass: self.max_carry_mass,
horizontal_top_speed: self.horizontal_top_speed,
vertical_top_speed: self.vertical_top_speed,
specifics: self.specifics.into(),
}
}
}
#[derive(Serialize, Deserialize, Clone, Debug)]
pub enum MovementSpecificData {
Wheel(WheelData),
Hover(HoverData),
Wing(AerofoilData),
Rudder(AerofoilData), // same as wing
Thruster(ThrusterData),
Propeller(ThrusterData), // same as thruster
InsectLeg(InsectLegData),
MechLeg(MechLegData),
SprinterLeg(MechLegData), // same as mech leg
TankTrack(TankTrackData),
Rotor(RotorData),
}
impl std::convert::Into<crate::data::movement_list::MovementSpecificData> for MovementSpecificData {
fn into(self) -> crate::data::movement_list::MovementSpecificData {
match self {
Self::Wheel(x) => crate::data::movement_list::MovementSpecificData::Wheel(x.into()),
Self::Hover(x) => crate::data::movement_list::MovementSpecificData::Hover(x.into()),
Self::Wing(x) => crate::data::movement_list::MovementSpecificData::Wing(x.into()),
Self::Rudder(x) => crate::data::movement_list::MovementSpecificData::Rudder(x.into()),
Self::Thruster(x) => crate::data::movement_list::MovementSpecificData::Thruster(x.into()),
Self::Propeller(x) => crate::data::movement_list::MovementSpecificData::Propeller(x.into()),
Self::InsectLeg(x) => crate::data::movement_list::MovementSpecificData::InsectLeg(x.into()),
Self::MechLeg(x) => crate::data::movement_list::MovementSpecificData::MechLeg(x.into()),
Self::SprinterLeg(x) => crate::data::movement_list::MovementSpecificData::SprinterLeg(x.into()),
Self::TankTrack(x) => crate::data::movement_list::MovementSpecificData::TankTrack(x.into()),
Self::Rotor(x) => crate::data::movement_list::MovementSpecificData::Rotor(x.into()),
}
}
}
#[derive(Serialize, Deserialize, Clone, Debug, Default)]
pub struct WheelData {
pub steering_speed_light: f32,
pub steering_speed_heavy: f32,
pub steering_force_multiplier_light: f32,
pub steering_force_multiplier_heavy: f32,
pub lateral_acceleration_light: f32,
pub lateral_acceleration_heavy: f32,
pub time_to_max_acceleration_light: f32,
pub time_to_max_acceleration_heavy: f32,
pub brake_force_light: f32,
pub brake_force_heavy: f32,
}
impl std::convert::Into<crate::data::movement_list::WheelData> for WheelData {
fn into(self) -> crate::data::movement_list::WheelData {
crate::data::movement_list::WheelData {
steering_speed_light: self.steering_speed_light,
steering_speed_heavy: self.steering_speed_heavy,
steering_force_multiplier_light: self.steering_force_multiplier_light,
steering_force_multiplier_heavy: self.steering_force_multiplier_heavy,
lateral_acceleration_light: self.lateral_acceleration_light,
lateral_acceleration_heavy: self.lateral_acceleration_heavy,
time_to_max_acceleration_light: self.time_to_max_acceleration_light,
time_to_max_acceleration_heavy: self.time_to_max_acceleration_heavy,
brake_force_light: self.brake_force_light,
brake_force_heavy: self.brake_force_heavy,
}
}
}
#[derive(Serialize, Deserialize, Clone, Debug, Default)]
pub struct HoverData {
pub max_hover_height_light: f32,
pub max_hover_height_heaver: f32,
pub height_change_speed_light: f32,
pub height_change_speed_heavy: f32,
pub turn_torque_light: f32,
pub turn_torque_heavy: f32,
pub acceleration_light: f32,
pub acceleration_heavy: f32,
pub max_angular_velocity_light: f32,
pub max_angular_velocity_heavy: f32,
pub lateral_damping_light: f32,
pub lateral_damping_heavy: f32,
}
impl std::convert::Into<crate::data::movement_list::HoverData> for HoverData {
fn into(self) -> crate::data::movement_list::HoverData {
crate::data::movement_list::HoverData {
max_hover_height_light: self.max_hover_height_light,
max_hover_height_heaver: self.max_hover_height_heaver,
height_change_speed_light: self.height_change_speed_light,
height_change_speed_heavy: self.height_change_speed_heavy,
turn_torque_light: self.turn_torque_light,
turn_torque_heavy: self.turn_torque_heavy,
acceleration_light: self.acceleration_light,
acceleration_heavy: self.acceleration_heavy,
max_angular_velocity_light: self.max_angular_velocity_light,
max_angular_velocity_heavy: self.max_angular_velocity_heavy,
lateral_damping_light: self.lateral_damping_light,
lateral_damping_heavy: self.lateral_damping_heavy,
}
}
}
#[derive(Serialize, Deserialize, Clone, Debug, Default)]
pub struct AerofoilData {
pub barrel_speed_light: f32,
pub barrel_speed_heavy: f32,
pub bank_speed_light: f32,
pub bank_speed_heavy: f32,
pub elevation_speed_light: f32,
pub elevation_speed_heavy: f32,
pub rudder_speed_light: f32,
pub rudder_speed_heavy: f32,
pub thrust_light: f32,
pub thrust_heavy: f32,
pub vtol_velocity_light: f32,
pub vtol_velocity_heavy: f32,
}
impl std::convert::Into<crate::data::movement_list::AerofoilData> for AerofoilData {
fn into(self) -> crate::data::movement_list::AerofoilData {
crate::data::movement_list::AerofoilData {
barrel_speed_light: self.barrel_speed_light,
barrel_speed_heavy: self.barrel_speed_heavy,
bank_speed_light: self.bank_speed_light,
bank_speed_heavy: self.bank_speed_heavy,
elevation_speed_light: self.elevation_speed_light,
elevation_speed_heavy: self.elevation_speed_heavy,
rudder_speed_light: self.rudder_speed_light,
rudder_speed_heavy: self.rudder_speed_heavy,
thrust_light: self.thrust_light,
thrust_heavy: self.thrust_heavy,
vtol_velocity_light: self.vtol_velocity_light,
vtol_velocity_heavy: self.vtol_velocity_heavy,
}
}
}
#[derive(Serialize, Deserialize, Clone, Debug, Default)]
pub struct ThrusterData {
pub acceleration_delay_light: f32,
pub acceleration_delay_heavy: f32,
}
impl std::convert::Into<crate::data::movement_list::ThrusterData> for ThrusterData {
fn into(self) -> crate::data::movement_list::ThrusterData {
crate::data::movement_list::ThrusterData {
acceleration_delay_light: self.acceleration_delay_light,
acceleration_delay_heavy: self.acceleration_delay_heavy,
}
}
}
#[derive(Serialize, Deserialize, Clone, Debug, Default)]
pub struct InsectLegData {
pub ideal_height_light: f32,
pub ideal_height_heavy: f32,
pub ideal_crouching_height_light: f32,
pub ideal_crouching_height_heavy: f32,
pub ideal_height_range_light: f32,
pub ideal_height_range_heavy: f32,
pub jump_height_light: f32,
pub jump_height_heavy: f32,
pub max_upwards_force_light: f32,
pub max_upwards_force_heavy: f32,
pub max_lateral_force_light: f32,
pub max_lateral_force_heavy: f32,
pub max_turning_force_light: f32,
pub max_turning_force_heavy: f32,
pub max_damping_force_light: f32,
pub max_damping_force_heavy: f32,
pub max_stopped_force_light: f32,
pub max_stopped_force_heavy: f32,
pub max_new_stopped_force_light: f32,
pub max_new_stopped_force_heavy: f32,
pub upwards_damping_force_light: f32,
pub upwards_damping_force_heavy: f32,
pub lateral_damp_force_light: f32,
pub lateral_damp_force_heavy: f32,
pub swagger_force_light: f32,
pub swagger_force_heavy: f32,
}
impl std::convert::Into<crate::data::movement_list::InsectLegData> for InsectLegData {
fn into(self) -> crate::data::movement_list::InsectLegData {
crate::data::movement_list::InsectLegData {
ideal_height_light: self.ideal_height_light,
ideal_height_heavy: self.ideal_height_heavy,
ideal_crouching_height_light: self.ideal_crouching_height_light,
ideal_crouching_height_heavy: self.ideal_crouching_height_heavy,
ideal_height_range_light: self.ideal_height_range_light,
ideal_height_range_heavy: self.ideal_height_range_heavy,
jump_height_light: self.jump_height_light,
jump_height_heavy: self.jump_height_heavy,
max_upwards_force_light: self.max_upwards_force_light,
max_upwards_force_heavy: self.max_upwards_force_heavy,
max_lateral_force_light: self.max_lateral_force_light,
max_lateral_force_heavy: self.max_lateral_force_heavy,
max_turning_force_light: self.max_turning_force_light,
max_turning_force_heavy: self.max_turning_force_heavy,
max_damping_force_light: self.max_damping_force_light,
max_damping_force_heavy: self.max_damping_force_heavy,
max_stopped_force_light: self.max_stopped_force_light,
max_stopped_force_heavy: self.max_stopped_force_heavy,
max_new_stopped_force_light: self.max_new_stopped_force_light,
max_new_stopped_force_heavy: self.max_new_stopped_force_heavy,
upwards_damping_force_light: self.upwards_damping_force_light,
upwards_damping_force_heavy: self.upwards_damping_force_heavy,
lateral_damp_force_light: self.lateral_damp_force_light,
lateral_damp_force_heavy: self.lateral_damp_force_heavy,
swagger_force_light: self.swagger_force_light,
swagger_force_heavy: self.swagger_force_heavy,
}
}
}
#[derive(Serialize, Deserialize, Clone, Debug, Default)]
pub struct MechLegData {
pub time_grounded_after_jump_light: f32,
pub time_grounded_after_jump_heavy: f32,
pub jump_height_light: f32,
pub jump_height_heavy: f32,
pub turn_acceleration_light: f32,
pub turn_acceleration_heavy: f32,
pub legacy_turn_acceleration_light: f32,
pub legacy_turn_acceleration_heavy: f32,
pub long_jump_speec_scale_light: f32,
pub long_jump_speec_scale_heavy: f32,
pub max_lateral_force_light: f32,
pub max_lateral_force_heavy: f32,
pub max_damping_force_light: f32,
pub max_damping_force_heavy: f32,
}
impl std::convert::Into<crate::data::movement_list::MechLegData> for MechLegData {
fn into(self) -> crate::data::movement_list::MechLegData {
crate::data::movement_list::MechLegData {
time_grounded_after_jump_light: self.time_grounded_after_jump_light,
time_grounded_after_jump_heavy: self.time_grounded_after_jump_heavy,
jump_height_light: self.jump_height_light,
jump_height_heavy: self.jump_height_heavy,
turn_acceleration_light: self.turn_acceleration_light,
turn_acceleration_heavy: self.turn_acceleration_heavy,
legacy_turn_acceleration_light: self.legacy_turn_acceleration_light,
legacy_turn_acceleration_heavy: self.legacy_turn_acceleration_heavy,
long_jump_speec_scale_light: self.long_jump_speec_scale_light,
long_jump_speec_scale_heavy: self.long_jump_speec_scale_heavy,
max_lateral_force_light: self.max_lateral_force_light,
max_lateral_force_heavy: self.max_lateral_force_heavy,
max_damping_force_light: self.max_damping_force_light,
max_damping_force_heavy: self.max_damping_force_heavy,
}
}
}
#[derive(Serialize, Deserialize, Clone, Debug, Default)]
pub struct TankTrackData {
pub max_turn_rate_moving_light: f32,
pub max_turn_rate_moving_heavy: f32,
pub max_turn_rate_stopped_light: f32,
pub max_turn_rate_stopped_heavy: f32,
pub turn_acceleration_light: f32,
pub turn_acceleration_heavy: f32,
pub lateral_acceleration_light: f32,
pub lateral_acceleration_heavy: f32,
}
impl std::convert::Into<crate::data::movement_list::TankTrackData> for TankTrackData {
fn into(self) -> crate::data::movement_list::TankTrackData {
crate::data::movement_list::TankTrackData {
max_turn_rate_moving_light: self.max_turn_rate_moving_light,
max_turn_rate_moving_heavy: self.max_turn_rate_moving_heavy,
max_turn_rate_stopped_light: self.max_turn_rate_stopped_light,
max_turn_rate_stopped_heavy: self.max_turn_rate_stopped_heavy,
turn_acceleration_light: self.turn_acceleration_light,
turn_acceleration_heavy: self.turn_acceleration_heavy,
lateral_acceleration_light: self.lateral_acceleration_light,
lateral_acceleration_heavy: self.lateral_acceleration_heavy,
}
}
}
#[derive(Serialize, Deserialize, Clone, Debug, Default)]
pub struct RotorData {
pub height_acceleration_light: f32,
pub height_acceleration_heavy: f32,
pub strafe_acceleration_light: f32,
pub strafe_acceleration_heavy: f32,
pub turn_acceleration_light: f32,
pub turn_acceleration_heavy: f32,
pub height_max_change_speed_light: f32,
pub height_max_change_speed_heavy: f32,
pub level_acceleration_light: f32,
pub level_acceleration_heavy: f32,
}
impl std::convert::Into<crate::data::movement_list::RotorData> for RotorData {
fn into(self) -> crate::data::movement_list::RotorData {
crate::data::movement_list::RotorData {
height_acceleration_light: self.height_acceleration_light,
height_acceleration_heavy: self.height_acceleration_heavy,
strafe_acceleration_light: self.strafe_acceleration_light,
strafe_acceleration_heavy: self.strafe_acceleration_heavy,
turn_acceleration_light: self.turn_acceleration_light,
turn_acceleration_heavy: self.turn_acceleration_heavy,
height_max_change_speed_light: self.height_max_change_speed_light,
height_max_change_speed_heavy: self.height_max_change_speed_heavy,
level_acceleration_light: self.level_acceleration_light,
level_acceleration_heavy: self.level_acceleration_heavy,
}
}
}

View File

@@ -0,0 +1,137 @@
use serde::{Serialize, Deserialize};
#[derive(Serialize, Deserialize, Clone, Debug, Default)]
#[serde(default)]
pub struct WeaponData {
pub damage_inflicted: Option<i32>,
pub protonium_damage_scale: Option<f32>,
pub projectile_speed: Option<f32>,
pub projectile_range: Option<f32>,
pub base_inaccuracy: Option<f32>,
pub base_air_inaccuracy: Option<f32>,
pub movement_inaccuracy: Option<f32>,
pub movement_max_speed: Option<f32>,
pub movement_min_speed: Option<f32>,
pub gun_rotation_slow: Option<f32>,
pub movement_inaccuracy_decay: Option<f32>,
pub slow_rotation_decay: Option<f32>,
pub quick_rotation_decay: Option<f32>,
pub movement_inaccuracy_recovery: Option<f32>,
pub repeat_fire_inaccuracy_total_degrees: Option<f32>,
pub repeat_fire_inaccuracy_decay: Option<f32>,
pub repeat_fire_innaccuracy_recovery: Option<f32>,
pub fire_instant_accuracy_decay: Option<f32>, // degrees
pub accuracy_non_recover_time: Option<f32>,
pub accuracy_decay: Option<f32>,
pub damage_radius: Option<f32>,
pub plasma_time_to_full_damage: Option<f32>,
pub plasma_starting_radius_scale: Option<f32>,
pub nano_dps: Option<f32>,
pub nano_hps: Option<f32>,
pub tesla_damage: Option<f32>,
pub tesla_charges: Option<f32>,
pub aeroflak_proximity_damage: Option<f32>,
pub aeroflak_damage_radius: Option<f32>,
pub aeroflak_explosion_radius: Option<f32>,
pub aeroflak_ground_clearance: Option<f32>,
pub aeroflak_max_stacks: Option<i32>,
pub aeroflak_damage_per_stack: Option<i32>,
pub aeroflak_stack_expire: Option<f32>,
pub shot_cooldown: Option<f32>,
pub smart_rotation_cooldown: Option<f32>,
pub smart_rotation_cooldown_extra: Option<f32>,
pub smart_rotation_max_stacks: Option<f32>,
pub spin_up_time: Option<f32>,
pub spin_down_time: Option<f32>,
pub spin_initial_cooldown: Option<f32>,
pub group_fire_scales: Vec<f32>,
pub mana_cost: Option<f32>,
pub lock_time: Option<f32>,
pub full_lock_release: Option<f32>,
pub change_lock_time: Option<f32>,
pub max_rotation_speed: Option<f32>,
pub initial_rotation_speed: Option<f32>,
pub rotation_acceleration: Option<f32>,
pub nano_healing_priority_time: Option<f32>,
pub module_range: Option<f32>,
pub shield_lifetime: Option<f32>,
pub teleport_time: Option<f32>,
pub camera_time: Option<f32>,
pub camera_delay: Option<f32>,
pub to_invisible_speed: Option<f32>,
pub to_invisible_duration: Option<f32>,
pub to_visible_duration: Option<f32>,
pub countdown_time: Option<f32>,
pub stun_time: Option<f32>,
pub stun_radius: Option<f32>,
pub effect_duration: Option<f32>,
}
impl std::convert::Into<crate::data::weapon_list::WeaponData> for WeaponData {
fn into(self) -> crate::data::weapon_list::WeaponData {
crate::data::weapon_list::WeaponData {
damage_inflicted: self.damage_inflicted,
protonium_damage_scale: self.protonium_damage_scale,
projectile_speed: self.projectile_speed,
projectile_range: self.projectile_range,
base_inaccuracy: self.base_inaccuracy,
base_air_inaccuracy: self.base_air_inaccuracy,
movement_inaccuracy: self.movement_inaccuracy,
movement_max_speed: self.movement_max_speed,
movement_min_speed: self.movement_min_speed,
gun_rotation_slow: self.gun_rotation_slow,
movement_inaccuracy_decay: self.movement_inaccuracy_decay,
slow_rotation_decay: self.slow_rotation_decay,
quick_rotation_decay: self.quick_rotation_decay,
movement_inaccuracy_recovery: self.movement_inaccuracy_recovery,
repeat_fire_inaccuracy_total_degrees: self.repeat_fire_inaccuracy_total_degrees,
repeat_fire_inaccuracy_decay: self.repeat_fire_inaccuracy_decay,
repeat_fire_innaccuracy_recovery: self.repeat_fire_innaccuracy_recovery,
fire_instant_accuracy_decay: self.fire_instant_accuracy_decay, // degrees
accuracy_non_recover_time: self.accuracy_non_recover_time,
accuracy_decay: self.accuracy_decay,
damage_radius: self.damage_radius,
plasma_time_to_full_damage: self.plasma_time_to_full_damage,
plasma_starting_radius_scale: self.plasma_starting_radius_scale,
nano_dps: self.nano_dps,
nano_hps: self.nano_hps,
tesla_damage: self.tesla_damage,
tesla_charges: self.tesla_charges,
aeroflak_proximity_damage: self.aeroflak_proximity_damage,
aeroflak_damage_radius: self.aeroflak_damage_radius,
aeroflak_explosion_radius: self.aeroflak_explosion_radius,
aeroflak_ground_clearance: self.aeroflak_ground_clearance,
aeroflak_max_stacks: self.aeroflak_max_stacks,
aeroflak_damage_per_stack: self.aeroflak_damage_per_stack,
aeroflak_stack_expire: self.aeroflak_stack_expire,
shot_cooldown: self.shot_cooldown,
smart_rotation_cooldown: self.smart_rotation_cooldown,
smart_rotation_cooldown_extra: self.smart_rotation_cooldown_extra,
smart_rotation_max_stacks: self.smart_rotation_max_stacks,
spin_up_time: self.spin_up_time,
spin_down_time: self.spin_down_time,
spin_initial_cooldown: self.spin_initial_cooldown,
group_fire_scales: self.group_fire_scales,
mana_cost: self.mana_cost,
lock_time: self.lock_time,
full_lock_release: self.full_lock_release,
change_lock_time: self.change_lock_time,
max_rotation_speed: self.max_rotation_speed,
initial_rotation_speed: self.initial_rotation_speed,
rotation_acceleration: self.rotation_acceleration,
nano_healing_priority_time: self.nano_healing_priority_time,
module_range: self.module_range,
shield_lifetime: self.shield_lifetime,
teleport_time: self.teleport_time,
camera_time: self.camera_time,
camera_delay: self.camera_delay,
to_invisible_speed: self.to_invisible_speed,
to_invisible_duration: self.to_invisible_duration,
to_visible_duration: self.to_visible_duration,
countdown_time: self.countdown_time,
stun_time: self.stun_time,
stun_radius: self.stun_radius,
effect_duration: self.effect_duration,
}
}
}

View File

@@ -0,0 +1 @@
pub mod config;

233
utils/cube_gen.py Normal file
View File

@@ -0,0 +1,233 @@
#!/bin/env python3
import sys
import json
# weapon required data
WEAPONS = {
"Laser" : {
"T0": {
"damage_inflicted": 42,
},
"T1": {
"damage_inflicted": 420,
},
"T2": {
"damage_inflicted": 4200,
},
"T3": {
"damage_inflicted": 42000,
},
"T4": {
"damage_inflicted": 420000,
},
"T5": {
"damage_inflicted": 4200000,
},
},
}
# different from the enum
'''CATEGORIES = {
0: "NotAFunctionalItem",
1: "Wheel",
2: "Hover",
3: "Wing",
4: "Rudder",
5: "Thruster",
6: "InsectLeg",
7: "MechLeg",
8: "Ski",
9: "TankTrack",
10: "Rotor",
11: "SprinterLeg",
12: "Propeller",
100: "Laser",
200: "Plasma",
250: "Mortar",
300: "Rail",
400: "Nano",
500: "Tesla",
600: "Aeroflak",
650: "Ion",
701: "Seeker",
750: "Chaingun",
800: "ShieldModule",
801: "GhostModule",
802: "BlinkModule",
803: "EmpModule",
804: "WindowmakerModule",
900: "EnergyModule",
}'''
CATEGORIES = [
"NotAFunctionalItem",
"Wheel",
"Hover",
"Wing",
"Rudder",
"Thruster",
"InsectLeg",
"MechLeg",
"Ski",
"TankTrack",
"Rotor",
"SprinterLeg",
"Propeller",
"Laser", #13
"Plasma",
"Mortar",
"Rail",
"Nano",
"Tesla",
"Aeroflak",
"Ion",
"Seeker",
"Chaingun",
"ShieldModule", #23
"GhostModule",
"BlinkModule",
"EmpModule",
"WindowmakerModule",
"EnergyModule",
]
def guess_category(name: str, sprite: str, cat: int) -> str:
name = name.lower()
sprite = sprite.lower()
for variant in CATEGORIES:
variant_sanitized = variant.lower()
if variant_sanitized in name or variant_sanitized in sprite:
return variant
return CATEGORIES[0]
def guess_type(name: str, sprite: str, cat: int) -> str:
category = guess_category(name, sprite, cat)
cat_i = CATEGORIES.index(category)
if cat_i == 0:
return "NotAFunctionalItem"
elif cat_i >= 23:
return "Module"
elif cat_i >= 13:
return "Weapon"
elif cat_i >= 1:
return "Movement"
else:
return "NotAFunctionalItem"
def guess_tier(name: str, sprite: str) -> str:
return guess_tier_by_name_str_key(name) or guess_tier_by_size(sprite) or "NoTier"
def guess_tier_by_size(sprite: str) -> str:
sprite = sprite.lower()
if "tiny" in sprite:
return "T0"
elif "small" in sprite:
return "T1"
elif "medium" in sprite:
return "T2"
elif "large" in sprite:
return "T3"
elif "huge" in sprite:
return "T4"
elif "mega" in sprite:
return "T5"
else:
return None
def guess_tier_by_name_str_key(name: str) -> str:
name = name.upper()
if "T0" in name:
return "T0"
elif "T1" in name:
return "T1"
elif "T2" in name:
return "T2"
elif "T3" in name:
return "T3"
elif "T4" in name:
return "T4"
elif "T5" in name:
return "T5"
else:
return None
def placements_to_int(placements: dict) -> int:
return int(placements["1 UInt8 up"]) | \
int(placements["1 UInt8 down"]) << 1 | \
int(placements["1 UInt8 left"]) << 2 | \
int(placements["1 UInt8 right"]) << 3 | \
int(placements["1 UInt8 back"]) << 4 | \
int(placements["1 UInt8 front"]) << 5
def main():
print(sys.argv)
filename_in = sys.argv[1]
with open(filename_in) as f:
cubes_asset = json.load(f)
name = cubes_asset["0 MonoBehaviour Base"]["1 string m_Name"]
print(f"found name (expected to be empty): `{name}`")
cubes = cubes_asset["0 MonoBehaviour Base"]["0 CubeTypeData cubeTypes"]["0 Array Array"]
print(f"found {len(cubes)} cubes to process")
cubes_out = {
"cubes": dict(),
"movement": dict(),
"lerp_value": 10.0,
}
for i in range(len(cubes)):
#print(f"processing cube {i}")
cube = cubes[i]["0 CubeTypeData data"]
name = str(cube["1 string nameStrKey"])
if name.startswith("str"):
name = name[3:]
if name.endswith("Name"):
name = name[:-4]
new_key = name + " hexCode:" + str(cube["1 string itemCode"]) + " intCode:" + str(cube["0 unsigned int itemCodeValue"])
stats = dict()
for stat_i in range(1, 7): # 1 to 6 (inclusive)
stat_key = "1 string stat" + str(stat_i)
if stat_key in cube:
stat_val = cube[stat_key]
#print(f"stat {stat_key} -> {stat_val}")
if len(stat_val) == 0:
continue
if " = " in stat_val:
new_stat_key = str(cube[stat_key]).split(" = ")[0]
new_stat_val = str(cube[stat_key]).split(" = ")[1]
else:
new_stat_key = str(cube[stat_key]).split(": ")[0]
new_stat_val = str(cube[stat_key]).split(": ")[1]
stats[new_stat_key] = new_stat_val
new_entry = {
"id": int(cube["0 unsigned int itemCodeValue"]),
"info": {
"category": guess_category(cube["1 string nameStrKey"], cube["1 string spriteName"], int(cube["0 PersistentCubeData cubeData"]["0 int category"])),
"placements": placements_to_int(cube["0 PersistentCubeData cubeData"]["0 CubeFaces selectableFaces"]),
"stats": stats, # required
"description": str(cube["1 string description"]), # required
"size": guess_tier(cube["1 string nameStrKey"], cube["1 string spriteName"]), # required
"type": guess_type(cube["1 string nameStrKey"], cube["1 string spriteName"], int(cube["0 PersistentCubeData cubeData"]["0 int category"])),
"active": int(cube["1 UInt8 active"]) != 0, # ignored
},
# ignored
"spriteName": cube["1 string spriteName"],
"nameStrKey": cube["1 string nameStrKey"],
"mirrorCubeId": cube["0 PersistentCubeData cubeData"]["1 string mirrorCubeId"],
"hexId": str(cube["1 string itemCode"]),
}
if "CPU LOAD" in stats:
new_entry["info"]["cpu"] = int(stats["CPU LOAD"].strip().split(" ")[0].strip())
if "ARMOR" in stats:
new_entry["info"]["health"] = int(stats["ARMOR"].replace(",", "").strip())
if len(new_entry["info"]["description"].strip()) == 0:
new_entry["info"]["description"] = name + " (" + str(cube["0 unsigned int itemCodeValue"]) + "_10|" + str(cube["1 string itemCode"]) + "_16) without a description"
if new_entry["info"]["category"] in WEAPONS and new_entry["info"]["type"] == "Weapon":
if new_entry["info"]["size"] in WEAPONS[new_entry["info"]["category"]]:
new_entry["weapon"] = WEAPONS[new_entry["info"]["category"]][new_entry["info"]["size"]]
print(f"processed cube {i} into {new_entry}")
cubes_out["cubes"][new_key] = new_entry
with open("../assets/robocraft/cubes.json", "w") as f:
json.dump(cubes_out, f, indent=4)
print(f"processed {len(cubes)} cubes")
if __name__ == "__main__":
main()