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

Get test mode working, complete #12

This commit is contained in:
NGnius (Graham)
2025-03-15 17:21:18 -04:00
parent 6fd4d673ca
commit ec565e904b
31 changed files with 6249 additions and 1743 deletions

View File

@@ -0,0 +1,19 @@
use polariton::operation::Typed;
pub struct AutoRegenHealthConfig {
pub seconds_to_wait_for_heal: f32,
pub seconds_to_full_heal: f32,
pub threshold_to_start_sound: f32,
pub enable_auto_heal: bool,
}
impl AutoRegenHealthConfig {
pub fn as_transmissible<C>(&self) -> Typed<C> {
let mut bytes = Vec::with_capacity(13);
bytes.extend_from_slice(&self.seconds_to_wait_for_heal.to_le_bytes());
bytes.extend_from_slice(&self.seconds_to_full_heal.to_le_bytes());
bytes.extend_from_slice(&self.threshold_to_start_sound.to_le_bytes());
bytes.push(self.enable_auto_heal as u8);
Typed::Bytes(bytes.into())
}
}

View File

@@ -0,0 +1,38 @@
#[repr(i16)]
#[allow(dead_code)]
#[derive(Debug)]
pub enum WebServicesError {
None = 0,
CPUTooHigh = 1,
CPUTooLow = 2,
RobotTierNotAllowed = 3,
CubeIDNotAllowed = 4,
CubeTypeNotAllowed = 5,
DatabaseError = 8,
UnexpectedError = 9,
WrongNumberOfAuthParams = 10,
Banned = 11,
EACValidationFailed = 12,
NotSteamUser = 13,
PromotionDoesntExist = 14,
NotEnoughMoney = 17,
MaxGarageSlots = 18,
PlatformFeatureNotAvailable = 19,
UserDoesNotHaveAllCubeTypes = 20,
ReplaceDailyQuestLimit = 21,
MaintenanceModeError = 125,
RobotShopMaintenanceMode = 126,
InvalidRobot = 140,
ExpiredRobot = 144,
RobotHasSanction = 145,
CustomisationNotOwned = 146,
ItemShopBundleExpired = 147,
UserNotFound = 200,
InvalidUsernameFormat = 201,
UsernameTooLong = 202,
InvalidUsername = 203,
TencentValidationFail = 204,
UsernameAlreadyTaken = 205,
UsernameTooShort = 206,
SaleEnded = 207
}

View File

