diff --git a/README.md b/README.md index f01909c..5c7c58b 100644 --- a/README.md +++ b/README.md @@ -12,17 +12,14 @@ To get CardLife to use these servers, replace the `ServerConfig.json` file in th To get Robocraft to use these servers, place [this servenvmulti.config](assets/robocraft/serenvmulti.config) file in the game files. - - -You may also need to add the following to your OS's `hosts` file: -``` -127.0.0.1 robocraftstaticdata.s3.amazonaws.com -``` - -The `hosts` file can be found at `/etc/hosts` on Linux and `C:\Windows\system32\drivers\etc\hosts` on Windows. Usually this requires elevated permissions (root/admin) to edit. - // TODO Don't expect people to run these servers on their own computer ## Privacy No data is collected or logged, except in dev mode. Some personal identifiers are sent but only exist ephemerally. + +## Development + +### Robocraft + +Run all of the servers using their respective `run_debug.sh` scripts and use the `dev` profile in `servenvmulti.config` to point the game to your local dev servers. diff --git a/rc_chat_room/src/data/channel.rs b/rc_chat_room/src/data/channel.rs new file mode 100644 index 0000000..0a1a27b --- /dev/null +++ b/rc_chat_room/src/data/channel.rs @@ -0,0 +1,68 @@ +use polariton::operation::{Typed, Arr}; + +pub struct ChatChannelInfo { + pub channel_name: String, + pub members: Vec, + pub channel_ty: ChatChannelType, +} + +impl ChatChannelInfo { + pub fn as_transmissible(&self) -> Typed { + Typed::HashMap(vec![ + (Typed::Str("channelName".into()), Typed::Str(self.channel_name.clone().into())), + (Typed::Str("members".into()), Typed::Arr(Arr { + ty: 104, // hashtable + items: self.members.iter().map(|x| x.as_transmissible()).collect(), + })), + (Typed::Str("channelType".into()), Typed::Int(self.channel_ty as _)), + ].into()) + } +} + +pub struct ChatChannelMember { + pub name: String, + pub use_custom_avatar: bool, + pub state: ChatPlayerState, + pub custom_avatar: Vec, // always PNG? + pub avatar_id: i32, +} + +impl ChatChannelMember { + pub fn as_transmissible(&self) -> Typed { + Typed::HashMap(vec![ + (Typed::Str("name".into()), Typed::Str(self.name.clone().into())), + (Typed::Str("useCustomAvatar".into()), Typed::Bool(self.use_custom_avatar.into())), + (Typed::Str("state".into()), Typed::Int(self.state as _)), + if self.use_custom_avatar { + (Typed::Str("customAvatar".into()), Typed::Bytes(self.custom_avatar.clone().into())) + } else { + (Typed::Str("avatarId".into()), Typed::Int(self.avatar_id)) + }, + ].into()) + } +} + +#[allow(dead_code)] +#[repr(u8)] +#[derive(Copy, Clone)] +pub enum ChatChannelType { + None = 0, + Public = 1, + Battle = 2, + BattleTeam = 3, + Platoon = 4, + Custom = 5, + Clan = 6, + Private = 7, + CustomGame = 8, +} + +#[allow(dead_code)] +#[repr(u8)] +#[derive(Copy, Clone)] +pub enum ChatPlayerState { + Idk0 = 0, + Idk1 = 1, + Idk2 = 2, + // FIXME +} diff --git a/rc_chat_room/src/data/mod.rs b/rc_chat_room/src/data/mod.rs index e69de29..ff02972 100644 --- a/rc_chat_room/src/data/mod.rs +++ b/rc_chat_room/src/data/mod.rs @@ -0,0 +1 @@ +pub mod channel; diff --git a/rc_chat_room/src/operations/all_joined_channels.rs b/rc_chat_room/src/operations/all_joined_channels.rs new file mode 100644 index 0000000..f4a04e7 --- /dev/null +++ b/rc_chat_room/src/operations/all_joined_channels.rs @@ -0,0 +1,58 @@ +use polariton_server::operations::SimpleFunc; +use polariton::operation::{ParameterTable, Typed, Arr}; + +use crate::data::channel::*; + +const PARAM_KEY: u8 = 18; + +pub(super) fn all_channels_provider() -> SimpleFunc<11, crate::UserTy, impl (Fn(ParameterTable, &crate::UserTy) -> Result) + Sync + Sync> { + SimpleFunc::new(|params, _| { + let mut params = params.to_dict(); + params.insert(PARAM_KEY, Typed::Arr(Arr { + ty: 104, // hashtable + items: vec![ + ChatChannelInfo { + channel_name: "RE_public_channel0".to_owned(), + members: vec![ + ChatChannelMember { + name: "RE_chat0_username0".to_owned(), + use_custom_avatar: false, + state: ChatPlayerState::Idk1, + custom_avatar: Vec::default(), + avatar_id: 2, + }, + ChatChannelMember { + name: "RE_chat0_username1".to_owned(), + use_custom_avatar: false, + state: ChatPlayerState::Idk2, + custom_avatar: Vec::default(), + avatar_id: 3, + }, + ], + channel_ty: ChatChannelType::Public, + }.as_transmissible(), + ChatChannelInfo { + channel_name: "RE_custom_channel1".to_owned(), + members: vec![ + ChatChannelMember { + name: "RE_chat1_username0".to_owned(), + use_custom_avatar: false, + state: ChatPlayerState::Idk0, + custom_avatar: Vec::default(), + avatar_id: 2, + }, + ChatChannelMember { + name: "RE_chat1_username1".to_owned(), + use_custom_avatar: false, + state: ChatPlayerState::Idk1, + custom_avatar: Vec::default(), + avatar_id: 3, + }, + ], + channel_ty: ChatChannelType::Custom, + }.as_transmissible(), + ], + })); + Ok(params.into()) + }) +} diff --git a/rc_chat_room/src/operations/mod.rs b/rc_chat_room/src/operations/mod.rs index 08557ef..294899e 100644 --- a/rc_chat_room/src/operations/mod.rs +++ b/rc_chat_room/src/operations/mod.rs @@ -1,6 +1,7 @@ mod more_auth; mod chat_ignores; mod pending_sanctions; +mod all_joined_channels; use polariton_server::operations::OperationsHandler; @@ -9,5 +10,6 @@ pub fn handler() -> OperationsHandler { .without_state(more_auth::MoreLobbyAuth) .without_state(chat_ignores::ignores_provider()) .without_state(pending_sanctions::pending_sanctions_checker()) + .without_state(all_joined_channels::all_channels_provider()) //.without_state(polariton_server::operations::Ack::<00000, _>::default()) } diff --git a/rc_services_room/src/data/custom_games.rs b/rc_services_room/src/data/custom_games.rs index 2a79437..b333ff0 100644 --- a/rc_services_room/src/data/custom_games.rs +++ b/rc_services_room/src/data/custom_games.rs @@ -1,6 +1,7 @@ #![allow(dead_code)] #[repr(u8)] +#[derive(Copy, Clone)] pub enum GameMode { BattleArena = 0, SuddenDeath = 1, @@ -26,8 +27,16 @@ impl GameMode { } #[repr(u8)] +#[derive(Copy, Clone)] pub enum MapVisibility { Good = 0, Poor = 1, Bad = 2, // VeryPoor } + +#[repr(u8)] +#[derive(Copy, Clone)] +pub enum CustomGameInviteCode { + NoInvite = 0, + PendingInvite = 1, +} diff --git a/rc_services_room/src/data/garage_bay.rs b/rc_services_room/src/data/garage_bay.rs index a457c92..42406ef 100644 --- a/rc_services_room/src/data/garage_bay.rs +++ b/rc_services_room/src/data/garage_bay.rs @@ -1,45 +1,13 @@ use polariton::operation::{Typed, Arr}; -#[allow(dead_code)] -#[derive(Copy, Clone)] -pub enum MovementCategory { - 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, -} +use super::weapon_list::ItemCategory; pub struct GarageSlotInfo { pub name: String, pub cubes: u32, pub crf_id: u32, // 0 means not uploaded pub was_rated: bool, // ignored when not on CRF - pub movement_categories: Vec, + pub movement_categories: Vec, pub uuid: (u32, u32), pub thumbnail_version: u32, pub total_robot_cpu: u32, @@ -76,14 +44,7 @@ impl GarageSlotInfo { (Typed::Str("tutorialRobot".into()), Typed::Bool(self.tutorial_robot.into())), (Typed::Str("starterRobotIndex".into()), Typed::Int(self.starter_robot_index)), (Typed::Str("controlType".into()), Typed::Int(self.control_type as i32)), - (Typed::Str("controlOptions".into()), Typed::Arr(Arr { - ty: 111, // bool - items: vec![ - Typed::Bool(self.control_options.vertical_strafing.into()), - Typed::Bool(self.control_options.sideways_driving.into()), - Typed::Bool(self.control_options.tracks_turn_on_spot.into()), - ], - })), + (Typed::Str("controlOptions".into()), self.control_options.as_transmissible()), (Typed::Str("masteryLevel".into()), Typed::Int(self.mastery_level)), (Typed::Str("baySkinId".into()), Typed::Str(self.bay_skin_id.clone().into())), (Typed::Str("weaponOrder".into()), Typed::Arr(Arr { @@ -109,4 +70,17 @@ pub struct ControlOptions { pub tracks_turn_on_spot: bool, } +impl ControlOptions { + pub fn as_transmissible(&self) -> Typed { + Typed::Arr(Arr { + ty: 111, // bool + items: vec![ + Typed::Bool(self.vertical_strafing.into()), + Typed::Bool(self.sideways_driving.into()), + Typed::Bool(self.tracks_turn_on_spot.into()), + ], + }) + } +} + diff --git a/rc_services_room/src/data/item_shop_bundle.rs b/rc_services_room/src/data/item_shop_bundle.rs index c267c34..764042b 100644 --- a/rc_services_room/src/data/item_shop_bundle.rs +++ b/rc_services_room/src/data/item_shop_bundle.rs @@ -30,21 +30,21 @@ impl ItemShopBundle { fn dump(&self, writer: &mut dyn Write) -> std::io::Result { let sku_bytes = self.sku.as_bytes(); - let mut total_len = writer.write(&encode_7_bit_i32(sku_bytes.len() as i32))?; + let mut total_len = writer.write(&super::encode_7_bit_i32(sku_bytes.len() as i32))?; total_len += writer.write(sku_bytes)?; let bundle_name_key_bytes = self.bundle_name_key.as_bytes(); - total_len += writer.write(&encode_7_bit_i32(bundle_name_key_bytes.len() as i32))?; + total_len += writer.write(&super::encode_7_bit_i32(bundle_name_key_bytes.len() as i32))?; total_len += writer.write(bundle_name_key_bytes)?; let sprite_bytes = self.sprite.as_bytes(); - total_len += writer.write(&encode_7_bit_i32(sprite_bytes.len() as i32))?; + total_len += writer.write(&super::encode_7_bit_i32(sprite_bytes.len() as i32))?; total_len += writer.write(sprite_bytes)?; total_len += writer.write(&[self.is_sprite_full_size as u8])?; let currency_bytes = self.currency.as_str().as_bytes(); - total_len += writer.write(&encode_7_bit_i32(currency_bytes.len() as i32))?; + total_len += writer.write(&super::encode_7_bit_i32(currency_bytes.len() as i32))?; total_len += writer.write(currency_bytes)?; total_len += writer.write(&self.price.to_le_bytes())?; @@ -108,17 +108,3 @@ impl CurrencyType { } } } - -fn encode_7_bit_i32(mut src: i32) -> Vec { - let mut out = Vec::with_capacity(5); - while src != 0 { - let last_7 = (src & 0x7F) as u8; - src = src >> 7; - if src != 0 { - out.push(last_7 | 0x80); - } else { - out.push(last_7); - } - } - out -} diff --git a/rc_services_room/src/data/mod.rs b/rc_services_room/src/data/mod.rs index 4bb7a7a..422196f 100644 --- a/rc_services_room/src/data/mod.rs +++ b/rc_services_room/src/data/mod.rs @@ -16,3 +16,29 @@ pub mod garage_bay; pub mod custom_games; pub mod tech_tree; pub mod item_shop_bundle; +pub mod player_robopass_season; +pub mod weapon_upgrade; +pub mod player_rank; +pub mod robot_data; +pub mod quest; + +pub(self) fn encode_7_bit_i32(mut src: i32) -> Vec { + let mut out = Vec::with_capacity(5); + while src != 0 { + let last_7 = (src & 0x7F) as u8; + src = src >> 7; + if src != 0 { + out.push(last_7 | 0x80); + } else { + out.push(last_7); + } + } + out +} + +pub(self) fn write_str_for_binreader(s: &str, writer: &mut dyn std::io::Write) -> std::io::Result { + let s_bytes = s.as_bytes(); + let mut total_len = writer.write(&encode_7_bit_i32(s_bytes.len() as i32))?; + total_len += writer.write(s_bytes)?; + Ok(total_len) +} diff --git a/rc_services_room/src/data/player_rank.rs b/rc_services_room/src/data/player_rank.rs new file mode 100644 index 0000000..4899b6a --- /dev/null +++ b/rc_services_room/src/data/player_rank.rs @@ -0,0 +1,21 @@ +use polariton::operation::{Typed, Dict, Arr}; + +pub struct PlayerRankStaticInfo { + pub sub_rank_thresholds: Vec, +} + +impl PlayerRankStaticInfo { + pub fn as_transmissible(&self) -> Typed { + Typed::Dict(Dict { + key_ty: 115, // str + val_ty: 42, // obj + items: vec![ + (Typed::Str("subRankCount".into()), Typed::Int(self.sub_rank_thresholds.len() as i32)), + (Typed::Str("subRankThresholds".into()), Typed::Arr(Arr { + ty: 105, // int + items: self.sub_rank_thresholds.iter().map(|x| Typed::Int(*x)).collect(), + })), + ], + }) + } +} diff --git a/rc_services_room/src/data/player_robopass_season.rs b/rc_services_room/src/data/player_robopass_season.rs new file mode 100644 index 0000000..5e5ba63 --- /dev/null +++ b/rc_services_room/src/data/player_robopass_season.rs @@ -0,0 +1,25 @@ +use polariton::operation::{Typed, Dict}; + +pub struct PlayerRoboPassSeasonInfo { + pub delta_xp_to_show: i32, + pub grade: i32, + pub has_deluxe: bool, + pub progress_in_grade: f32, + pub xp_from_start: i32, +} + +impl PlayerRoboPassSeasonInfo { + pub fn as_transmissible(&self) -> Typed { + Typed::Dict(Dict { + key_ty: 115, // str + val_ty: 42, // obj + items: vec![ + (Typed::Str("deltaXpToShow".into()), Typed::Int(self.delta_xp_to_show)), + (Typed::Str("grade".into()), Typed::Int(self.grade)), + (Typed::Str("hasDeluxe".into()), Typed::Bool(self.has_deluxe.into())), + (Typed::Str("progressInGrade".into()), Typed::Float(self.progress_in_grade)), + (Typed::Str("xpFromSeasonStart".into()), Typed::Int(self.xp_from_start)), + ], + }) + } +} diff --git a/rc_services_room/src/data/quest.rs b/rc_services_room/src/data/quest.rs new file mode 100644 index 0000000..7676241 --- /dev/null +++ b/rc_services_room/src/data/quest.rs @@ -0,0 +1,66 @@ +#![allow(dead_code)] + +use std::io::Write; + +use polariton::operation::Typed; + +pub struct DailyQuestsInfo { + pub can_remove_quest: bool, + pub player_quests: Vec, + pub completed_quests: Vec, +} + +impl DailyQuestsInfo { + pub fn as_transmissible(&self) -> Typed { + let mut buf = Vec::new(); + let mut writer = std::io::Cursor::new(&mut buf); + self.dump(&mut writer).unwrap(); + Typed::Bytes(buf.into()) + } + + fn dump(&self, writer: &mut dyn Write) -> std::io::Result { + let mut total_len = writer.write(&[self.can_remove_quest as u8])?; + total_len += QuestInfo::dump_many(writer, &self.player_quests)?; + total_len += QuestInfo::dump_many(writer, &self.completed_quests)?; + Ok(total_len) + } + + +} + +pub struct QuestInfo { + pub id: String, + pub name: String, + pub description: String, + pub xp: i32, + pub premium_xp: i32, + pub robits: i32, + pub premium_robits: i32, + pub progress_count: i32, + pub target_count: i32, + pub seen: bool, +} + +impl QuestInfo { + fn dump(&self, writer: &mut dyn Write) -> std::io::Result { + let mut total_len = super::write_str_for_binreader(&self.id, writer)?; + total_len += super::write_str_for_binreader(&self.name, writer)?; + total_len += super::write_str_for_binreader(&self.description, writer)?; + total_len += writer.write(&self.xp.to_le_bytes())?; + total_len += writer.write(&self.premium_xp.to_le_bytes())?; + total_len += writer.write(&self.robits.to_le_bytes())?; + total_len += writer.write(&self.premium_robits.to_le_bytes())?; + total_len += writer.write(&self.progress_count.to_le_bytes())?; + total_len += writer.write(&self.target_count.to_le_bytes())?; + total_len += writer.write(&[self.seen as u8])?; + Ok(total_len) + } + + fn dump_many(writer: &mut dyn Write, quests: &[QuestInfo]) -> std::io::Result { + let mut total_len = writer.write(&(quests.len() as i16).to_le_bytes())?; + for quest in quests.iter() { + total_len += quest.dump(writer)?; + } + Ok(total_len) + } +} diff --git a/rc_services_room/src/data/robot_data.rs b/rc_services_room/src/data/robot_data.rs new file mode 100644 index 0000000..b85ff0a --- /dev/null +++ b/rc_services_room/src/data/robot_data.rs @@ -0,0 +1,23 @@ +use polariton::operation::Typed; + +pub struct PrebuiltRobotInfo { + //pub id: String, + pub name: String, + pub class: String, + pub category: String, + pub robot_data: Vec, + pub colour_data: Vec, +} + +impl PrebuiltRobotInfo { + pub fn as_transmissible(&self) -> Typed { + Typed::HashMap(vec![ + //(Typed::Str("[key]".into()), Typed::Str(self.id.clone().into())), + (Typed::Str("Name".into()), Typed::Str(self.name.clone().into())), + (Typed::Str("Class".into()), Typed::Str(self.class.clone().into())), + (Typed::Str("Category".into()), Typed::Str(self.category.clone().into())), + (Typed::Str("RobotData".into()), Typed::Bytes(self.robot_data.clone().into())), + (Typed::Str("ColourData".into()), Typed::Bytes(self.colour_data.clone().into())), + ].into()) + } +} diff --git a/rc_services_room/src/data/weapon_list.rs b/rc_services_room/src/data/weapon_list.rs index b166a10..b2d31c2 100644 --- a/rc_services_room/src/data/weapon_list.rs +++ b/rc_services_room/src/data/weapon_list.rs @@ -210,4 +210,8 @@ impl ItemCategory { ItemCategory::EnergyModule => "EnergyModule", } } + + pub fn but_bigger(&self) -> i32 { + (*self as i32) * 100_000 + } } diff --git a/rc_services_room/src/data/weapon_upgrade.rs b/rc_services_room/src/data/weapon_upgrade.rs new file mode 100644 index 0000000..a144956 --- /dev/null +++ b/rc_services_room/src/data/weapon_upgrade.rs @@ -0,0 +1,29 @@ +use polariton::operation::{Typed, Dict}; + +use super::{cube_list::ItemTier, weapon_list::ItemCategory}; + +pub struct WeaponUpgradeInfo { + pub tier: ItemTier, + pub type_: ItemCategory, + pub xp: f64, + pub rating: i32, + pub rank: i32, + pub power: i32, +} + +impl WeaponUpgradeInfo { + pub fn as_transmissible(&self) -> Typed { + Typed::Dict(Dict { + key_ty: 115, // str + val_ty: 42, // obj + items: vec![ + (Typed::Str("weaponSize".into()), Typed::Int(self.tier as _)), + (Typed::Str("weaponType".into()), Typed::Int(self.type_ as _)), + (Typed::Str("weaponXp".into()), Typed::Double(self.xp)), + (Typed::Str("weaponRating".into()), Typed::Int(self.rating)), + (Typed::Str("weaponRank".into()), Typed::Int(self.rank)), + (Typed::Str("weaponPower".into()), Typed::Int(self.power)), + ], + }) + } +} diff --git a/rc_services_room/src/operations/ab_test_group.rs b/rc_services_room/src/operations/ab_test_group.rs new file mode 100644 index 0000000..978c2e9 --- /dev/null +++ b/rc_services_room/src/operations/ab_test_group.rs @@ -0,0 +1,14 @@ +use polariton_server::operations::SimpleFunc; +use polariton::operation::{ParameterTable, Typed}; + +const TEST_PARAM_KEY: u8 = 166; +const TEST_GROUP_PARAM_KEY: u8 = 167; + +pub(super) fn test_group_provider() -> SimpleFunc<55, crate::UserTy, impl (Fn(ParameterTable, &crate::UserTy) -> Result) + Sync + Sync> { + SimpleFunc::new(|params, _| { + let mut params = params.to_dict(); + params.insert(TEST_PARAM_KEY, Typed::Str("RE_AB_test".into())); + params.insert(TEST_GROUP_PARAM_KEY, Typed::Str("RE_AB_test_group".into())); + Ok(params.into()) + }) +} diff --git a/rc_services_room/src/operations/all_customisations_info.rs b/rc_services_room/src/operations/all_customisations_info.rs index 1cbabcc..894d09a 100644 --- a/rc_services_room/src/operations/all_customisations_info.rs +++ b/rc_services_room/src/operations/all_customisations_info.rs @@ -19,9 +19,9 @@ pub(super) fn all_customisations_provider() -> SimpleFunc<216, crate::UserTy, im ty: 104, // hashtable items: vec![ CustomisationData { - id: "skin0".to_string(), - localised_name: "Default".to_string(), - skin_scene_name: "TODO_skin".to_string(), + id: "RC_MothershipSkin_Neptune_01".to_string(), + localised_name: "Neptune 01".to_string(), + skin_scene_name: "RC_MothershipSkin_Neptune_01".to_string(), simulation_prefab: "TODO_sim_prefab".to_string(), preview_image_name: "TODO_preview_img".to_string(), is_default: true, diff --git a/rc_services_room/src/operations/building_xp.rs b/rc_services_room/src/operations/building_xp.rs new file mode 100644 index 0000000..4d04ccd --- /dev/null +++ b/rc_services_room/src/operations/building_xp.rs @@ -0,0 +1,16 @@ +use polariton_server::operations::SimpleFunc; +use polariton::operation::{ParameterTable, Typed}; + +const PROGRESS_PARAM_KEY: u8 = 199; +const LEVEL_PARAM_KEY: u8 = 81; +const GAINED_XP_PARAM_KEY: u8 = 205; + +pub(super) fn building_xp_save_provider() -> SimpleFunc<170, crate::UserTy, impl (Fn(ParameterTable, &crate::UserTy) -> Result) + Sync + Sync> { + SimpleFunc::new(|params, _| { + let mut params = params.to_dict(); + params.insert(PROGRESS_PARAM_KEY, Typed::Float(1.0)); + params.insert(LEVEL_PARAM_KEY, Typed::Int(31337)); + params.insert(GAINED_XP_PARAM_KEY, Typed::Int(0)); + Ok(params.into()) + }) +} diff --git a/rc_services_room/src/operations/building_xp_config.rs b/rc_services_room/src/operations/building_xp_config.rs new file mode 100644 index 0000000..a5f4939 --- /dev/null +++ b/rc_services_room/src/operations/building_xp_config.rs @@ -0,0 +1,21 @@ +use polariton_server::operations::SimpleFunc; +use polariton::operation::{ParameterTable, Typed, Dict}; + +const PARAM_KEY: u8 = 79; + +pub(super) fn building_xp_config_provider() -> SimpleFunc<199, crate::UserTy, impl (Fn(ParameterTable, &crate::UserTy) -> Result) + Sync + Sync> { + SimpleFunc::new(|params, _| { + let mut params = params.to_dict(); + params.insert(PARAM_KEY, Typed::Dict(Dict { + key_ty: 115, // str + val_ty: 104, // hashtable + items: vec![ + (Typed::Str("BuildXPSettings".into()), Typed::HashMap(vec![ + (Typed::Str("buildModePeriodUserEarnXP".into()), Typed::Float(1.0)), // TODO what are the time units? + (Typed::Str("buildModePeriodUserInactivity".into()), Typed::Float(2.0)), + ].into())), + ], + })); + Ok(params.into()) + }) +} diff --git a/rc_services_room/src/operations/chat_settings.rs b/rc_services_room/src/operations/chat_settings.rs new file mode 100644 index 0000000..bf73a22 --- /dev/null +++ b/rc_services_room/src/operations/chat_settings.rs @@ -0,0 +1,14 @@ +use polariton_server::operations::SimpleFunc; +use polariton::operation::{ParameterTable, Typed}; + +const PARAM_KEY: u8 = 17; + +pub(super) fn chat_settings_provider() -> SimpleFunc<18, crate::UserTy, impl (Fn(ParameterTable, &crate::UserTy) -> Result) + Sync + Sync> { + SimpleFunc::new(|params, _| { + let mut params = params.to_dict(); + params.insert(PARAM_KEY, Typed::HashMap(vec![ + (Typed::Str("chatEnabled".into()), Typed::Bool(true.into())), + ].into())); + Ok(params.into()) + }) +} diff --git a/rc_services_room/src/operations/crf_limits.rs b/rc_services_room/src/operations/crf_limits.rs new file mode 100644 index 0000000..01ce1ec --- /dev/null +++ b/rc_services_room/src/operations/crf_limits.rs @@ -0,0 +1,15 @@ +use polariton_server::operations::SimpleFunc; +use polariton::operation::{ParameterTable, Typed}; + +const PARAM_KEY: u8 = 100; + +pub(super) fn robot_shop_submission_infos_provider() -> SimpleFunc<95, crate::UserTy, impl (Fn(ParameterTable, &crate::UserTy) -> Result) + Sync + Sync> { + SimpleFunc::new(|params, _| { + let mut params = params.to_dict(); + params.insert(PARAM_KEY, Typed::HashMap(vec![ + (Typed::Str("submissionCount".into()), Typed::Int(0)), + (Typed::Str("maxSubmissions".into()), Typed::Int(10)), + ].into())); + Ok(params.into()) + }) +} diff --git a/rc_services_room/src/operations/cube_awards.rs b/rc_services_room/src/operations/cube_awards.rs new file mode 100644 index 0000000..86d6301 --- /dev/null +++ b/rc_services_room/src/operations/cube_awards.rs @@ -0,0 +1,15 @@ +use polariton_server::operations::SimpleFunc; +use polariton::operation::{ParameterTable, Typed, Arr}; + +const PARAM_KEY: u8 = 216; + +pub(super) fn cube_awards_provider() -> SimpleFunc<206, crate::UserTy, impl (Fn(ParameterTable, &crate::UserTy) -> Result) + Sync + Sync> { + SimpleFunc::new(|params, _| { + let mut params = params.to_dict(); + params.insert(PARAM_KEY, Typed::Arr(Arr { + ty: 115, // str + items: Vec::default(), + })); + Ok(params.into()) + }) +} diff --git a/rc_services_room/src/operations/cube_list.rs b/rc_services_room/src/operations/cube_list.rs index f6797af..21adef0 100644 --- a/rc_services_room/src/operations/cube_list.rs +++ b/rc_services_room/src/operations/cube_list.rs @@ -6,7 +6,7 @@ use polariton::operation::{ParameterTable, Typed, Dict}; 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) + Sync + Sync> { SimpleFunc::new(|params, _| { @@ -16,7 +16,7 @@ pub(super) fn cube_list_provider() -> SimpleFunc<2, crate::UserTy, impl (Fn(Para val_ty: 104, // hashtable items: vec![ //(u32 in base16 aka hex, hashtable) - (Typed::Str("DEADBEEF".into()), CubeInfo { + CubeInfo { cpu: 1, health: 1, health_boost: 1.0, @@ -36,7 +36,7 @@ pub(super) fn cube_list_provider() -> SimpleFunc<2, crate::UserTy, impl (Fn(Para cosmetic: false, variant_of: "0".to_string(), ignore_in_weapon_list: true, - }.as_transmissible()), + }.as_transmissible_key_val(DEFAULT_CUBE_ID), CubeInfo { cpu: 1, health: 1, diff --git a/rc_services_room/src/operations/custom_games_invite.rs b/rc_services_room/src/operations/custom_games_invite.rs new file mode 100644 index 0000000..4b40e1a --- /dev/null +++ b/rc_services_room/src/operations/custom_games_invite.rs @@ -0,0 +1,15 @@ +use polariton_server::operations::SimpleFunc; +use polariton::operation::{ParameterTable, Typed}; + +use crate::data::custom_games::*; + +const PARAM_KEY: u8 = 168; +//const INVITE_PARAM_KEY: u8 = 189; // hashtable (refer to C# CheckIfHasBeenInvitedToCustomGameSessionRequest) + +pub(super) fn pending_invite_provider() -> SimpleFunc<0, crate::UserTy, impl (Fn(ParameterTable, &crate::UserTy) -> Result) + Sync + Sync> { + SimpleFunc::new(|params, _| { + let mut params = params.to_dict(); + params.insert(PARAM_KEY, Typed::Int(CustomGameInviteCode::NoInvite as _)); + Ok(params.into()) + }) +} diff --git a/rc_services_room/src/operations/custom_games_team.rs b/rc_services_room/src/operations/custom_games_team.rs new file mode 100644 index 0000000..8e183b3 --- /dev/null +++ b/rc_services_room/src/operations/custom_games_team.rs @@ -0,0 +1,25 @@ +use polariton_server::operations::SimpleFunc; +use polariton::operation::{ParameterTable, Typed, Dict}; + +use crate::data::custom_games::*; + +const PARAM_KEY: u8 = 168; + +pub(super) fn team_setup_provider() -> SimpleFunc<162, crate::UserTy, impl (Fn(ParameterTable, &crate::UserTy) -> Result) + Sync + Sync> { + SimpleFunc::new(|params, _| { + let mut params = params.to_dict(); + params.insert(PARAM_KEY, Typed::Dict(Dict { + key_ty: 115, // str + val_ty: 105, // int + items: vec![ + (Typed::Str(GameMode::BattleArena.as_str().into()), Typed::Int(10)), + (Typed::Str(GameMode::SuddenDeath.as_str().into()), Typed::Int(10)), + (Typed::Str(GameMode::Pit.as_str().into()), Typed::Int(10)), + (Typed::Str(GameMode::TestMode.as_str().into()), Typed::Int(10)), + (Typed::Str(GameMode::SinglePlayer.as_str().into()), Typed::Int(1)), + (Typed::Str(GameMode::TeamDeathmatch.as_str().into()), Typed::Int(10)), + (Typed::Str(GameMode::Campaign.as_str().into()), Typed::Int(6)), + ] })); + Ok(params.into()) + }) +} diff --git a/rc_services_room/src/operations/daily_quests.rs b/rc_services_room/src/operations/daily_quests.rs new file mode 100644 index 0000000..4367b81 --- /dev/null +++ b/rc_services_room/src/operations/daily_quests.rs @@ -0,0 +1,31 @@ +use polariton_server::operations::SimpleFunc; +use polariton::operation::ParameterTable; + +use crate::data::quest::*; + +const PARAM_KEY: u8 = 155; // int + +pub(super) fn player_daily_quests_provider() -> SimpleFunc<13, crate::UserTy, impl (Fn(ParameterTable, &crate::UserTy) -> Result) + Sync + Sync> { + SimpleFunc::new(|params, _| { + let mut params = params.to_dict(); + params.insert(PARAM_KEY, DailyQuestsInfo { + can_remove_quest: true, + player_quests: vec![ + QuestInfo { + id: "RE_quest_id0".to_owned(), + name: "RE_quest_name0".to_owned(), + description: "RE_quest_description0".to_owned(), + xp: 1_000, + premium_xp: 2_000, + robits: 1_000, + premium_robits: 1_000, + progress_count: 1, + target_count: 3, + seen: true, + } + ], + completed_quests: Vec::default(), + }.as_transmissible()); + Ok(params.into()) + }) +} diff --git a/rc_services_room/src/operations/garage_slots.rs b/rc_services_room/src/operations/garage_slots.rs index 6f1273b..8658ebc 100644 --- a/rc_services_room/src/operations/garage_slots.rs +++ b/rc_services_room/src/operations/garage_slots.rs @@ -2,6 +2,7 @@ use polariton_server::operations::SimpleFunc; use polariton::operation::{ParameterTable, Typed, Dict}; use crate::data::garage_bay::*; +use crate::data::weapon_list::ItemCategory; const SLOTS_PARAM_KEY: u8 = 44; const SELECTED_SLOT_PARAM_KEY: u8 = 43; @@ -15,11 +16,11 @@ pub(super) fn garage_slot_provider() -> SimpleFunc<40, crate::UserTy, impl (Fn(P val_ty: 104, // hashmap items: vec![ (Typed::Int(0), GarageSlotInfo { - name: "Reverse-engineer great success!".to_owned(), + name: "Reverse-engineer great success! slot_name".to_owned(), cubes: 1, crf_id: 0, was_rated: false, - movement_categories: vec![MovementCategory::Wheel], + movement_categories: vec![ItemCategory::Wheel], uuid: (2,4), thumbnail_version: 0, total_robot_cpu: 1, diff --git a/rc_services_room/src/operations/garage_upgrades.rs b/rc_services_room/src/operations/garage_upgrades.rs index 23ecba0..647de04 100644 --- a/rc_services_room/src/operations/garage_upgrades.rs +++ b/rc_services_room/src/operations/garage_upgrades.rs @@ -8,8 +8,8 @@ pub(super) fn garage_upgrades_provider() -> SimpleFunc<1, crate::UserTy, impl (F let mut params = params.to_dict(); params.insert(PARAM_KEY, Typed::HashMap(vec![ (Typed::Str("cpuIncreaseCost".into()), Typed::Dict(Dict { - key_ty: 110, // int - val_ty: 110, // int + key_ty: 105, // int + val_ty: 105, // int items: vec![ // (CPU limit, upgrade cost) (Typed::Int(100), Typed::Int(100)), diff --git a/rc_services_room/src/operations/last_completed_campaign.rs b/rc_services_room/src/operations/last_completed_campaign.rs new file mode 100644 index 0000000..cf3f0b3 --- /dev/null +++ b/rc_services_room/src/operations/last_completed_campaign.rs @@ -0,0 +1,14 @@ +use polariton_server::operations::SimpleFunc; +use polariton::operation::{ParameterTable, Typed}; + +// const CAMPAIGN_ID_PARAM_KEY: u8 = 22; // str +// const DIFFICULTY_PARAM_KEY: u8 = 22; // int +const AVAILABLE_PARAM_KEY: u8 = 89; // bool + +pub(super) fn completed_campaign_provider() -> SimpleFunc<77, crate::UserTy, impl (Fn(ParameterTable, &crate::UserTy) -> Result) + Sync + Sync> { + SimpleFunc::new(|params, _| { + let mut params = params.to_dict(); + params.insert(AVAILABLE_PARAM_KEY, Typed::Bool(false.into())); + Ok(params.into()) + }) +} diff --git a/rc_services_room/src/operations/league_limits.rs b/rc_services_room/src/operations/league_limits.rs new file mode 100644 index 0000000..862ee06 --- /dev/null +++ b/rc_services_room/src/operations/league_limits.rs @@ -0,0 +1,19 @@ +use polariton_server::operations::SimpleFunc; +use polariton::operation::{ParameterTable, Typed, Dict}; + +const PARAM_KEY: u8 = 1; + +pub(super) fn league_battle_parameters_provider() -> SimpleFunc<57, crate::UserTy, impl (Fn(ParameterTable, &crate::UserTy) -> Result) + Sync + Sync> { + SimpleFunc::new(|params, _| { + let mut params = params.to_dict(); + params.insert(PARAM_KEY, Typed::Dict(Dict { + key_ty: 115, //str + val_ty: 42, // obj + items: vec![ + (Typed::Str("playerLevelRequired".into()), Typed::Int(10)), + (Typed::Str("minCpu".into()), Typed::Int(100)), + ], + })); + Ok(params.into()) + }) +} diff --git a/rc_services_room/src/operations/machine.rs b/rc_services_room/src/operations/machine.rs new file mode 100644 index 0000000..8f9e3c2 --- /dev/null +++ b/rc_services_room/src/operations/machine.rs @@ -0,0 +1,33 @@ +use polariton_server::operations::SimpleFunc; +use polariton::operation::{ParameterTable, Typed}; + +use crate::data::weapon_list::ItemCategory; +use crate::data::garage_bay::*; + +const SLOT_PARAM_KEY: u8 = 45; // uint +const DATA_PARAM_KEY: u8 = 49; // byte arr +const CUBES_COUNT_PARAM_KEY: u8 = 51; // int +const WEAPON_ORDER_PARAM_KEY: u8 = 52; // int arr +const MOVEMENT_CATEGORIES_PARAM_KEY: u8 = 56; // int arr +const CONTROL_TYPE_PARAM_KEY: u8 = 59; // int +const CONTROL_OPTIONS_PARAM_KEY: u8 = 60; // bool arr +const MASTERY_LEVEL_PARAM_KEY: u8 = 18; // int + +pub(super) fn garage_machine_provider() -> SimpleFunc<43, crate::UserTy, impl (Fn(ParameterTable, &crate::UserTy) -> Result) + Sync + Sync> { + SimpleFunc::new(|params, _| { + let mut params = params.to_dict(); + if let Some(garage_slot) = params.get(&SLOT_PARAM_KEY) { + log::debug!("Got machine request for slot {:?}", garage_slot); + } else { + params.insert(SLOT_PARAM_KEY, Typed::Int(0)); + } + params.insert(DATA_PARAM_KEY, Typed::Bytes(vec![0u8, 0u8, 0u8, 0u8].into())); // first 4 bytes are i32 for length of rest of data + params.insert(CUBES_COUNT_PARAM_KEY, Typed::Int(1)); + params.insert(WEAPON_ORDER_PARAM_KEY, Typed::IntArr(vec![0].into())); + params.insert(MOVEMENT_CATEGORIES_PARAM_KEY, Typed::IntArr(vec![ItemCategory::Wheel.but_bigger()].into())); + params.insert(CONTROL_TYPE_PARAM_KEY, Typed::Int(ControlType::Camera as _)); + params.insert(CONTROL_OPTIONS_PARAM_KEY, ControlOptions { vertical_strafing: false, sideways_driving: false, tracks_turn_on_spot: false, }.as_transmissible()); + params.insert(MASTERY_LEVEL_PARAM_KEY, Typed::Int(0)); + Ok(params.into()) + }) +} diff --git a/rc_services_room/src/operations/machine_colour.rs b/rc_services_room/src/operations/machine_colour.rs new file mode 100644 index 0000000..ebc37a6 --- /dev/null +++ b/rc_services_room/src/operations/machine_colour.rs @@ -0,0 +1,19 @@ +use polariton_server::operations::SimpleFunc; +use polariton::operation::{ParameterTable, Typed}; + +// const USERNAME_PARAM_KEY: u8 = 30; // str +const SLOT_PARAM_KEY: u8 = 31; // int +const DATA_PARAM_KEY: u8 = 33; // byte arr + +pub(super) fn garage_machine_colour_provider() -> SimpleFunc<33, crate::UserTy, impl (Fn(ParameterTable, &crate::UserTy) -> Result) + Sync + Sync> { + SimpleFunc::new(|params, _| { + let mut params = params.to_dict(); + if let Some(garage_slot) = params.get(&SLOT_PARAM_KEY) { + log::debug!("Got machine colour request for slot {:?}", garage_slot); + } else { + params.insert(SLOT_PARAM_KEY, Typed::Int(0)); + } + params.insert(DATA_PARAM_KEY, Typed::Bytes(vec![0u8, 0u8, 0u8, 0u8].into())); // first 4 bytes are i32 for length of rest of data + Ok(params.into()) + }) +} diff --git a/rc_services_room/src/operations/mod.rs b/rc_services_room/src/operations/mod.rs index b540daf..073bf8a 100644 --- a/rc_services_room/src/operations/mod.rs +++ b/rc_services_room/src/operations/mod.rs @@ -43,6 +43,34 @@ mod game_event_params; mod garage_bay_uuid; mod tech_tree_data; mod item_shop_bundles; +mod robot_customisations; +mod player_data; +mod player_robopass; +mod weapon_upgrades; +mod player_rank; +mod ab_test_group; +mod league_limits; +mod crf_limits; +mod robot_mastery_settings; +mod player_started_purchase; +mod custom_games_team; +mod custom_games_invite; +mod chat_settings; +mod prebuilt_robots; +mod prebuilt_colours; +mod robopass_preview_items; +mod singleplayer_campaigns; +mod purchases; +mod building_xp_config; +mod weapon_rating_static; +mod weapon_xp_static; +mod machine; +mod machine_colour; +mod last_completed_campaign; +mod daily_quests; +mod cube_awards; +mod robot_sanction; +mod building_xp; use polariton_server::operations::OperationsHandler; @@ -95,5 +123,37 @@ pub fn handler() -> OperationsHandler { .without_state(garage_bay_uuid::garage_id_provider()) .without_state(tech_tree_data::tech_tree_layout_provider()) .without_state(item_shop_bundles::item_bundle_provider()) + .without_state(robot_customisations::bay_customisations_provider()) + .without_state(player_data::player_data_provider()) + .without_state(player_robopass::player_robopass_season_provider()) + .without_state(weapon_upgrades::weapons_upgrade_provider()) + .without_state(polariton_server::operations::Ack::<172, _>::default()) // custom game change robot tier (param 67 is tier) + .without_state(player_rank::rank_provider()) + .without_state(player_rank::rank_static_provider()) + .without_state(ab_test_group::test_group_provider()) + .without_state(league_limits::league_battle_parameters_provider()) + .without_state(crf_limits::robot_shop_submission_infos_provider()) + .without_state(robot_mastery_settings::robot_mastery_settings_provider()) + .without_state(player_started_purchase::started_purchase_provider()) + .without_state(custom_games_team::team_setup_provider()) + .without_state(polariton_server::operations::Ack::<152, _>::default()) // custom game player state changed (188 is desired state) + .without_state(custom_games_invite::pending_invite_provider()) + .without_state(chat_settings::chat_settings_provider()) + .without_state(prebuilt_robots::garage_robot_data_provider()) + .without_state(prebuilt_colours::garage_colour_combo_provider()) + .without_state(robopass_preview_items::robopass_preview_provider()) + .without_state(singleplayer_campaigns::singleplayer_campaigns_provider()) + .without_state(purchases::pending_purchases_provider()) + .without_state(building_xp_config::building_xp_config_provider()) + .without_state(weapon_rating_static::weapon_rating_provider()) + .without_state(weapon_xp_static::weapon_xp_provider()) + .without_state(machine::garage_machine_provider()) + .without_state(machine_colour::garage_machine_colour_provider()) + .without_state(last_completed_campaign::completed_campaign_provider()) + .without_state(daily_quests::player_daily_quests_provider()) + .without_state(tech_points::tech_points_awards_provider()) + .without_state(cube_awards::cube_awards_provider()) + .without_state(robot_sanction::robot_sanction_provider()) + .without_state(building_xp::building_xp_save_provider()) //.without_state(polariton_server::operations::Ack::<70, _>::default()) } diff --git a/rc_services_room/src/operations/player_data.rs b/rc_services_room/src/operations/player_data.rs new file mode 100644 index 0000000..f8c973b --- /dev/null +++ b/rc_services_room/src/operations/player_data.rs @@ -0,0 +1,38 @@ +use polariton_server::operations::SimpleFunc; +use polariton::operation::{ParameterTable, Typed, Arr}; + +use crate::data::{garage_bay::*, weapon_list::ItemCategory}; + +const GARAGE_SLOT_KEY: u8 = 45; +const NAME_KEY: u8 = 42; +const CRF_ID_KEY: u8 = 35; +const ROBOT_CPU_KEY: u8 = 177; +const CONTROL_TYPE_KEY: u8 = 59; +const CONTROL_OPTIONS_KEY: u8 = 60; +const WEAPON_ORDER_KEY: u8 = 52; +const ITEM_CATEGORY_KEY: u8 = 56; + +pub(super) fn player_data_provider() -> SimpleFunc<61, crate::UserTy, impl (Fn(ParameterTable, &crate::UserTy) -> Result) + Sync + Sync> { + SimpleFunc::new(|params, _| { + let mut params = params.to_dict(); + params.insert(GARAGE_SLOT_KEY, Typed::Int(0)); + params.insert(NAME_KEY, Typed::Str("Reverse-engineer great success!".into())); + params.insert(CRF_ID_KEY, Typed::Int(0)); + params.insert(ROBOT_CPU_KEY, Typed::Int(1)); + params.insert(CONTROL_TYPE_KEY, Typed::Int(ControlType::Camera as _)); + params.insert(CONTROL_OPTIONS_KEY, ControlOptions { vertical_strafing: false, sideways_driving: false, tracks_turn_on_spot: false, }.as_transmissible()); + params.insert(WEAPON_ORDER_KEY, Typed::Arr(Arr { + ty: 105, // int + items: vec![ + Typed::Int(0), + ], + })); + params.insert(ITEM_CATEGORY_KEY, Typed::Arr(Arr { + ty: 105, // int + items: vec![ + Typed::Int(ItemCategory::Wheel.but_bigger()), + ], + })); + Ok(params.into()) + }) +} diff --git a/rc_services_room/src/operations/player_rank.rs b/rc_services_room/src/operations/player_rank.rs new file mode 100644 index 0000000..2ee775c --- /dev/null +++ b/rc_services_room/src/operations/player_rank.rs @@ -0,0 +1,26 @@ +use polariton_server::operations::SimpleFunc; +use polariton::operation::{ParameterTable, Typed}; + +use crate::data::player_rank::*; + +const PARAM_KEY: u8 = 80; + +pub(super) fn rank_provider() -> SimpleFunc<80, crate::UserTy, impl (Fn(ParameterTable, &crate::UserTy) -> Result) + Sync + Sync> { + SimpleFunc::new(|params, _| { + let mut params = params.to_dict(); + params.insert(PARAM_KEY, Typed::Int(3)); + Ok(params.into()) + }) +} + +const STATIC_PARAM_KEY: u8 = 1; + +pub(super) fn rank_static_provider() -> SimpleFunc<126, crate::UserTy, impl (Fn(ParameterTable, &crate::UserTy) -> Result) + Sync + Sync> { + SimpleFunc::new(|params, _| { + let mut params = params.to_dict(); + params.insert(STATIC_PARAM_KEY, PlayerRankStaticInfo { + sub_rank_thresholds: vec![1, 2, 3, 4, 5], + }.as_transmissible()); + Ok(params.into()) + }) +} diff --git a/rc_services_room/src/operations/player_robopass.rs b/rc_services_room/src/operations/player_robopass.rs new file mode 100644 index 0000000..8371761 --- /dev/null +++ b/rc_services_room/src/operations/player_robopass.rs @@ -0,0 +1,20 @@ +use polariton_server::operations::SimpleFunc; +use polariton::operation::ParameterTable; + +use crate::data::player_robopass_season::*; + +const PARAM_KEY: u8 = 237; + +pub(super) fn player_robopass_season_provider() -> SimpleFunc<178, crate::UserTy, impl (Fn(ParameterTable, &crate::UserTy) -> Result) + Sync + Sync> { + SimpleFunc::new(|params, _| { + let mut params = params.to_dict(); + params.insert(PARAM_KEY, PlayerRoboPassSeasonInfo { + delta_xp_to_show: 42, + grade: 1, + has_deluxe: true, + progress_in_grade: 0.5, + xp_from_start: 12345, + }.as_transmissible()); + Ok(params.into()) + }) +} diff --git a/rc_services_room/src/operations/player_started_purchase.rs b/rc_services_room/src/operations/player_started_purchase.rs new file mode 100644 index 0000000..f8f8583 --- /dev/null +++ b/rc_services_room/src/operations/player_started_purchase.rs @@ -0,0 +1,12 @@ +use polariton_server::operations::SimpleFunc; +use polariton::operation::{ParameterTable, Typed}; + +const PARAM_KEY: u8 = 135; + +pub(super) fn started_purchase_provider() -> SimpleFunc<54, crate::UserTy, impl (Fn(ParameterTable, &crate::UserTy) -> Result) + Sync + Sync> { + SimpleFunc::new(|params, _| { + let mut params = params.to_dict(); + params.insert(PARAM_KEY, Typed::Bool(false.into())); + Ok(params.into()) + }) +} diff --git a/rc_services_room/src/operations/prebuilt_colours.rs b/rc_services_room/src/operations/prebuilt_colours.rs new file mode 100644 index 0000000..6e2808b --- /dev/null +++ b/rc_services_room/src/operations/prebuilt_colours.rs @@ -0,0 +1,12 @@ +use polariton_server::operations::SimpleFunc; +use polariton::operation::{ParameterTable, Typed}; + +const PARAM_KEY: u8 = 1; + +pub(super) fn garage_colour_combo_provider() -> SimpleFunc<37, crate::UserTy, impl (Fn(ParameterTable, &crate::UserTy) -> Result) + Sync + Sync> { + SimpleFunc::new(|params, _| { + let mut params = params.to_dict(); + params.insert(PARAM_KEY, Typed::Str("[[0,1,2,3]]".into())); // why tf is this a JSON in a string??? (list of lists of bytes) + Ok(params.into()) + }) +} diff --git a/rc_services_room/src/operations/prebuilt_robots.rs b/rc_services_room/src/operations/prebuilt_robots.rs new file mode 100644 index 0000000..87eb11d --- /dev/null +++ b/rc_services_room/src/operations/prebuilt_robots.rs @@ -0,0 +1,26 @@ +use polariton_server::operations::SimpleFunc; +use polariton::operation::{ParameterTable, Typed, Dict}; + +use crate::data::robot_data::*; + +const PARAM_KEY: u8 = 1; + +pub(super) fn garage_robot_data_provider() -> SimpleFunc<4, crate::UserTy, impl (Fn(ParameterTable, &crate::UserTy) -> Result) + Sync + Sync> { + SimpleFunc::new(|params, _| { + let mut params = params.to_dict(); + params.insert(PARAM_KEY, Typed::Dict(Dict { + key_ty: 115, // str + val_ty: 104, // hashmap + items: vec![ + (Typed::Str(format!("{}_{}", 12345, 54321).into()), PrebuiltRobotInfo { + name: "Reverse-engineer great success! prebuilt_name".to_owned(), + class: "RE_robot_class0".to_owned(), + category: "RE_robot_category0".to_owned(), + robot_data: vec![0u8, 0u8, 0u8, 0u8], // first 4 bytes are i32 for the cube count (we want it to be 0) + colour_data: vec![0u8, 0u8, 0u8, 0u8], + }.as_transmissible()), + ] + })); + Ok(params.into()) + }) +} diff --git a/rc_services_room/src/operations/purchases.rs b/rc_services_room/src/operations/purchases.rs new file mode 100644 index 0000000..eb6812a --- /dev/null +++ b/rc_services_room/src/operations/purchases.rs @@ -0,0 +1,17 @@ +use polariton_server::operations::SimpleFunc; +use polariton::operation::{ParameterTable, Typed, Dict}; + +const PARAM_KEY: u8 = 88; + +pub(super) fn pending_purchases_provider() -> SimpleFunc<81, crate::UserTy, impl (Fn(ParameterTable, &crate::UserTy) -> Result) + Sync + Sync> { + SimpleFunc::new(|params, _| { + let mut params = params.to_dict(); + // TODO implement purchases system + params.insert(PARAM_KEY, Typed::Dict(Dict { + key_ty: 115, // str + val_ty: 104, // hashtable + items: vec![], + })); + Ok(params.into()) + }) +} diff --git a/rc_services_room/src/operations/robopass_preview_items.rs b/rc_services_room/src/operations/robopass_preview_items.rs new file mode 100644 index 0000000..e06efc9 --- /dev/null +++ b/rc_services_room/src/operations/robopass_preview_items.rs @@ -0,0 +1,16 @@ +use polariton_server::operations::SimpleFunc; +use polariton::operation::{ParameterTable, Typed, Dict}; + +const PARAM_KEY: u8 = 1; + +pub(super) fn robopass_preview_provider() -> SimpleFunc<167, crate::UserTy, impl (Fn(ParameterTable, &crate::UserTy) -> Result) + Sync + Sync> { + SimpleFunc::new(|params, _| { + let mut params = params.to_dict(); + params.insert(PARAM_KEY, Typed::Dict(Dict { + key_ty: 115, // str + val_ty: 104, // hashtable + items: vec![], + })); + Ok(params.into()) + }) +} diff --git a/rc_services_room/src/operations/robot_customisations.rs b/rc_services_room/src/operations/robot_customisations.rs new file mode 100644 index 0000000..1a8b653 --- /dev/null +++ b/rc_services_room/src/operations/robot_customisations.rs @@ -0,0 +1,17 @@ +use polariton_server::operations::SimpleFunc; +use polariton::operation::{ParameterTable, Typed}; + +//const BAY_ID_KEY: u8 = 54; // in +const BAY_SKIN_KEY: u8 = 234; +const SPAWN_EFFECT_KEY: u8 = 235; +const DEATH_EFFECT_KEY: u8 = 236; + +pub(super) fn bay_customisations_provider() -> SimpleFunc<218, crate::UserTy, impl (Fn(ParameterTable, &crate::UserTy) -> Result) + Sync + Sync> { + SimpleFunc::new(|params, _| { + let mut params = params.to_dict(); + params.insert(BAY_SKIN_KEY, Typed::Str("RC_MothershipSkin_Neptune_01".into())); + params.insert(SPAWN_EFFECT_KEY, Typed::Str("RE_todo_spawn_effect".into())); + params.insert(DEATH_EFFECT_KEY, Typed::Str("RE_todo_death_effect".into())); + Ok(params.into()) + }) +} diff --git a/rc_services_room/src/operations/robot_mastery_settings.rs b/rc_services_room/src/operations/robot_mastery_settings.rs new file mode 100644 index 0000000..3b815c6 --- /dev/null +++ b/rc_services_room/src/operations/robot_mastery_settings.rs @@ -0,0 +1,14 @@ +use polariton_server::operations::SimpleFunc; +use polariton::operation::{ParameterTable, Typed}; + +const PARAM_KEY: u8 = 193; + +pub(super) fn robot_mastery_settings_provider() -> SimpleFunc<73, crate::UserTy, impl (Fn(ParameterTable, &crate::UserTy) -> Result) + Sync + Sync> { + SimpleFunc::new(|params, _| { + let mut params = params.to_dict(); + params.insert(PARAM_KEY, Typed::HashMap(vec![ + (Typed::Str("RobitsRewardForCRFRobotCreator".into()), Typed::Int(1_000)), + ].into())); + Ok(params.into()) + }) +} diff --git a/rc_services_room/src/operations/robot_sanction.rs b/rc_services_room/src/operations/robot_sanction.rs new file mode 100644 index 0000000..9accdea --- /dev/null +++ b/rc_services_room/src/operations/robot_sanction.rs @@ -0,0 +1,19 @@ +use polariton_server::operations::SimpleFunc; +use polariton::operation::{ParameterTable, Typed, Arr}; + +const ROBOT_ID_PARAM_KEY: u8 = 54; // str (in) +const SANCTION_JSONS_PARAM_KEY: u8 = 102; // str arr (out; list of jsons) + +pub(super) fn robot_sanction_provider() -> SimpleFunc<174, crate::UserTy, impl (Fn(ParameterTable, &crate::UserTy) -> Result) + Sync + Sync> { + SimpleFunc::new(|params, _| { + let mut params = params.to_dict(); + if let Some(Typed::Str(s)) = params.get(&ROBOT_ID_PARAM_KEY) { + log::debug!("Got sanction check for robot {}", s.string); + } + params.insert(SANCTION_JSONS_PARAM_KEY, Typed::Arr(Arr { + ty: 115, // str + items: Vec::default(), + })); + Ok(params.into()) + }) +} diff --git a/rc_services_room/src/operations/singleplayer_campaigns.rs b/rc_services_room/src/operations/singleplayer_campaigns.rs new file mode 100644 index 0000000..fa92501 --- /dev/null +++ b/rc_services_room/src/operations/singleplayer_campaigns.rs @@ -0,0 +1,22 @@ +use polariton_server::operations::SimpleFunc; +use polariton::operation::{ParameterTable, Typed}; + +const CAMPAIGNS_BYTES_PARAM_KEY: u8 = 64; // list of bytes (serialised data) +const CAMPAIGNS_WAVES_PARAM_KEY: u8 = 70; // hashtable +const CAMPAIGNS_VERSIONS_PARAM_KEY: u8 = 69; // hashtable + +pub(super) fn singleplayer_campaigns_provider() -> SimpleFunc<65, crate::UserTy, impl (Fn(ParameterTable, &crate::UserTy) -> Result) + Sync + Sync> { + SimpleFunc::new(|params, _| { + let mut params = params.to_dict(); + // TODO implement serialisation of Campaign[] properly + params.insert(CAMPAIGNS_BYTES_PARAM_KEY, Typed::Bytes(vec![0u8, 0u8, 0u8, 0u8].into())); // first 4 bytes are i32 for length of the rest + params.insert(CAMPAIGNS_WAVES_PARAM_KEY, Typed::HashMap(vec![].into())); + params.insert(CAMPAIGNS_VERSIONS_PARAM_KEY, Typed::HashMap(vec![ + (Typed::Str("CurrentVersionNumber".into()), Typed::Int(0)), + (Typed::Str("LockedCampaignsInfo".into()), Typed::HashMap(vec![ + (Typed::Str("0".into()), Typed::Bool(false.into())) + ].into())), + ].into())); + Ok(params.into()) + }) +} diff --git a/rc_services_room/src/operations/tech_points.rs b/rc_services_room/src/operations/tech_points.rs index 251a3dc..16063a2 100644 --- a/rc_services_room/src/operations/tech_points.rs +++ b/rc_services_room/src/operations/tech_points.rs @@ -1,12 +1,22 @@ use polariton_server::operations::SimpleFunc; use polariton::operation::{ParameterTable, Typed}; -const PARAM_KEY: u8 = 214; +const CURRENT_PARAM_KEY: u8 = 214; pub(super) fn tech_points_provider() -> SimpleFunc<187, crate::UserTy, impl (Fn(ParameterTable, &crate::UserTy) -> Result) + Sync + Sync> { SimpleFunc::new(|params, _| { let mut params = params.to_dict(); - params.insert(PARAM_KEY, Typed::Int(1337)); + params.insert(CURRENT_PARAM_KEY, Typed::Int(1337)); + Ok(params.into()) + }) +} + +const UNCLAIMED_PARAM_KEY: u8 = 212; + +pub(super) fn tech_points_awards_provider() -> SimpleFunc<185, crate::UserTy, impl (Fn(ParameterTable, &crate::UserTy) -> Result) + Sync + Sync> { + SimpleFunc::new(|params, _| { + let mut params = params.to_dict(); + params.insert(UNCLAIMED_PARAM_KEY, Typed::Int(0)); Ok(params.into()) }) } diff --git a/rc_services_room/src/operations/weapon_rating_static.rs b/rc_services_room/src/operations/weapon_rating_static.rs new file mode 100644 index 0000000..490ec7f --- /dev/null +++ b/rc_services_room/src/operations/weapon_rating_static.rs @@ -0,0 +1,33 @@ +use polariton_server::operations::SimpleFunc; +use polariton::operation::{ParameterTable, Typed, Dict}; + +const PARAM_KEY: u8 = 1; + +pub(super) fn weapon_rating_provider() -> SimpleFunc<127, crate::UserTy, impl (Fn(ParameterTable, &crate::UserTy) -> Result) + Sync + Sync> { + SimpleFunc::new(|params, _| { + let mut params = params.to_dict(); + params.insert(PARAM_KEY, Typed::HashMap(vec![ + (Typed::Str("subRankCount".into()), Typed::Int(2)), + (Typed::Str("subRankInterval".into()), Typed::Int(10)), + (Typed::Str("gainsPerRank".into()), Typed::ObjArr(vec![ + Typed::Dict(Dict { + key_ty: 115, // str + val_ty: 42, // obj + items: vec![ + (Typed::Str("win".into()), Typed::Int(7)), + (Typed::Str("loss".into()), Typed::Int(3)), + ], + }), + Typed::Dict(Dict { + key_ty: 115, // str + val_ty: 42, // obj + items: vec![ + (Typed::Str("win".into()), Typed::Int(11)), + (Typed::Str("loss".into()), Typed::Int(3)), + ], + }) + ].into())), + ].into())); + Ok(params.into()) + }) +} diff --git a/rc_services_room/src/operations/weapon_upgrades.rs b/rc_services_room/src/operations/weapon_upgrades.rs new file mode 100644 index 0000000..4a55278 --- /dev/null +++ b/rc_services_room/src/operations/weapon_upgrades.rs @@ -0,0 +1,23 @@ +use polariton_server::operations::SimpleFunc; +use polariton::operation::{ParameterTable, Typed}; + +use crate::data::weapon_upgrade::*; + +const PARAM_KEY: u8 = 38; + +pub(super) fn weapons_upgrade_provider() -> SimpleFunc<82, crate::UserTy, impl (Fn(ParameterTable, &crate::UserTy) -> Result) + Sync + Sync> { + SimpleFunc::new(|params, _| { + let mut params = params.to_dict(); + params.insert(PARAM_KEY, Typed::ObjArr(vec![ + WeaponUpgradeInfo { + tier: crate::data::cube_list::ItemTier::T0, + type_: crate::data::weapon_list::ItemCategory::Laser, + xp: 4.2, + rating: 1, + rank: 1, + power: 1, + }.as_transmissible(), + ].into())); + Ok(params.into()) + }) +} diff --git a/rc_services_room/src/operations/weapon_xp_static.rs b/rc_services_room/src/operations/weapon_xp_static.rs new file mode 100644 index 0000000..d694f0c --- /dev/null +++ b/rc_services_room/src/operations/weapon_xp_static.rs @@ -0,0 +1,42 @@ +use polariton_server::operations::SimpleFunc; +use polariton::operation::{ParameterTable, Typed, Dict}; + +use crate::data::cube_list::ItemTier; + +const PARAM_KEY: u8 = 1; + +pub(super) fn weapon_xp_provider() -> SimpleFunc<129, crate::UserTy, impl (Fn(ParameterTable, &crate::UserTy) -> Result) + Sync + Sync> { + SimpleFunc::new(|params, _| { + let mut params = params.to_dict(); + params.insert(PARAM_KEY, Typed::HashMap(vec![ + (Typed::Str("maxPower".into()), Typed::Int(2)), + (Typed::Str("powerLevelsPerTier".into()), Typed::Dict(Dict { + key_ty: 105, // int + val_ty: 122, // obj arr + items: vec![ + (Typed::Int(ItemTier::T0 as _), Typed::ObjArr(vec![ + Typed::Dict(Dict { + key_ty: 115, // str + val_ty: 42, // obj + items: vec![ + (Typed::Str("xp".into()), Typed::Int(1_000)), + (Typed::Str("costRobits".into()), Typed::Int(1_000)), + (Typed::Str("damageMultiplier".into()), Typed::Float(1.1)), + ], + }), + Typed::Dict(Dict { + key_ty: 115, // str + val_ty: 42, // obj + items: vec![ + (Typed::Str("xp".into()), Typed::Int(2_000)), + (Typed::Str("costRobits".into()), Typed::Int(2_000)), + (Typed::Str("damageMultiplier".into()), Typed::Float(1.2)), + ], + }), + ].into())), + ], + })), + ].into())); + Ok(params.into()) + }) +} diff --git a/rc_social_room/src/data/clan.rs b/rc_social_room/src/data/clan.rs index 61d9d05..b63c6e0 100644 --- a/rc_social_room/src/data/clan.rs +++ b/rc_social_room/src/data/clan.rs @@ -50,3 +50,21 @@ pub enum ClanType { Open = 1, Closed = 2, } + +pub struct ClanInfo { + pub clan_name: String, + pub clan_description: String, + pub clan_type: ClanType, + pub clan_size: i32, +} + +impl ClanInfo { + pub fn as_transmissible(&self) -> Typed { + Typed::HashMap(vec![ + (Typed::Str("clanName".into()), Typed::Str(self.clan_name.clone().into())), + (Typed::Str("clanDescription".into()), Typed::Str(self.clan_description.clone().into())), + (Typed::Str("clanType".into()), Typed::Int(self.clan_type as i32)), + (Typed::Str("clanSize".into()), Typed::Int(self.clan_size)), + ].into()) + } +} diff --git a/rc_social_room/src/operations/mod.rs b/rc_social_room/src/operations/mod.rs index 251fc04..b808006 100644 --- a/rc_social_room/src/operations/mod.rs +++ b/rc_social_room/src/operations/mod.rs @@ -3,6 +3,10 @@ mod friend_list; mod settings; mod clan_invite; mod clan_info; +mod search_clan; +mod season_rewards; +mod previous_battle_rewards; +mod platoon_data; use polariton_server::operations::OperationsHandler; @@ -16,4 +20,9 @@ pub fn handler() -> OperationsHandler { .without_state(clan_invite::clan_invites_provider()) .without_state(polariton_server::operations::Ack::<19, _>::default()) // get pending platoon invite (this is equivalent to having no pending invite) .without_state(clan_info::clan_info_provider()) + .without_state(search_clan::search_clans_provider()) + .without_state(polariton_server::operations::Ack::<52, _>::default()) // validate pending season rewards (this just always needs to be ack-ed) + .without_state(season_rewards::season_rewards_provider()) + .without_state(previous_battle_rewards::pending_battle_rewards_provider()) + .without_state(platoon_data::platoon_provider()) } diff --git a/rc_social_room/src/operations/platoon_data.rs b/rc_social_room/src/operations/platoon_data.rs new file mode 100644 index 0000000..24b1ddb --- /dev/null +++ b/rc_social_room/src/operations/platoon_data.rs @@ -0,0 +1,15 @@ +use polariton_server::operations::SimpleFunc; +use polariton::operation::ParameterTable; + +//const PLATOON_ID_PARAM_KEY: u8 = 16; +//const PLATOON_LEADER_PARAM_KEY: u8 = 17; +//const USER_LIST_PARAM_KEY: u8 = 7; + +pub(super) fn platoon_provider() -> SimpleFunc<18, crate::UserTy, impl (Fn(ParameterTable, &crate::UserTy) -> Result) + Sync + Sync> { + SimpleFunc::new(|params, _| { + //let mut params = params.to_dict(); + // if platoon ID is not provided, you're not in a platoon + //Ok(params.into()) + Ok(params) + }) +} diff --git a/rc_social_room/src/operations/previous_battle_rewards.rs b/rc_social_room/src/operations/previous_battle_rewards.rs new file mode 100644 index 0000000..c37ca8f --- /dev/null +++ b/rc_social_room/src/operations/previous_battle_rewards.rs @@ -0,0 +1,13 @@ +use polariton_server::operations::SimpleFunc; +use polariton::operation::{ParameterTable, Typed}; + +const PARAM_KEY: u8 = 60; +//const USER_PARAM_KEY: u8 = 1; // str (username) + +pub(super) fn pending_battle_rewards_provider() -> SimpleFunc<54, crate::UserTy, impl (Fn(ParameterTable, &crate::UserTy) -> Result) + Sync + Sync> { + SimpleFunc::new(|params, _| { + let mut params = params.to_dict(); + params.insert(PARAM_KEY, Typed::Bool(false.into())); + Ok(params.into()) + }) +} diff --git a/rc_social_room/src/operations/search_clan.rs b/rc_social_room/src/operations/search_clan.rs new file mode 100644 index 0000000..2f7380d --- /dev/null +++ b/rc_social_room/src/operations/search_clan.rs @@ -0,0 +1,37 @@ +use polariton_server::operations::SimpleFunc; +use polariton::operation::{ParameterTable, Typed, Arr}; + +use crate::data::clan::*; + +// params in TODO +const STRING_PARAM_KEY: u8 = 39; +/*const DAYS_SINCE_ACTIVE_PARAM_KEY: u8 = 40; +const START_RANGE_PARAM_KEY: u8 = 41; +const END_RANGE_PARAM_KEY: u8 = 43; +const TYPES_PARAM_KEY: u8 = 34;*/ + +// params out +const RESULTS_PARAM_KEY: u8 = 42; + +pub(super) fn search_clans_provider() -> SimpleFunc<32, crate::UserTy, impl (Fn(ParameterTable, &crate::UserTy) -> Result) + Sync + Sync> { + SimpleFunc::new(|params, _| { + let mut params = params.to_dict(); + if let Some(Typed::Str(s)) = params.get(&STRING_PARAM_KEY) { + if !s.string.is_empty() { + log::debug!("Got clan search string `{}`", s.string); + } + } + params.insert(RESULTS_PARAM_KEY, Typed::Arr(Arr { + ty: 104, // hashmap + items: vec![ + ClanInfo { + clan_name: "".to_owned(), + clan_description: "".to_owned(), + clan_type: ClanType::Closed, + clan_size: 1, + }.as_transmissible(), + ], + })); + Ok(params.into()) + }) +} diff --git a/rc_social_room/src/operations/season_rewards.rs b/rc_social_room/src/operations/season_rewards.rs new file mode 100644 index 0000000..a21a4b8 --- /dev/null +++ b/rc_social_room/src/operations/season_rewards.rs @@ -0,0 +1,26 @@ +use polariton_server::operations::SimpleFunc; +use polariton::operation::{ParameterTable, Typed}; + +const MONTH_PARAM_KEY: u8 = 49; +const YEAR_PARAM_KEY: u8 = 63; +const ROBITS_PARAM_KEY: u8 = 47; +const IS_CLAIMED_PARAM_KEY: u8 = 46; +const CLAN_AVERAGE_PARAM_KEY: u8 = 54; +const CLAN_TOTAL_PARAM_KEY: u8 = 55; +const CLAN_NAME_PARAM_KEY: u8 = 31; +const PLAYER_XP_PARAM_KEY: u8 = 57; + +pub(super) fn season_rewards_provider() -> SimpleFunc<50, crate::UserTy, impl (Fn(ParameterTable, &crate::UserTy) -> Result) + Sync + Sync> { + SimpleFunc::new(|params, _| { + let mut params = params.to_dict(); + params.insert(MONTH_PARAM_KEY, Typed::Int(02)); + params.insert(YEAR_PARAM_KEY, Typed::Int(2025)); + params.insert(ROBITS_PARAM_KEY, Typed::Int(42)); + params.insert(IS_CLAIMED_PARAM_KEY, Typed::Bool(true.into())); + params.insert(CLAN_AVERAGE_PARAM_KEY, Typed::Int(67)); + params.insert(CLAN_TOTAL_PARAM_KEY, Typed::Int(42_123)); + params.insert(CLAN_NAME_PARAM_KEY, Typed::Str("RE_clan_name_rewards".into())); + params.insert(PLAYER_XP_PARAM_KEY, Typed::Int(10_000)); + Ok(params.into()) + }) +}