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:
1
Cargo.lock
generated
1
Cargo.lock
generated
@@ -1774,6 +1774,7 @@ name = "rc_services_room"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"base64 0.22.1",
|
"base64 0.22.1",
|
||||||
|
"chrono",
|
||||||
"clap",
|
"clap",
|
||||||
"env_logger",
|
"env_logger",
|
||||||
"hex",
|
"hex",
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -11,5 +11,6 @@ pub fn handler() -> OperationsHandler<crate::UserTy> {
|
|||||||
.without_state(chat_ignores::ignores_provider())
|
.without_state(chat_ignores::ignores_provider())
|
||||||
.without_state(pending_sanctions::pending_sanctions_checker())
|
.without_state(pending_sanctions::pending_sanctions_checker())
|
||||||
.without_state(all_joined_channels::all_channels_provider())
|
.without_state(all_joined_channels::all_channels_provider())
|
||||||
|
.without_state(polariton_server::operations::Ack::<12, _>::default())
|
||||||
//.without_state(polariton_server::operations::Ack::<00000, _>::default())
|
//.without_state(polariton_server::operations::Ack::<00000, _>::default())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,3 +15,4 @@ base64 = "0.22"
|
|||||||
hex = "0.4"
|
hex = "0.4"
|
||||||
serde.workspace = true
|
serde.workspace = true
|
||||||
serde_json.workspace = true
|
serde_json.workspace = true
|
||||||
|
chrono = "0.4"
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
RUST_BACKTRACE=1 RUST_LOG=debug cargo run
|
RUST_BACKTRACE=1 RUST_LOG=debug cargo run #&> ../data/rc_services_room.log
|
||||||
|
|||||||
19
rc_services_room/src/data/auto_regen.rs
Normal file
19
rc_services_room/src/data/auto_regen.rs
Normal 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())
|
||||||
|
}
|
||||||
|
}
|
||||||
38
rc_services_room/src/data/error_codes.rs
Normal file
38
rc_services_room/src/data/error_codes.rs
Normal 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
|
||||||
|
}
|
||||||
@@ -32,7 +32,7 @@ impl GarageSlotInfo {
|
|||||||
(Typed::Str("wasRated".into()), Typed::Bool(self.was_rated.into())),
|
(Typed::Str("wasRated".into()), Typed::Bool(self.was_rated.into())),
|
||||||
(Typed::Str("movementCategories".into()), Typed::Arr(Arr {
|
(Typed::Str("movementCategories".into()), Typed::Arr(Arr {
|
||||||
ty: TypePrefix::Int, // int
|
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("uniqueId1".into()), Typed::Int(self.uuid.0 as i32)),
|
||||||
(Typed::Str("uniqueId2".into()), Typed::Int(self.uuid.1 as i32)),
|
(Typed::Str("uniqueId2".into()), Typed::Int(self.uuid.1 as i32)),
|
||||||
|
|||||||
20
rc_services_room/src/data/lobby.rs
Normal file
20
rc_services_room/src/data/lobby.rs
Normal 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 _),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -21,6 +21,10 @@ pub mod weapon_upgrade;
|
|||||||
pub mod player_rank;
|
pub mod player_rank;
|
||||||
pub mod robot_data;
|
pub mod robot_data;
|
||||||
pub mod quest;
|
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> {
|
pub(self) fn encode_7_bit_i32(mut src: i32) -> Vec<u8> {
|
||||||
let mut out = Vec::with_capacity(5);
|
let mut out = Vec::with_capacity(5);
|
||||||
|
|||||||
@@ -54,6 +54,7 @@ pub enum MovementCategorySpecificData {
|
|||||||
SprinterLeg(MechLegCategoryData), // same as mech leg
|
SprinterLeg(MechLegCategoryData), // same as mech leg
|
||||||
TankTrack,
|
TankTrack,
|
||||||
Rotor(RotorCategoryData),
|
Rotor(RotorCategoryData),
|
||||||
|
Ski,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MovementCategorySpecificData {
|
impl MovementCategorySpecificData {
|
||||||
@@ -70,6 +71,7 @@ impl MovementCategorySpecificData {
|
|||||||
Self::SprinterLeg(x) => x.as_transmissible(),
|
Self::SprinterLeg(x) => x.as_transmissible(),
|
||||||
Self::TankTrack => Vec::default(),
|
Self::TankTrack => Vec::default(),
|
||||||
Self::Rotor(x) => x.as_transmissible(),
|
Self::Rotor(x) => x.as_transmissible(),
|
||||||
|
Self::Ski => Vec::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -161,6 +163,7 @@ pub enum MovementSpecificData {
|
|||||||
SprinterLeg(MechLegData), // same as mech leg
|
SprinterLeg(MechLegData), // same as mech leg
|
||||||
TankTrack(TankTrackData),
|
TankTrack(TankTrackData),
|
||||||
Rotor(RotorData),
|
Rotor(RotorData),
|
||||||
|
Ski,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MovementSpecificData {
|
impl MovementSpecificData {
|
||||||
@@ -177,6 +180,7 @@ impl MovementSpecificData {
|
|||||||
Self::SprinterLeg(x) => x.as_transmissible(),
|
Self::SprinterLeg(x) => x.as_transmissible(),
|
||||||
Self::TankTrack(x) => x.as_transmissible(),
|
Self::TankTrack(x) => x.as_transmissible(),
|
||||||
Self::Rotor(x) => x.as_transmissible(),
|
Self::Rotor(x) => x.as_transmissible(),
|
||||||
|
Self::Ski => Vec::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -213,7 +217,7 @@ impl WheelData {
|
|||||||
|
|
||||||
pub struct HoverData {
|
pub struct HoverData {
|
||||||
pub max_hover_height_light: f32,
|
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_light: f32,
|
||||||
pub height_change_speed_heavy: f32,
|
pub height_change_speed_heavy: f32,
|
||||||
pub turn_torque_light: f32,
|
pub turn_torque_light: f32,
|
||||||
@@ -230,7 +234,7 @@ impl HoverData {
|
|||||||
pub fn as_transmissible<C>(&self) -> Vec<(Typed<C>, Typed<C>)> {
|
pub fn as_transmissible<C>(&self) -> Vec<(Typed<C>, Typed<C>)> {
|
||||||
vec![
|
vec![
|
||||||
(Typed::Str("maxHoverHeightLight".into()), Typed::Float(self.max_hover_height_light)),
|
(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("heightChangeSpeedLight".into()), Typed::Float(self.height_change_speed_light)),
|
||||||
(Typed::Str("heightChangeSpeedHeavy".into()), Typed::Float(self.height_change_speed_heavy)),
|
(Typed::Str("heightChangeSpeedHeavy".into()), Typed::Float(self.height_change_speed_heavy)),
|
||||||
(Typed::Str("turnTorqueLight".into()), Typed::Float(self.turn_torque_light)),
|
(Typed::Str("turnTorqueLight".into()), Typed::Float(self.turn_torque_light)),
|
||||||
@@ -364,8 +368,8 @@ pub struct MechLegData {
|
|||||||
pub turn_acceleration_heavy: f32,
|
pub turn_acceleration_heavy: f32,
|
||||||
pub legacy_turn_acceleration_light: f32,
|
pub legacy_turn_acceleration_light: f32,
|
||||||
pub legacy_turn_acceleration_heavy: f32,
|
pub legacy_turn_acceleration_heavy: f32,
|
||||||
pub long_jump_speec_scale_light: f32,
|
pub long_jump_speed_scale_light: f32,
|
||||||
pub long_jump_speec_scale_heavy: f32,
|
pub long_jump_speed_scale_heavy: f32,
|
||||||
pub max_lateral_force_light: f32,
|
pub max_lateral_force_light: f32,
|
||||||
pub max_lateral_force_heavy: f32,
|
pub max_lateral_force_heavy: f32,
|
||||||
pub max_damping_force_light: 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("turnAccelerationHeavy".into()), Typed::Float(self.turn_acceleration_heavy)),
|
||||||
(Typed::Str("legacyTurnAccelerationLight".into()), Typed::Float(self.legacy_turn_acceleration_light)),
|
(Typed::Str("legacyTurnAccelerationLight".into()), Typed::Float(self.legacy_turn_acceleration_light)),
|
||||||
(Typed::Str("legacyTurnAccelerationHeavy".into()), Typed::Float(self.legacy_turn_acceleration_heavy)),
|
(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("longJumpSpeedScaleLight".into()), Typed::Float(self.long_jump_speed_scale_light)),
|
||||||
(Typed::Str("longJumpSpeedScaleHeavy".into()), Typed::Float(self.long_jump_speec_scale_heavy)),
|
(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("maxLateralForceLight".into()), Typed::Float(self.max_lateral_force_light)),
|
||||||
(Typed::Str("maxLateralForceHeavy".into()), Typed::Float(self.max_lateral_force_heavy)),
|
(Typed::Str("maxLateralForceHeavy".into()), Typed::Float(self.max_lateral_force_heavy)),
|
||||||
(Typed::Str("maxDampingForceLight".into()), Typed::Float(self.max_damping_force_light)),
|
(Typed::Str("maxDampingForceLight".into()), Typed::Float(self.max_damping_force_light)),
|
||||||
|
|||||||
37
rc_services_room/src/data/voting.rs
Normal file
37
rc_services_room/src/data/voting.rs
Normal 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",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -72,6 +72,10 @@ mod cube_awards;
|
|||||||
mod robot_sanction;
|
mod robot_sanction;
|
||||||
mod building_xp;
|
mod building_xp;
|
||||||
mod reconnect_game;
|
mod reconnect_game;
|
||||||
|
mod regen_config;
|
||||||
|
mod pageantry;
|
||||||
|
mod signup_time;
|
||||||
|
mod validate_machine;
|
||||||
|
|
||||||
use polariton_server::operations::OperationsHandler;
|
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(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::<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(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())
|
||||||
}
|
}
|
||||||
|
|||||||
13
rc_services_room/src/operations/pageantry.rs
Normal file
13
rc_services_room/src/operations/pageantry.rs
Normal 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()
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -7,8 +7,8 @@ pub(super) fn power_bar_provider() -> SimpleFunc<51, crate::UserTy, impl (Fn(Par
|
|||||||
SimpleFunc::new(|params, _| {
|
SimpleFunc::new(|params, _| {
|
||||||
let mut params = params.to_dict();
|
let mut params = params.to_dict();
|
||||||
params.insert(PARAM_KEY, Typed::HashMap(vec![
|
params.insert(PARAM_KEY, Typed::HashMap(vec![
|
||||||
(Typed::Str("refillRatePerSecond".into()), Typed::Float(1.0)),
|
(Typed::Str("refillRatePerSecond".into()), Typed::Float(1000.0)),
|
||||||
(Typed::Str("powerForAllRobots".into()), Typed::Int(1_000 /* converted to u32 */)),
|
(Typed::Str("powerForAllRobots".into()), Typed::Int(1_000_000 /* converted to u32 */)),
|
||||||
].into()
|
].into()
|
||||||
));
|
));
|
||||||
Ok(params.into())
|
Ok(params.into())
|
||||||
|
|||||||
13
rc_services_room/src/operations/regen_config.rs
Normal file
13
rc_services_room/src/operations/regen_config.rs
Normal 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()
|
||||||
|
})
|
||||||
|
}
|
||||||
14
rc_services_room/src/operations/signup_time.rs
Normal file
14
rc_services_room/src/operations/signup_time.rs
Normal 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())
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -14,7 +14,7 @@ pub(super) fn taunts_config_provider() -> SimpleFunc<164, crate::UserTy, impl (F
|
|||||||
items: vec![
|
items: vec![
|
||||||
(Typed::Str("taunts".into()), TauntsData {
|
(Typed::Str("taunts".into()), TauntsData {
|
||||||
taunts: vec![
|
taunts: vec![
|
||||||
TauntData {
|
/*TauntData {
|
||||||
group_name: "totally_real_group_name".to_string(),
|
group_name: "totally_real_group_name".to_string(),
|
||||||
assets: AssetData {
|
assets: AssetData {
|
||||||
idle_effect: "tbd".to_string(),
|
idle_effect: "tbd".to_string(),
|
||||||
@@ -33,7 +33,7 @@ pub(super) fn taunts_config_provider() -> SimpleFunc<164, crate::UserTy, impl (F
|
|||||||
rotation: 0,
|
rotation: 0,
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}*/
|
||||||
]
|
]
|
||||||
}.as_transmissible())
|
}.as_transmissible())
|
||||||
]
|
]
|
||||||
|
|||||||
30
rc_services_room/src/operations/validate_machine.rs
Normal file
30
rc_services_room/src/operations/validate_machine.rs
Normal 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())
|
||||||
|
})
|
||||||
|
}
|
||||||
62
rc_services_room/src/persist/combat.rs
Normal file
62
rc_services_room/src/persist/combat.rs
Normal 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,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,15 +5,16 @@ use serde::{Serialize, Deserialize};
|
|||||||
use polariton::operation::{Typed, Dict};
|
use polariton::operation::{Typed, Dict};
|
||||||
use polariton::serdes::TypePrefix;
|
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)]
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
pub struct CubeConfig {
|
pub struct CubeConfig {
|
||||||
cubes: HashMap<String, Cube>,
|
cubes: HashMap<String, Cube>,
|
||||||
movement: HashMap<ItemCategory, MovementCategoryData>,
|
movement: HashMap<ItemCategory, MovementCategoryData>,
|
||||||
lerp_value: f32,
|
lerp_value: f32,
|
||||||
|
battle: BattleConfig,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CubeConfig {
|
impl CubeConfig {
|
||||||
@@ -153,4 +154,27 @@ impl <C: Clone> super::ConfigProvider<C> for CubeConfig {
|
|||||||
fn ids(&self) -> Vec<u32> {
|
fn ids(&self) -> Vec<u32> {
|
||||||
self.cubes.values().map(|cube| cube.id).collect()
|
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,
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,4 +7,6 @@ pub trait ConfigProvider<C> {
|
|||||||
fn weapon_upgrade_list(&self) -> Typed<C>;
|
fn weapon_upgrade_list(&self) -> Typed<C>;
|
||||||
fn tech_tree_nodes(&self, unlocked_cubes: &std::collections::HashSet<u32>) -> Typed<C>;
|
fn tech_tree_nodes(&self, unlocked_cubes: &std::collections::HashSet<u32>) -> Typed<C>;
|
||||||
fn ids(&self) -> Vec<u32>;
|
fn ids(&self) -> Vec<u32>;
|
||||||
|
fn regen_config(&self) -> Typed<C>;
|
||||||
|
fn after_battle_vote_config(&self) -> Typed<C>;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ pub struct CubeInfo {
|
|||||||
pub cpu: u32,
|
pub cpu: u32,
|
||||||
#[serde(default = "default_1")]
|
#[serde(default = "default_1")]
|
||||||
pub health: u32,
|
pub health: u32,
|
||||||
#[serde(default = "default_1_0")]
|
#[serde(default)]
|
||||||
pub health_boost: f32,
|
pub health_boost: f32,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub grey_out_in_tutorial: bool,
|
pub grey_out_in_tutorial: bool,
|
||||||
@@ -59,10 +59,6 @@ fn default_1() -> u32 {
|
|||||||
1
|
1
|
||||||
}
|
}
|
||||||
|
|
||||||
fn default_1_0() -> f32 {
|
|
||||||
1.0
|
|
||||||
}
|
|
||||||
|
|
||||||
fn default_63() -> u32 {
|
fn default_63() -> u32 {
|
||||||
63
|
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)]
|
#[derive(Serialize, Deserialize, Clone, Copy, Debug, Default)]
|
||||||
pub enum VisibilityMode {
|
pub enum VisibilityMode {
|
||||||
Mothership,
|
|
||||||
#[default]
|
#[default]
|
||||||
|
Mothership,
|
||||||
All,
|
All,
|
||||||
Tutorial,
|
Tutorial,
|
||||||
None,
|
None,
|
||||||
|
|||||||
@@ -16,3 +16,6 @@ pub use weapon::{WeaponData, WeaponUpgradeInfo};
|
|||||||
|
|
||||||
mod tech_tree;
|
mod tech_tree;
|
||||||
pub use tech_tree::TechTreeData;
|
pub use tech_tree::TechTreeData;
|
||||||
|
|
||||||
|
mod combat;
|
||||||
|
pub use combat::BattleConfig;
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ pub struct MovementCategoryData {
|
|||||||
pub max_hover_height: Option<f32>,
|
pub max_hover_height: Option<f32>,
|
||||||
pub light_machine_mass: Option<f32>,
|
pub light_machine_mass: Option<f32>,
|
||||||
pub heavy_machine_mass: Option<f32>,
|
pub heavy_machine_mass: Option<f32>,
|
||||||
|
#[serde(flatten)]
|
||||||
pub specifics: MovementCategorySpecificData,
|
pub specifics: MovementCategorySpecificData,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -31,6 +32,7 @@ impl MovementCategoryData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug, Default)]
|
#[derive(Serialize, Deserialize, Clone, Debug, Default)]
|
||||||
|
#[serde(tag = "movement_enum_variant")]
|
||||||
pub enum MovementCategorySpecificData {
|
pub enum MovementCategorySpecificData {
|
||||||
#[default]
|
#[default]
|
||||||
Wheel,
|
Wheel,
|
||||||
@@ -44,6 +46,7 @@ pub enum MovementCategorySpecificData {
|
|||||||
SprinterLeg(MechLegCategoryData), // same as mech leg
|
SprinterLeg(MechLegCategoryData), // same as mech leg
|
||||||
TankTrack,
|
TankTrack,
|
||||||
Rotor(RotorCategoryData),
|
Rotor(RotorCategoryData),
|
||||||
|
Ski,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::convert::Into<crate::data::movement_list::MovementCategorySpecificData> for MovementCategorySpecificData {
|
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::SprinterLeg(x) => crate::data::movement_list::MovementCategorySpecificData::SprinterLeg(x.into()),
|
||||||
Self::TankTrack => crate::data::movement_list::MovementCategorySpecificData::TankTrack,
|
Self::TankTrack => crate::data::movement_list::MovementCategorySpecificData::TankTrack,
|
||||||
Self::Rotor(x) => crate::data::movement_list::MovementCategorySpecificData::Rotor(x.into()),
|
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 max_carry_mass: Option<f32>,
|
||||||
pub horizontal_top_speed: Option<f32>,
|
pub horizontal_top_speed: Option<f32>,
|
||||||
pub vertical_top_speed: Option<f32>,
|
pub vertical_top_speed: Option<f32>,
|
||||||
|
#[serde(flatten)]
|
||||||
pub specifics: MovementSpecificData,
|
pub specifics: MovementSpecificData,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -139,6 +144,7 @@ impl std::convert::Into<crate::data::movement_list::MovementData> for MovementDa
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||||
|
#[serde(tag = "movement_enum_variant")]
|
||||||
pub enum MovementSpecificData {
|
pub enum MovementSpecificData {
|
||||||
Wheel(WheelData),
|
Wheel(WheelData),
|
||||||
Hover(HoverData),
|
Hover(HoverData),
|
||||||
@@ -151,6 +157,7 @@ pub enum MovementSpecificData {
|
|||||||
SprinterLeg(MechLegData), // same as mech leg
|
SprinterLeg(MechLegData), // same as mech leg
|
||||||
TankTrack(TankTrackData),
|
TankTrack(TankTrackData),
|
||||||
Rotor(RotorData),
|
Rotor(RotorData),
|
||||||
|
Ski,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::convert::Into<crate::data::movement_list::MovementSpecificData> for MovementSpecificData {
|
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::SprinterLeg(x) => crate::data::movement_list::MovementSpecificData::SprinterLeg(x.into()),
|
||||||
Self::TankTrack(x) => crate::data::movement_list::MovementSpecificData::TankTrack(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::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)]
|
#[derive(Serialize, Deserialize, Clone, Debug, Default)]
|
||||||
pub struct HoverData {
|
pub struct HoverData {
|
||||||
pub max_hover_height_light: f32,
|
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_light: f32,
|
||||||
pub height_change_speed_heavy: f32,
|
pub height_change_speed_heavy: f32,
|
||||||
pub turn_torque_light: 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 {
|
fn into(self) -> crate::data::movement_list::HoverData {
|
||||||
crate::data::movement_list::HoverData {
|
crate::data::movement_list::HoverData {
|
||||||
max_hover_height_light: self.max_hover_height_light,
|
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_light: self.height_change_speed_light,
|
||||||
height_change_speed_heavy: self.height_change_speed_heavy,
|
height_change_speed_heavy: self.height_change_speed_heavy,
|
||||||
turn_torque_light: self.turn_torque_light,
|
turn_torque_light: self.turn_torque_light,
|
||||||
@@ -360,8 +368,8 @@ pub struct MechLegData {
|
|||||||
pub turn_acceleration_heavy: f32,
|
pub turn_acceleration_heavy: f32,
|
||||||
pub legacy_turn_acceleration_light: f32,
|
pub legacy_turn_acceleration_light: f32,
|
||||||
pub legacy_turn_acceleration_heavy: f32,
|
pub legacy_turn_acceleration_heavy: f32,
|
||||||
pub long_jump_speec_scale_light: f32,
|
pub long_jump_speed_scale_light: f32,
|
||||||
pub long_jump_speec_scale_heavy: f32,
|
pub long_jump_speed_scale_heavy: f32,
|
||||||
pub max_lateral_force_light: f32,
|
pub max_lateral_force_light: f32,
|
||||||
pub max_lateral_force_heavy: f32,
|
pub max_lateral_force_heavy: f32,
|
||||||
pub max_damping_force_light: 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,
|
turn_acceleration_heavy: self.turn_acceleration_heavy,
|
||||||
legacy_turn_acceleration_light: self.legacy_turn_acceleration_light,
|
legacy_turn_acceleration_light: self.legacy_turn_acceleration_light,
|
||||||
legacy_turn_acceleration_heavy: self.legacy_turn_acceleration_heavy,
|
legacy_turn_acceleration_heavy: self.legacy_turn_acceleration_heavy,
|
||||||
long_jump_speec_scale_light: self.long_jump_speec_scale_light,
|
long_jump_speed_scale_light: self.long_jump_speed_scale_light,
|
||||||
long_jump_speec_scale_heavy: self.long_jump_speec_scale_heavy,
|
long_jump_speed_scale_heavy: self.long_jump_speed_scale_heavy,
|
||||||
max_lateral_force_light: self.max_lateral_force_light,
|
max_lateral_force_light: self.max_lateral_force_light,
|
||||||
max_lateral_force_heavy: self.max_lateral_force_heavy,
|
max_lateral_force_heavy: self.max_lateral_force_heavy,
|
||||||
max_damping_force_light: self.max_damping_force_light,
|
max_damping_force_light: self.max_damping_force_light,
|
||||||
|
|||||||
@@ -142,10 +142,10 @@ impl <C: Clone> super::User<C> for UserData {
|
|||||||
data: polariton::operation::Typed::Bytes(slot.robot_data.into()),
|
data: polariton::operation::Typed::Bytes(slot.robot_data.into()),
|
||||||
colour_data: polariton::operation::Typed::Bytes(slot.colour_data.into()),
|
colour_data: polariton::operation::Typed::Bytes(slot.colour_data.into()),
|
||||||
cube_count: polariton::operation::Typed::Int(slot.cubes as _),
|
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| {
|
movement_categories: polariton::operation::Typed::IntArr(slot.movement_categories.into_iter().map(|cat| {
|
||||||
let cat: crate::data::weapon_list::ItemCategory = cat.into();
|
let cat: crate::data::weapon_list::ItemCategory = cat.into();
|
||||||
cat as i32
|
cat.but_bigger()
|
||||||
}).collect::<Vec<_>>().into()),
|
}).collect::<Vec<_>>().into()),
|
||||||
control_type: polariton::operation::Typed::Int(control_ty as _),
|
control_type: polariton::operation::Typed::Int(control_ty as _),
|
||||||
control_options: control_options.as_transmissible(),
|
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.robot_data = vehicle.robot_data;
|
||||||
existing_data.colour_data = vehicle.colour_data;
|
existing_data.colour_data = vehicle.colour_data;
|
||||||
log::debug!("weapon order: {:?}", vehicle.weapon_order);
|
log::debug!("weapon order: {:?}", vehicle.weapon_order);
|
||||||
|
existing_data.weapon_order = vehicle.weapon_order;
|
||||||
self.save_garage(&existing_data).map_err(|e| {
|
self.save_garage(&existing_data).map_err(|e| {
|
||||||
log::error!("Failed to save vehicle {}: {}", id, e);
|
log::error!("Failed to save vehicle {}: {}", id, e);
|
||||||
DATABASE_ERR
|
DATABASE_ERR
|
||||||
})?;
|
})?;
|
||||||
Ok(())
|
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)]
|
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||||
|
|||||||
@@ -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, },
|
control_options: crate::persist::GarageControls { vertical_strafing: false, sideways_driving: false, tracks_turn_on_spot: false, },
|
||||||
mastery_level: 1,
|
mastery_level: 1,
|
||||||
bay_skin_id: "RC_MothershipSkin_Neptune_01".to_owned(), // TODO get the rest of the names
|
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],
|
robot_data: vec![0; 4],
|
||||||
colour_data: vec![0; 4],
|
colour_data: vec![0; 4],
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,3 +24,11 @@ fn __must_impl<T: UserProvider<()>>() {}
|
|||||||
fn __test_impl() {
|
fn __test_impl() {
|
||||||
__must_impl::<UserImpl>();
|
__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
|
||||||
|
}
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ pub trait User<C> {
|
|||||||
fn all_slots_by_id(&self) -> UserSlots<C>;
|
fn all_slots_by_id(&self) -> UserSlots<C>;
|
||||||
fn slot_by_id(&self, id: i32) -> Result<UserSlotData<C>, i16>;
|
fn slot_by_id(&self, id: i32) -> Result<UserSlotData<C>, i16>;
|
||||||
fn save_slot(&self, vehicle: VehicleData) -> Result<(), i16>;
|
fn save_slot(&self, vehicle: VehicleData) -> Result<(), i16>;
|
||||||
|
fn signup_date(&self) -> i64;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct UserSlots<C> {
|
pub struct UserSlots<C> {
|
||||||
|
|||||||
@@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
import sys
|
import sys
|
||||||
import json
|
import json
|
||||||
|
import argparse
|
||||||
|
import re
|
||||||
|
|
||||||
# weapon required data
|
# weapon required data
|
||||||
WEAPONS = {
|
WEAPONS = {
|
||||||
@@ -203,6 +205,16 @@ def guess_type(category: str) -> str:
|
|||||||
else:
|
else:
|
||||||
return "NotAFunctionalItem"
|
return "NotAFunctionalItem"
|
||||||
|
|
||||||
|
TIERS = [
|
||||||
|
"NoTier",
|
||||||
|
"T0",
|
||||||
|
"T1",
|
||||||
|
"T2",
|
||||||
|
"T3",
|
||||||
|
"T4",
|
||||||
|
"T5",
|
||||||
|
]
|
||||||
|
|
||||||
def guess_tier(name: str, sprite: str) -> str:
|
def guess_tier(name: str, sprite: str) -> str:
|
||||||
if guess_category(name, sprite) == "NotAFunctionalItem" and "medium" in name.lower(): # Medium cube variants
|
if guess_category(name, sprite) == "NotAFunctionalItem" and "medium" in name.lower(): # Medium cube variants
|
||||||
return "NoTier"
|
return "NoTier"
|
||||||
@@ -288,19 +300,134 @@ def is_variant_guess(name: str, sprite: str) -> bool:
|
|||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def main():
|
FIELD_NAME_EXCEPTIONS = {
|
||||||
print(sys.argv)
|
"verticalTopSpeed": "max_vertical_velocity",
|
||||||
filename_in = sys.argv[1]
|
}
|
||||||
with open(filename_in) as f:
|
|
||||||
|
def rename_field(original: str) -> str:
|
||||||
|
if original in FIELD_NAME_EXCEPTIONS:
|
||||||
|
return FIELD_NAME_EXCEPTIONS[original]
|
||||||
|
else:
|
||||||
|
return camel_to_snake_case(original)
|
||||||
|
|
||||||
|
SEEN_MOVEMENTS = {}
|
||||||
|
|
||||||
|
SEEN_WEAPONS = {}
|
||||||
|
|
||||||
|
EXCLUDED_FIELDS = [
|
||||||
|
"T0",
|
||||||
|
"T1",
|
||||||
|
"T2",
|
||||||
|
"T3",
|
||||||
|
"T4",
|
||||||
|
"T5",
|
||||||
|
]
|
||||||
|
|
||||||
|
def apply_entry_overrides(entry: dict, cubes_data: dict, weapons_data: dict, movement_data: dict):
|
||||||
|
if cubes_data is not None:
|
||||||
|
if entry["hexId"] in cubes_data:
|
||||||
|
cube_data = cubes_data[entry["hexId"]]
|
||||||
|
entry["info"]["description"] = cube_data["Description"]
|
||||||
|
entry["info"]["health"] = cube_data["health"]
|
||||||
|
entry["info"]["cpu"] = cube_data["cpuRating"]
|
||||||
|
entry["info"]["visibility"] = cube_data["buildVisibility"]
|
||||||
|
entry["info"]["ranking"] = cube_data["robotRanking"]
|
||||||
|
if "ItemSize" in cube_data:
|
||||||
|
entry["info"]["size"] = cube_data["ItemSize"]
|
||||||
|
if "ItemType" in cube_data:
|
||||||
|
entry["info"]["type"] = cube_data["ItemType"]
|
||||||
|
if "ItemCategory" in cube_data:
|
||||||
|
entry["info"]["category"] = cube_data["ItemCategory"]
|
||||||
|
if "PlacementFaces" in cube_data:
|
||||||
|
entry["info"]["placements"] = cube_data["PlacementFaces"]
|
||||||
|
if movement_data is not None and not entry["isVariant"]:
|
||||||
|
if entry["info"]["category"] in movement_data["Movements"]:
|
||||||
|
if entry["info"]["size"] in movement_data["Movements"][entry["info"]["category"]]:
|
||||||
|
if entry["info"]["category"] not in SEEN_MOVEMENTS:
|
||||||
|
SEEN_MOVEMENTS[entry["info"]["category"]] = dict()
|
||||||
|
SEEN_MOVEMENTS[entry["info"]["category"]][entry["info"]["size"]] = True
|
||||||
|
specific_data = movement_data["Movements"][entry["info"]["category"]][entry["info"]["size"]]
|
||||||
|
if "movement" not in entry:
|
||||||
|
entry["movement"] = dict()
|
||||||
|
for (key, val) in specific_data.items():
|
||||||
|
entry["movement"][rename_field(key)] = specific_data[key]
|
||||||
|
entry["movement"]["movement_enum_variant"] = entry["info"]["category"]
|
||||||
|
if weapons_data is not None and not entry["isVariant"]:
|
||||||
|
weapon_key = entry["info"]["size"] + "_" + entry["info"]["category"]
|
||||||
|
if weapon_key in weapons_data:
|
||||||
|
if weapon_key in SEEN_WEAPONS:
|
||||||
|
print("WARN: Already seen weapon key", weapon_key)
|
||||||
|
SEEN_WEAPONS[weapon_key] = True
|
||||||
|
if "weapon" not in entry:
|
||||||
|
entry["weapon"] = dict()
|
||||||
|
for (key, val) in weapons_data[weapon_key].items():
|
||||||
|
entry["weapon"][rename_field(key)] = val
|
||||||
|
|
||||||
|
def apply_global_overrides(conf: dict, cubes_data: dict, weapons_data: dict, movement_data: dict):
|
||||||
|
if movement_data is not None:
|
||||||
|
if "movement" not in conf:
|
||||||
|
conf["movement"] = dict()
|
||||||
|
for (category, cat_setting) in movement_data["Movements"].items():
|
||||||
|
if category not in conf["movement"]:
|
||||||
|
conf["movement"][category] = dict()
|
||||||
|
for (field, setting) in cat_setting.items():
|
||||||
|
if field not in EXCLUDED_FIELDS:
|
||||||
|
conf["movement"][category][rename_field(field)] = setting
|
||||||
|
conf["movement"][category]["movement_enum_variant"] = category
|
||||||
|
|
||||||
|
def load_or_none(file_json):
|
||||||
|
if file_json is None:
|
||||||
|
return None
|
||||||
|
else:
|
||||||
|
with open(file_json) as f:
|
||||||
|
return json.load(f)
|
||||||
|
|
||||||
|
CAMEL_TO_SNAKE_PATTERN = re.compile(r'(?<!^)(?=[A-Z])')
|
||||||
|
|
||||||
|
def camel_to_snake_case(s: str) -> str:
|
||||||
|
return CAMEL_TO_SNAKE_PATTERN.sub('_', s).lower()
|
||||||
|
|
||||||
|
def main(asset_in, cubes=None, weapons=None, movement=None):
|
||||||
|
cubes_data = load_or_none(cubes)
|
||||||
|
weapons_data = load_or_none(weapons)
|
||||||
|
movement_data = load_or_none(movement)
|
||||||
|
with open(asset_in) as f:
|
||||||
cubes_asset = json.load(f)
|
cubes_asset = json.load(f)
|
||||||
|
|
||||||
name = cubes_asset["0 MonoBehaviour Base"]["1 string m_Name"]
|
name = cubes_asset["0 MonoBehaviour Base"]["1 string m_Name"]
|
||||||
print(f"found name (expected to be empty): `{name}`")
|
print(f"found name (expected to be empty): `{name}`")
|
||||||
cubes = cubes_asset["0 MonoBehaviour Base"]["0 CubeTypeData cubeTypes"]["0 Array Array"]
|
cubes = cubes_asset["0 MonoBehaviour Base"]["0 CubeTypeData cubeTypes"]["0 Array Array"]
|
||||||
print(f"found {len(cubes)} cubes to process")
|
print(f"found {len(cubes)} cubes to process")
|
||||||
cubes_out = {
|
conf_out = {
|
||||||
"cubes": dict(),
|
"cubes": dict(),
|
||||||
"movement": dict(),
|
"movement": dict(),
|
||||||
"lerp_value": 10.0,
|
"lerp_value": 0.1,
|
||||||
|
"battle": {
|
||||||
|
"regen": {
|
||||||
|
"wait_for_heal_s": 5.0,
|
||||||
|
"wait_full_heal_s": 5.0,
|
||||||
|
"sound_start_s": 2.5,
|
||||||
|
"auto_heal": True,
|
||||||
|
},
|
||||||
|
"votes": {
|
||||||
|
"BestPlayed": [
|
||||||
|
{
|
||||||
|
"name": "Best Played",
|
||||||
|
"localised_name": "strBestPlayed",
|
||||||
|
"color": "0000ff",
|
||||||
|
"votes_required": 1,
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"BestLooking": [
|
||||||
|
{
|
||||||
|
"name": "Best Looking",
|
||||||
|
"localised_name": "strBestLooking",
|
||||||
|
"color": "ff0000",
|
||||||
|
"votes_required": 2,
|
||||||
|
}
|
||||||
|
],
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
last_tech_tree_id = 0
|
last_tech_tree_id = 0
|
||||||
tech_tree_index = 0
|
tech_tree_index = 0
|
||||||
@@ -346,6 +473,7 @@ def main():
|
|||||||
"nameStrKey": cube["1 string nameStrKey"],
|
"nameStrKey": cube["1 string nameStrKey"],
|
||||||
"mirrorCubeId": cube["0 PersistentCubeData cubeData"]["1 string mirrorCubeId"],
|
"mirrorCubeId": cube["0 PersistentCubeData cubeData"]["1 string mirrorCubeId"],
|
||||||
"hexId": str(cube["1 string itemCode"]),
|
"hexId": str(cube["1 string itemCode"]),
|
||||||
|
"isVariant": is_variant_guess(cube["1 string nameStrKey"], cube["1 string spriteName"]),
|
||||||
}
|
}
|
||||||
if "protonium" in name.lower():
|
if "protonium" in name.lower():
|
||||||
new_entry["info"]["protonium"] = True
|
new_entry["info"]["protonium"] = True
|
||||||
@@ -364,7 +492,7 @@ def main():
|
|||||||
else:
|
else:
|
||||||
new_entry["info"]["description"] += " (" + str(cube["0 unsigned int itemCodeValue"]) + "_10|" + str(cube["1 string itemCode"]) + "_16)"
|
new_entry["info"]["description"] += " (" + str(cube["0 unsigned int itemCodeValue"]) + "_10|" + str(cube["1 string itemCode"]) + "_16)"
|
||||||
|
|
||||||
is_original = not is_variant_guess(cube["1 string nameStrKey"], cube["1 string spriteName"])
|
is_original = not new_entry["isVariant"]
|
||||||
# weapons
|
# weapons
|
||||||
if new_entry["info"]["type"] == "Weapon":
|
if new_entry["info"]["type"] == "Weapon":
|
||||||
if is_original and "module" not in new_entry["info"]["category"].lower(): # ignore variants and modules
|
if is_original and "module" not in new_entry["info"]["category"].lower(): # ignore variants and modules
|
||||||
@@ -410,11 +538,36 @@ def main():
|
|||||||
}
|
}
|
||||||
tech_tree_specials_index += 1
|
tech_tree_specials_index += 1
|
||||||
|
|
||||||
|
# overrides
|
||||||
|
apply_entry_overrides(new_entry, cubes_data, weapons_data, movement_data)
|
||||||
|
|
||||||
print(f"processed cube {i} into {new_entry}")
|
print(f"processed cube {i} into {new_entry}")
|
||||||
cubes_out["cubes"][new_key] = new_entry
|
conf_out["cubes"][new_key] = new_entry
|
||||||
with open("../assets/robocraft/cubes.json", "w") as f:
|
# more overrides
|
||||||
json.dump(cubes_out, f, indent=4)
|
apply_global_overrides(conf_out, cubes_data, weapons_data, movement_data)
|
||||||
|
with open("../assets/robocraft/config.json", "w") as f:
|
||||||
|
json.dump(conf_out, f, indent=4)
|
||||||
print(f"processed {len(cubes)} cubes")
|
print(f"processed {len(cubes)} cubes")
|
||||||
|
if movement_data is not None:
|
||||||
|
for category in CATEGORIES[1:13]:
|
||||||
|
if category not in SEEN_MOVEMENTS:
|
||||||
|
print("Missed movement category", category)
|
||||||
|
else:
|
||||||
|
if len(SEEN_MOVEMENTS[category]) != len(TIERS) - 1:
|
||||||
|
print("Only found", len(SEEN_MOVEMENTS[category]), "of", len(TIERS) - 1, "tiers for movement category", category)
|
||||||
|
'''for tier in TIERS[1:]:
|
||||||
|
if tier not in SEEN_MOVEMENTS[category] or SEEN_MOVEMENTS[category][tier] == False:
|
||||||
|
print("Missed movement tier", tier, "in category", category)'''
|
||||||
|
if weapons_data is not None:
|
||||||
|
if len(weapons_data) != len(SEEN_WEAPONS):
|
||||||
|
print("Only found", len(SEEN_WEAPONS), "of", len(weapons_data), "weapon entries in reference")
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
main()
|
parser = argparse.ArgumentParser()
|
||||||
|
parser.add_argument("asset_json")
|
||||||
|
parser.add_argument("--cubes")
|
||||||
|
parser.add_argument("--weapons")
|
||||||
|
parser.add_argument("--movement")
|
||||||
|
args = parser.parse_args()
|
||||||
|
main(args.asset_json, cubes=args.cubes, weapons=args.weapons, movement=args.movement)
|
||||||
|
|||||||
Reference in New Issue
Block a user