@@ -32,7 +32,7 @@ impl GarageSlotInfo {
(Typed::Str("wasRated".into()), Typed::Bool(self.was_rated.into())),
(Typed::Str("movementCategories".into()), Typed::Arr(Arr {
ty: TypePrefix::Int, // int
items: self.movement_categories.iter().map(|x| Typed::Int((*x as i32) * 100_000)).collect(),
items: self.movement_categories.iter().map(|x| Typed::Int(x.but_bigger() as i32)).collect(),
})),
(Typed::Str("uniqueId1".into()), Typed::Int(self.uuid.0 as i32)),
(Typed::Str("uniqueId2".into()), Typed::Int(self.uuid.1 as i32)),

View File

@@ -0,0 +1,20 @@
#[repr(i8)]
#[derive(Debug)]
pub enum LobbyType {
None = -1,
CustomGame = 1,
QuickPlay = 2,
Solo = 3
}
impl LobbyType {
pub fn from_int(i: i32) -> Result<Self, i16> {
match i {
-1 => Ok(Self::None),
1 => Ok(Self::CustomGame),
2 => Ok(Self::QuickPlay),
3 => Ok(Self::Solo),
_ => Err(super::error_codes::WebServicesError::UnexpectedError as _),
}
}
}

View File

@@ -21,6 +21,10 @@ pub mod weapon_upgrade;
pub mod player_rank;
pub mod robot_data;
pub mod quest;
pub mod auto_regen;
pub mod voting;
pub mod lobby;
pub mod error_codes;
pub(self) fn encode_7_bit_i32(mut src: i32) -> Vec<u8> {
let mut out = Vec::with_capacity(5);

View File

@@ -54,6 +54,7 @@ pub enum MovementCategorySpecificData {
SprinterLeg(MechLegCategoryData), // same as mech leg
TankTrack,
Rotor(RotorCategoryData),
Ski,
}
impl MovementCategorySpecificData {
@@ -70,6 +71,7 @@ impl MovementCategorySpecificData {
Self::SprinterLeg(x) => x.as_transmissible(),
Self::TankTrack => Vec::default(),
Self::Rotor(x) => x.as_transmissible(),
Self::Ski => Vec::default(),
}
}
}
@@ -161,6 +163,7 @@ pub enum MovementSpecificData {
SprinterLeg(MechLegData), // same as mech leg
TankTrack(TankTrackData),
Rotor(RotorData),
Ski,
}
impl MovementSpecificData {
@@ -177,6 +180,7 @@ impl MovementSpecificData {
Self::SprinterLeg(x) => x.as_transmissible(),
Self::TankTrack(x) => x.as_transmissible(),
Self::Rotor(x) => x.as_transmissible(),
Self::Ski => Vec::default(),
}
}
}
@@ -213,7 +217,7 @@ impl WheelData {
pub struct HoverData {
pub max_hover_height_light: f32,
pub max_hover_height_heaver: f32,
pub max_hover_height_heavy: f32,
pub height_change_speed_light: f32,
pub height_change_speed_heavy: f32,
pub turn_torque_light: f32,
@@ -230,7 +234,7 @@ impl HoverData {
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)),
(Typed::Str("maxHoverHeightHeavy".into()), Typed::Float(self.max_hover_height_heavy)),
(Typed::Str("heightChangeSpeedLight".into()), Typed::Float(self.height_change_speed_light)),
(Typed::Str("heightChangeSpeedHeavy".into()), Typed::Float(self.height_change_speed_heavy)),
(Typed::Str("turnTorqueLight".into()), Typed::Float(self.turn_torque_light)),
@@ -364,8 +368,8 @@ pub struct MechLegData {
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 long_jump_speed_scale_light: f32,
pub long_jump_speed_scale_heavy: f32,
pub max_lateral_force_light: f32,
pub max_lateral_force_heavy: f32,
pub max_damping_force_light: f32,
@@ -383,8 +387,8 @@ impl MechLegData {
(Typed::Str("turnAccelerationHeavy".into()), Typed::Float(self.turn_acceleration_heavy)),
(Typed::Str("legacyTurnAccelerationLight".into()), Typed::Float(self.legacy_turn_acceleration_light)),
(Typed::Str("legacyTurnAccelerationHeavy".into()), Typed::Float(self.legacy_turn_acceleration_heavy)),
(Typed::Str("longJumpSpeedScaleLight".into()), Typed::Float(self.long_jump_speec_scale_light)),
(Typed::Str("longJumpSpeedScaleHeavy".into()), Typed::Float(self.long_jump_speec_scale_heavy)),
(Typed::Str("longJumpSpeedScaleLight".into()), Typed::Float(self.long_jump_speed_scale_light)),
(Typed::Str("longJumpSpeedScaleHeavy".into()), Typed::Float(self.long_jump_speed_scale_heavy)),
(Typed::Str("maxLateralForceLight".into()), Typed::Float(self.max_lateral_force_light)),
(Typed::Str("maxLateralForceHeavy".into()), Typed::Float(self.max_lateral_force_heavy)),
(Typed::Str("maxDampingForceLight".into()), Typed::Float(self.max_damping_force_light)),

View File

@@ -0,0 +1,37 @@
use polariton::{operation::Typed, serdes::TypePrefix};
pub struct VoteThresholdData {
pub name: String,
pub localised_name: String,
pub color: String,
pub votes_required: i32,
}
impl VoteThresholdData {
pub fn as_transmissible<C>(&self) -> Typed<C> {
Typed::Dict(polariton::operation::Dict {
key_ty: TypePrefix::Str,
val_ty: TypePrefix::Any,
items: vec![
(Typed::Str("name".into()), Typed::Str(self.name.clone().into())),
(Typed::Str("localisedName".into()), Typed::Str(self.localised_name.clone().into())),
(Typed::Str("color".into()), Typed::Str(self.color.clone().into())),
(Typed::Str("votesRequired".into()), Typed::Int(self.votes_required)),
]
})
}
}
pub enum Vote {
BestPlayed = 0,
BestLooking = 1,
}
impl Vote {
pub fn as_str(&self) -> &'static str {
match self {
Self::BestPlayed => "BestPlayed",
Self::BestLooking => "BestLooking",
}
}
}

View File

@@ -76,3 +76,16 @@ pub(super) fn garage_machine_save_provider() -> SimpleFunc<41, crate::UserTy, im
})
}
pub const DEFAULT_WEAPON_ORDER_PARAM_KEY: u8 = 138;
pub(super) fn weapon_order_provider() -> SimpleFunc<118, crate::UserTy, impl (Fn(ParameterTable, &crate::UserTy) -> Result<ParameterTable, i16>) + Sync + Sync> {
SimpleFunc::new(|params, user: &crate::UserTy| {
let mut params = params.to_dict();
let lock = user.read().unwrap();
let user_info = lock.user()?;
let weapon_order = user_info.slot_by_id(user_info.selected_garage_slot() as i32)?.weapon_order;
params.insert(DEFAULT_WEAPON_ORDER_PARAM_KEY, weapon_order);
Ok(params.into())
})
}

View File

@@ -72,6 +72,10 @@ mod cube_awards;
mod robot_sanction;
mod building_xp;
mod reconnect_game;
mod regen_config;
mod pageantry;
mod signup_time;
mod validate_machine;
use polariton_server::operations::OperationsHandler;
@@ -161,4 +165,9 @@ pub fn handler(init_ctx: &crate::InitConfig) -> OperationsHandler<crate::UserTy>
.without_state(machine::garage_machine_save_provider())
.without_state(polariton_server::operations::Ack::<32, _>::default()) // TODO handle SaveMachineColorRequest instead of ignoring it
.without_state(polariton_server::operations::Ack::<45, _>::default()) // TODO handle UpdateThumbnailVersionRequest instead of ignoring it
.without_state(machine::weapon_order_provider())
.without_state(regen_config::auto_regen_config_provider(&init_ctx.cubes))
.without_state(pageantry::after_battle_vote_thresholds_provider(&init_ctx.cubes))
.without_state(signup_time::user_signup_date_provider())
.without_state(validate_machine::validate_robot_provider())
}

View File

@@ -0,0 +1,13 @@
use polariton_server::operations::Immediate;
use crate::persist::config::ConfigProvider;
const PARAM_KEY: u8 = 203; // bytes
pub(super) fn after_battle_vote_thresholds_provider(conf: &crate::persist::config::ConfigImpl) -> Immediate<169, crate::UserTy> {
Immediate::new(|| {
let mut params = std::collections::HashMap::with_capacity(1);
params.insert(PARAM_KEY, conf.after_battle_vote_config());
params.into()
})
}

View File

@@ -7,8 +7,8 @@ pub(super) fn power_bar_provider() -> SimpleFunc<51, crate::UserTy, impl (Fn(Par
SimpleFunc::new(|params, _| {
let mut params = params.to_dict();
params.insert(PARAM_KEY, Typed::HashMap(vec![
(Typed::Str("refillRatePerSecond".into()), Typed::Float(1.0)),
(Typed::Str("powerForAllRobots".into()), Typed::Int(1_000 /* converted to u32 */)),
(Typed::Str("refillRatePerSecond".into()), Typed::Float(1000.0)),
(Typed::Str("powerForAllRobots".into()), Typed::Int(1_000_000 /* converted to u32 */)),
].into()
));
Ok(params.into())

View File

@@ -0,0 +1,13 @@
use polariton_server::operations::Immediate;
use crate::persist::config::ConfigProvider;
const PARAM_KEY: u8 = 37; // bytes
pub(super) fn auto_regen_config_provider(conf: &crate::persist::config::ConfigImpl) -> Immediate<35, crate::UserTy> {
Immediate::new(|| {
let mut params = std::collections::HashMap::with_capacity(1);
params.insert(PARAM_KEY, conf.regen_config());
params.into()
})
}

View File

@@ -0,0 +1,14 @@
use polariton_server::operations::SimpleFunc;
use polariton::operation::{ParameterTable, Typed};
const PARAM_KEY: u8 = 71; // long
pub(super) fn user_signup_date_provider() -> SimpleFunc<63, crate::UserTy, impl (Fn(ParameterTable, &crate::UserTy) -> Result<ParameterTable, i16>) + Sync + Sync> {
SimpleFunc::new(|params, user: &crate::UserTy| {
let mut params = params.to_dict();
let lock = user.read().unwrap();
let user_info = lock.user()?;
params.insert(PARAM_KEY, Typed::Long(user_info.signup_date()));
Ok(params.into())
})
}

View File

@@ -14,7 +14,7 @@ pub(super) fn taunts_config_provider() -> SimpleFunc<164, crate::UserTy, impl (F
items: vec![
(Typed::Str("taunts".into()), TauntsData {
taunts: vec![
TauntData {
/*TauntData {
group_name: "totally_real_group_name".to_string(),
assets: AssetData {
idle_effect: "tbd".to_string(),
@@ -33,7 +33,7 @@ pub(super) fn taunts_config_provider() -> SimpleFunc<164, crate::UserTy, impl (F
rotation: 0,
}
]
}
}*/
]
}.as_transmissible())
]

View File

@@ -0,0 +1,30 @@
use polariton_server::operations::SimpleFunc;
use polariton::operation::{ParameterTable, Typed};
const LOBBY_PARAM_KEY: u8 = 134;
const VALIDATE_ROBOT_RESULT_PARAM_KEY: u8 = 111;
// possible codes
#[allow(dead_code)]
#[repr(u8)]
enum ValidateMachineResult {
Invalid = 0,
Ok = 1,
NoWeapon = 2,
NoMovement = 3,
Sanctioned = 4,
}
pub(super) fn validate_robot_provider() -> SimpleFunc<102, crate::UserTy, impl (Fn(ParameterTable, &crate::UserTy) -> Result<ParameterTable, i16>) + Sync + Sync> {
SimpleFunc::new(|params, _user: &crate::UserTy| {
let mut params = params.to_dict();
if let Some(Typed::Int(lobby_ty)) = params.get(&LOBBY_PARAM_KEY) {
log::info!("Got lobby type {} ({:?})", lobby_ty, crate::data::lobby::LobbyType::from_int(*lobby_ty));
}
// let lock = user.read().unwrap();
// let user_info = lock.user()?;
// TODO actually validate the vehicle
params.insert(VALIDATE_ROBOT_RESULT_PARAM_KEY, Typed::Int(ValidateMachineResult::Ok as _));
Ok(params.into())
})
}

View File

@@ -0,0 +1,62 @@
use std::collections::HashMap;
use serde::{Serialize, Deserialize};
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct BattleConfig {
pub regen: AutoRegenHealth,
pub votes: HashMap<Vote, Vec<VoteThreshold>>,
}
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct AutoRegenHealth {
pub wait_for_heal_s: f32,
pub wait_full_heal_s: f32,
pub sound_start_s: f32,
pub auto_heal: bool,
}
impl std::convert::Into<crate::data::auto_regen::AutoRegenHealthConfig> for AutoRegenHealth {
fn into(self) -> crate::data::auto_regen::AutoRegenHealthConfig {
crate::data::auto_regen::AutoRegenHealthConfig {
seconds_to_wait_for_heal: self.wait_for_heal_s,
seconds_to_full_heal: self.wait_full_heal_s,
threshold_to_start_sound: self.sound_start_s,
enable_auto_heal: self.auto_heal,
}
}
}
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct VoteThreshold {
pub name: String,
pub localised_name: String,
pub color: String,
pub votes_required: i32,
}
impl std::convert::Into<crate::data::voting::VoteThresholdData> for VoteThreshold {
fn into(self) -> crate::data::voting::VoteThresholdData {
crate::data::voting::VoteThresholdData {
name: self.name,
localised_name: self.localised_name,
color: self.color,
votes_required: self.votes_required,
}
}
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, Hash)]
pub enum Vote {
BestPlayed,
BestLooking,
}
impl std::convert::Into<crate::data::voting::Vote> for Vote {
fn into(self) -> crate::data::voting::Vote {
match self {
Self::BestPlayed => crate::data::voting::Vote::BestPlayed,
Self::BestLooking => crate::data::voting::Vote::BestLooking,
}
}
}

View File

@@ -5,15 +5,16 @@ use serde::{Serialize, Deserialize};
use polariton::operation::{Typed, Dict};
use polariton::serdes::TypePrefix;
use super::super::{MovementCategoryData, MovementData, Cube, ItemCategory, ItemTier};
use super::super::{MovementCategoryData, MovementData, Cube, ItemCategory, ItemTier, BattleConfig};
const CUBE_CONFIG_FILENAME: &str = "cubes.json";
const CUBE_CONFIG_FILENAME: &str = "config.json";
#[derive(Serialize, Deserialize, Debug)]
pub struct CubeConfig {
cubes: HashMap<String, Cube>,
movement: HashMap<ItemCategory, MovementCategoryData>,
lerp_value: f32,
battle: BattleConfig,
}
impl CubeConfig {
@@ -153,4 +154,27 @@ impl <C: Clone> super::ConfigProvider<C> for CubeConfig {
fn ids(&self) -> Vec<u32> {
self.cubes.values().map(|cube| cube.id).collect()
}
fn regen_config(&self) -> Typed<C> {
let regen_data: crate::data::auto_regen::AutoRegenHealthConfig = self.battle.regen.clone().into();
regen_data.as_transmissible()
}
fn after_battle_vote_config(&self) -> Typed<C> {
let mut vote_data = Vec::with_capacity(self.battle.votes.len()); // probably len() == 2
for (key, val) in self.battle.votes.iter() {
let key_data: crate::data::voting::Vote = key.to_owned().into();
let mut val_data = Vec::with_capacity(val.len());
for item in val {
let vote_data: crate::data::voting::VoteThresholdData = item.to_owned().into();
val_data.push(vote_data.as_transmissible());
}
vote_data.push((Typed::Str(key_data.as_str().into()), Typed::ObjArr(val_data.into())));
}
Typed::Dict(Dict {
key_ty: TypePrefix::Str,
val_ty: TypePrefix::Any,
items: vote_data,
})
}
}

View File

@@ -7,4 +7,6 @@ pub trait ConfigProvider<C> {
fn weapon_upgrade_list(&self) -> Typed<C>;
fn tech_tree_nodes(&self, unlocked_cubes: &std::collections::HashSet<u32>) -> Typed<C>;
fn ids(&self) -> Vec<u32>;
fn regen_config(&self) -> Typed<C>;
fn after_battle_vote_config(&self) -> Typed<C>;
}

View File

@@ -22,7 +22,7 @@ pub struct CubeInfo {
pub cpu: u32,
#[serde(default = "default_1")]
pub health: u32,
#[serde(default = "default_1_0")]
#[serde(default)]
pub health_boost: f32,
#[serde(default)]
pub grey_out_in_tutorial: bool,
@@ -59,10 +59,6 @@ fn default_1() -> u32 {
1
}
fn default_1_0() -> f32 {
1.0
}
fn default_63() -> u32 {
63
}
@@ -113,8 +109,8 @@ impl <C: Clone> std::convert::Into<crate::data::cube_list::CubeInfo<C>> for Cube
#[derive(Serialize, Deserialize, Clone, Copy, Debug, Default)]
pub enum VisibilityMode {
Mothership,
#[default]
Mothership,
All,
Tutorial,
None,

View File

@@ -16,3 +16,6 @@ pub use weapon::{WeaponData, WeaponUpgradeInfo};
mod tech_tree;
pub use tech_tree::TechTreeData;
mod combat;
pub use combat::BattleConfig;

View File

@@ -11,6 +11,7 @@ pub struct MovementCategoryData {
pub max_hover_height: Option<f32>,
pub light_machine_mass: Option<f32>,
pub heavy_machine_mass: Option<f32>,
#[serde(flatten)]
pub specifics: MovementCategorySpecificData,
}
@@ -31,6 +32,7 @@ impl MovementCategoryData {
}
#[derive(Serialize, Deserialize, Clone, Debug, Default)]
#[serde(tag = "movement_enum_variant")]
pub enum MovementCategorySpecificData {
#[default]
Wheel,
@@ -44,6 +46,7 @@ pub enum MovementCategorySpecificData {
SprinterLeg(MechLegCategoryData), // same as mech leg
TankTrack,
Rotor(RotorCategoryData),
Ski,
}
impl std::convert::Into<crate::data::movement_list::MovementCategorySpecificData> for MovementCategorySpecificData {
@@ -60,6 +63,7 @@ impl std::convert::Into<crate::data::movement_list::MovementCategorySpecificData
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()),
Self::Ski => crate::data::movement_list::MovementCategorySpecificData::Ski,
}
}
}
@@ -123,6 +127,7 @@ pub struct MovementData {
pub max_carry_mass: Option<f32>,
pub horizontal_top_speed: Option<f32>,
pub vertical_top_speed: Option<f32>,
#[serde(flatten)]
pub specifics: MovementSpecificData,
}
@@ -139,6 +144,7 @@ impl std::convert::Into<crate::data::movement_list::MovementData> for MovementDa
}
#[derive(Serialize, Deserialize, Clone, Debug)]
#[serde(tag = "movement_enum_variant")]
pub enum MovementSpecificData {
Wheel(WheelData),
Hover(HoverData),
@@ -151,6 +157,7 @@ pub enum MovementSpecificData {
SprinterLeg(MechLegData), // same as mech leg
TankTrack(TankTrackData),
Rotor(RotorData),
Ski,
}
impl std::convert::Into<crate::data::movement_list::MovementSpecificData> for MovementSpecificData {
@@ -167,6 +174,7 @@ impl std::convert::Into<crate::data::movement_list::MovementSpecificData> for Mo
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()),
Self::Ski=> crate::data::movement_list::MovementSpecificData::Ski,
}
}
}
@@ -205,7 +213,7 @@ impl std::convert::Into<crate::data::movement_list::WheelData> for WheelData {
#[derive(Serialize, Deserialize, Clone, Debug, Default)]
pub struct HoverData {
pub max_hover_height_light: f32,
pub max_hover_height_heaver: f32,
pub max_hover_height_heavy: f32,
pub height_change_speed_light: f32,
pub height_change_speed_heavy: f32,
pub turn_torque_light: f32,
@@ -222,7 +230,7 @@ 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,
max_hover_height_heavy: self.max_hover_height_heavy,
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,
@@ -360,8 +368,8 @@ pub struct MechLegData {
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 long_jump_speed_scale_light: f32,
pub long_jump_speed_scale_heavy: f32,
pub max_lateral_force_light: f32,
pub max_lateral_force_heavy: f32,
pub max_damping_force_light: f32,
@@ -379,8 +387,8 @@ impl std::convert::Into<crate::data::movement_list::MechLegData> for MechLegData
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,
long_jump_speed_scale_light: self.long_jump_speed_scale_light,
long_jump_speed_scale_heavy: self.long_jump_speed_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,

View File

@@ -142,10 +142,10 @@ impl <C: Clone> super::User<C> for UserData {
data: polariton::operation::Typed::Bytes(slot.robot_data.into()),
colour_data: polariton::operation::Typed::Bytes(slot.colour_data.into()),
cube_count: polariton::operation::Typed::Int(slot.cubes as _),
weapon_order: polariton::operation::Typed::IntArr(vec![0].into()), // TODO
weapon_order: polariton::operation::Typed::IntArr(slot.weapon_order.clone().into()),
movement_categories: polariton::operation::Typed::IntArr(slot.movement_categories.into_iter().map(|cat| {
let cat: crate::data::weapon_list::ItemCategory = cat.into();
cat as i32
cat.but_bigger()
}).collect::<Vec<_>>().into()),
control_type: polariton::operation::Typed::Int(control_ty as _),
control_options: control_options.as_transmissible(),
@@ -169,12 +169,34 @@ impl <C: Clone> super::User<C> for UserData {
existing_data.robot_data = vehicle.robot_data;
existing_data.colour_data = vehicle.colour_data;
log::debug!("weapon order: {:?}", vehicle.weapon_order);
existing_data.weapon_order = vehicle.weapon_order;
self.save_garage(&existing_data).map_err(|e| {
log::error!("Failed to save vehicle {}: {}", id, e);
DATABASE_ERR
})?;
Ok(())
}
fn signup_date(&self) -> i64 {
match self.root.metadata() {
Ok(meta) => {
match meta.created() {
Ok(created) => {
match created.duration_since(std::time::SystemTime::UNIX_EPOCH) {
Ok(dur) => {
return super::since_windows_epoch(dur.as_secs() as i64);
},
Err(e) => log::error!("could not get duration since unix epoch of {}: {}", self.root.display(), e),
}
},
Err(e) => log::error!("could not read creation time of {}: {}", self.root.display(), e),
}
},
Err(e) => log::error!("could not retrieve metadata of {}: {}", self.root.display(), e),
}
super::since_windows_epoch(0)
}
}
#[derive(Serialize, Deserialize, Clone, Debug)]

View File

@@ -60,7 +60,7 @@ fn default_garage_slots() -> Vec<crate::persist::GarageSlot> {
control_options: crate::persist::GarageControls { vertical_strafing: false, sideways_driving: false, tracks_turn_on_spot: false, },
mastery_level: 1,
bay_skin_id: "RC_MothershipSkin_Neptune_01".to_owned(), // TODO get the rest of the names
weapon_order: vec![0],
weapon_order: vec![],
robot_data: vec![0; 4],
colour_data: vec![0; 4],
}

View File

@@ -24,3 +24,11 @@ fn __must_impl<T: UserProvider<()>>() {}
fn __test_impl() {
__must_impl::<UserImpl>();
}
pub fn since_windows_epoch(since_unix_epoch: i64) -> i64 {
use chrono::TimeZone;
let windows_epoch = chrono::Utc.from_utc_datetime(&chrono::NaiveDateTime::parse_from_str("1601-01-01 00:00:00", "%Y-%m-%d %H:%M:%S").unwrap());
let time_in = chrono::DateTime::<chrono::Utc>::from_timestamp(since_unix_epoch, 0).unwrap();
//let time_in = chrono::Utc.from_utc_datetime(&chrono::NaiveDateTime::from_timestamp(since_unix_epoch, 0));
time_in.signed_duration_since(windows_epoch).num_milliseconds() * 10_000
}

View File

@@ -21,6 +21,7 @@ pub trait User<C> {
fn all_slots_by_id(&self) -> UserSlots<C>;
fn slot_by_id(&self, id: i32) -> Result<UserSlotData<C>, i16>;
fn save_slot(&self, vehicle: VehicleData) -> Result<(), i16>;
fn signup_date(&self) -> i64;
}
pub struct UserSlots<C> {