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

Move common components to shared lib

This commit is contained in:
NGnius (Graham)
2025-03-30 16:22:25 -04:00
parent 610f54e236
commit 0e048a17b1
76 changed files with 284 additions and 1110 deletions

View File

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

View File

@@ -0,0 +1,301 @@
use polariton::operation::Typed;
pub struct CampaignsGameParameters {
pub campaigns: Vec<CampaignParameters>,
}
impl CampaignsGameParameters {
fn dump(&self, writer: &mut dyn std::io::Write) -> std::io::Result<usize> {
writer.write_all(&(self.campaigns.len() as i32).to_le_bytes())?;
let mut total_len = 4;
for campaign in self.campaigns.iter() {
total_len += campaign.dump(writer)?;
}
Ok(total_len)
}
pub fn as_transmissible<C>(&self) -> Typed<C> {
let mut buf = Vec::new();
self.dump(&mut std::io::Cursor::new(&mut buf)).unwrap();
Typed::Bytes(buf.into())
}
}
pub struct CampaignParameters {
pub id: String,
pub excluded_cubes: Vec<u32>, // encoded to hex strings
pub categories: Vec<super::weapon_list::ItemCategory>,
pub min_cpu: i32,
pub max_cpu: i32,
pub name: String,
pub description: String,
pub image: String,
pub rules: Vec<String>,
pub parameters: Vec<Vec<String>>,
pub difficulties: Vec<CampaignDifficultyData>,
pub completed: Vec<CampaignCompletionData>,
pub map: String,
}
impl CampaignParameters {
fn dump(&self, writer: &mut dyn std::io::Write) -> std::io::Result<usize> {
let mut total_len = super::write_str_for_binreader(&self.id, writer)?;
writer.write_all(&(self.excluded_cubes.len() as i32).to_le_bytes())?;
total_len += 4;
for excluded_cube in self.excluded_cubes.iter() {
let s = super::cube_id_to_str(*excluded_cube);
total_len += super::write_str_for_binreader(&s, writer)?;
}
writer.write_all(&(self.categories.len() as i32).to_le_bytes())?;
total_len += 4;
for cat in self.categories.iter() {
total_len += super::write_str_for_binreader(cat.as_str(), writer)?;
}
writer.write_all(&self.min_cpu.to_le_bytes())?;
writer.write_all(&self.max_cpu.to_le_bytes())?;
total_len += 8;
total_len += super::write_str_for_binreader(&self.name, writer)?;
total_len += super::write_str_for_binreader(&self.description, writer)?;
total_len += super::write_str_for_binreader(&self.image, writer)?;
writer.write_all(&(self.rules.len() as i32).to_le_bytes())?;
total_len += 4;
for rule in self.rules.iter() {
total_len += super::write_str_for_binreader(rule, writer)?;
}
writer.write_all(&(self.parameters.len() as i32).to_le_bytes())?;
total_len += 4;
for param_vec in self.parameters.iter() {
writer.write_all(&(param_vec.len() as i32).to_le_bytes())?;
total_len += 4;
for param in param_vec.iter() {
total_len += super::write_str_for_binreader(param, writer)?;
}
}
writer.write_all(&(self.difficulties.len() as i32).to_le_bytes())?;
total_len += 4;
for difficulty in self.difficulties.iter() {
writer.write_all(&(CampaignDifficultyData::WRITE_BYTES_LEN as i32).to_le_bytes())?;
total_len += 4 + difficulty.dump(writer)?;
}
writer.write_all(&(self.completed.len() as i32).to_le_bytes())?;
total_len += 4;
for completion in self.completed.iter() {
total_len += completion.dump(writer)?;
}
total_len += super::write_str_for_binreader(&self.map, writer)?;
Ok(total_len)
}
}
pub struct CampaignDifficultyData {
pub level: i32,
pub lives: i32,
pub auto_heal: bool,
pub single_wave_bonus: i32,
pub initial_health_boost: f32,
pub health_boost_wave_increase: f32,
pub initial_damage_boost: f32,
pub damage_boost_wave_increase: f32,
}
impl CampaignDifficultyData {
const WRITE_BYTES_LEN: usize = 29;
fn dump(&self, writer: &mut dyn std::io::Write) -> std::io::Result<usize> {
writer.write_all(&self.level.to_le_bytes())?;
writer.write_all(&self.lives.to_le_bytes())?;
writer.write_all(&[self.auto_heal as u8])?;
writer.write_all(&self.single_wave_bonus.to_le_bytes())?;
writer.write_all(&self.initial_health_boost.to_le_bytes())?;
writer.write_all(&self.health_boost_wave_increase.to_le_bytes())?;
writer.write_all(&self.initial_damage_boost.to_le_bytes())?;
writer.write_all(&self.damage_boost_wave_increase.to_le_bytes())?;
Ok(Self::WRITE_BYTES_LEN)
}
}
pub struct CampaignCompletionData {
pub index: i32,
pub wave: i32,
pub difficulty: bool,
}
impl CampaignCompletionData {
const WRITE_BYTES_LEN: usize = 9;
fn dump(&self, writer: &mut dyn std::io::Write) -> std::io::Result<usize> {
writer.write_all(&self.index.to_le_bytes())?;
writer.write_all(&self.wave.to_le_bytes())?;
writer.write_all(&[self.difficulty as u8])?;
Ok(Self::WRITE_BYTES_LEN)
}
}
pub struct LiveCampaignWaves {
pub waves: Vec<WavesData>,
}
impl LiveCampaignWaves {
pub fn as_transmissible<C>(&self) -> Typed<C> {
Typed::HashMap(self.waves.iter().flat_map(|waves| waves.as_transmissible_key_val()).collect::<Vec<_>>().into())
}
}
pub struct WavesData {
pub id: String,
pub waves: Vec<WaveData>,
pub campaign_type: CampaignType,
}
impl WavesData {
pub fn as_transmissible_key_val<C>(&self) -> [(Typed<C>, Typed<C>); 3] {
[
(Typed::Str(format!("wavesNumberInCurrentCampaign_{}", self.id).into()), Typed::Int(self.waves.len() as _)),
(Typed::Str(self.id.clone().into()), Typed::HashMap(self.waves.iter().enumerate().flat_map(|(i, wave)| wave.as_transmissible_key_val(i)).collect::<Vec<_>>().into())),
(Typed::Str(format!("campaignType_{}", self.id).into()), Typed::Int(self.campaign_type as _)),
]
}
}
pub struct WaveData {
pub robots_in_wave: Vec<WaveRobotData>,
}
impl WaveData {
pub fn as_transmissible_key_val<C>(&self, index: usize) -> [(Typed<C>, Typed<C>); 2] {
[
(Typed::Str(format!("numberOfDifferentRobotsInCurrentWave_{}", index).into()), Typed::Int(self.robots_in_wave.len() as _)),
(Typed::Int(index as _), Typed::HashMap(self.robots_in_wave.iter().enumerate().map(|(i, robot)| (Typed::Int(i as _), robot.as_transmissible())).collect::<Vec<_>>().into())),
]
}
}
pub struct WaveRobotData {
pub name: String,
pub weapon: String,
pub movement: String,
pub rank: String,
pub count: i32,
}
impl WaveRobotData {
pub fn as_transmissible<C>(&self) -> Typed<C> {
Typed::HashMap(vec![
(Typed::Str("RobotName".into()), Typed::Str(self.name.clone().into())),
(Typed::Str("RobotWeapon".into()), Typed::Str(self.weapon.clone().into())),
(Typed::Str("RobotMovementPart".into()), Typed::Str(self.movement.clone().into())),
(Typed::Str("RobotRank".into()), Typed::Str(self.rank.clone().into())),
(Typed::Str("RobotCount".into()), Typed::Int(self.count)),
].into())
}
}
#[repr(u8)]
#[derive(Debug, Clone, Copy)]
pub enum CampaignType {
TimedElimination = 0,
Survival = 1,
Elimination = 2,
}
pub struct GameModeVersionParameters {
pub current_version: i32,
pub is_locked: std::collections::HashMap<String, bool>,
}
impl GameModeVersionParameters {
pub fn as_transmissible<C>(&self) -> Typed<C> {
Typed::HashMap(vec![
(Typed::Str("CurrentVersionNumber".into()), Typed::Int(self.current_version)),
(Typed::Str("LockedCampaignsInfo".into()), Typed::HashMap(self.is_locked.iter().map(|(key, val)| (Typed::Str(key.into()), Typed::Bool(*val))).collect::<Vec<_>>().into())),
].into())
}
}
pub struct CampaignWavesDifficultyData {
pub difficulty: CampaignDifficultyData,
pub waves: Vec<CompleteWaveData>,
}
impl CampaignWavesDifficultyData {
pub fn as_transmissible<C>(&self) -> Typed<C> {
let mut buf = Vec::new();
self.dump(&mut std::io::Cursor::new(&mut buf)).unwrap();
Typed::Bytes(buf.into())
}
fn dump(&self, writer: &mut dyn std::io::Write) -> std::io::Result<usize> {
writer.write_all(&(CampaignDifficultyData::WRITE_BYTES_LEN as i32).to_le_bytes())?;
self.difficulty.dump(writer)?;
writer.write_all(&(self.waves.len() as i32).to_le_bytes())?;
let mut waves_total_len = 4;
for wave in self.waves.iter() {
waves_total_len += wave.dump(writer)?;
}
Ok(4 + CampaignDifficultyData::WRITE_BYTES_LEN + waves_total_len)
}
}
pub struct CompleteWaveData {
pub player_spawn_location: i32,
pub robots_in_wave: Vec<CompleteWaveRobotData>,
pub kill_target: i32,
pub time_min: i32,
pub time_max: i32,
}
impl CompleteWaveData {
fn dump(&self, writer: &mut dyn std::io::Write) -> std::io::Result<usize> {
writer.write_all(&self.player_spawn_location.to_le_bytes())?;
writer.write_all(&(self.robots_in_wave.len() as i32).to_le_bytes())?;
let mut robots_total_len = 4;
for robot in self.robots_in_wave.iter() {
robots_total_len += robot.dump(writer)?;
}
writer.write_all(&self.kill_target.to_le_bytes())?;
writer.write_all(&self.time_min.to_le_bytes())?;
writer.write_all(&self.time_max.to_le_bytes())?;
Ok(16 + robots_total_len)
}
}
pub struct CompleteWaveRobotData {
pub name: String,
pub robot_data: Vec<u8>,
pub colour_data: Vec<u8>,
pub time_to_spawn: i32,
pub kills_to_spawn: i32,
pub time_to_despawn: i32,
pub kills_to_despawn: i32,
pub initial_robot_amount: i32,
pub periodic_robot_amount: i32,
pub spawn_interval: i32,
pub min_robot_amount: i32,
pub max_robot_amount: i32,
pub is_boss: bool,
pub is_kill_requirement: bool,
}
impl CompleteWaveRobotData {
fn dump(&self, writer: &mut dyn std::io::Write) -> std::io::Result<usize> {
let mut total_len = super::write_str_for_binreader(&self.name, writer)?;
writer.write_all(&(self.robot_data.len() as i32).to_le_bytes())?;
total_len += 4;
writer.write_all(&self.robot_data)?;
total_len += self.robot_data.len();
writer.write_all(&(self.colour_data.len() as i32).to_le_bytes())?;
total_len += 4;
writer.write_all(&self.colour_data)?;
total_len += self.colour_data.len();
writer.write_all(&self.time_to_spawn.to_le_bytes())?;
writer.write_all(&self.kills_to_spawn.to_le_bytes())?;
writer.write_all(&self.time_to_despawn.to_le_bytes())?;
writer.write_all(&self.kills_to_despawn.to_le_bytes())?;
writer.write_all(&self.initial_robot_amount.to_le_bytes())?;
writer.write_all(&self.periodic_robot_amount.to_le_bytes())?;
writer.write_all(&self.spawn_interval.to_le_bytes())?;
writer.write_all(&self.min_robot_amount.to_le_bytes())?;
writer.write_all(&self.max_robot_amount.to_le_bytes())?;
writer.write_all(&[self.is_boss as u8])?;
writer.write_all(&[self.is_kill_requirement as u8])?;
Ok(total_len)
}
}

View File

@@ -0,0 +1,133 @@
#![allow(dead_code)]
use std::collections::HashMap;
use polariton::operation::{Dict, Typed};
pub struct CubeInfo<C: Clone> {
pub cpu: u32,
pub health: u32,
pub health_boost: f32,
pub grey_out_in_tutorial: bool,
pub visibility: VisibilityMode,
pub indestructible: bool,
pub category: super::weapon_list::ItemCategory,
pub placements: u32, // default 63
pub protonium: bool,
pub unlocked_by_league: bool,
pub league_unlock_index: i32,
pub stats: HashMap<String, Typed<C>>,
pub description: String,
pub size: ItemTier,
pub type_: ItemType,
pub ranking: i32,
pub cosmetic: bool,
pub variant_of: String, // cube id (in hex)
pub ignore_in_weapon_list: bool,
}
impl <C: Clone> CubeInfo<C> {
pub fn as_transmissible(&self) -> Typed<C> {
Typed::HashMap(vec![
(Typed::Str("cpuRating".into()), Typed::Int(self.cpu as i32)),
(Typed::Str("health".into()), Typed::Int(self.health as i32)),
(Typed::Str("healthBoost".into()), Typed::Float(self.health_boost)),
(Typed::Str("GreyOutInTutorial".into()), Typed::Bool(self.grey_out_in_tutorial.into())),
(Typed::Str("buildVisibility".into()), Typed::Str(self.visibility.as_str().into())),
(Typed::Str("isIndestructible".into()), Typed::Bool(self.indestructible.into())),
(Typed::Str("ItemCategory".into()), Typed::Int(self.category as i32)),
(Typed::Str("PlacementFaces".into()), Typed::Int(self.placements as i32)),
(Typed::Str("protoniumCrystal".into()), Typed::Bool(self.protonium.into())),
(Typed::Str("UnlockedByLeague".into()), Typed::Bool(self.unlocked_by_league.into())),
(Typed::Str("LeagueUnlockIndex".into()), Typed::Int(self.league_unlock_index)),
(Typed::Str("DisplayStats".into()), {
let items: Vec<(Typed<C>, Typed<C>)> = self.stats.iter().map(|(key, val)| (Typed::<C>::Str(key.into()), val.to_owned())).collect();
//Typed::HashMap(items.into())
Typed::Dict(Dict {
key_ty: polariton::serdes::TypePrefix::Str,
val_ty: polariton::serdes::TypePrefix::Any,
items,
})
}),
(Typed::Str("Description".into()), Typed::Str(self.description.clone().into())),
(Typed::Str("ItemSize".into()), Typed::Int(self.size as i32)),
(Typed::Str("ItemType".into()), Typed::Str(self.type_.as_str().into())),
(Typed::Str("robotRanking".into()), Typed::Int(self.ranking)),
(Typed::Str("isCosmetic".into()), Typed::Bool(self.cosmetic.into())),
(Typed::Str("variantOf".into()), Typed::Str(self.variant_of.clone().into())),
(Typed::Str("ignoreInWeaponsList".into()), Typed::Bool(self.ignore_in_weapon_list.into())), // optional
].into())
}
pub fn as_transmissible_key_val(&self, cube_id: u32) -> (Typed<C>, Typed<C>) {
(Typed::Str(hex::encode(cube_id.to_be_bytes()).into()), self.as_transmissible())
}
}
#[derive(Clone, Copy)]
pub enum VisibilityMode {
Mothership,
All,
Tutorial,
None,
}
impl VisibilityMode {
fn as_str(&self) -> &'static str {
match self {
Self::Mothership => "Mothership",
Self::All => "All",
Self::Tutorial => "Tutorial",
Self::None => "None",
}
}
}
#[repr(u32)]
#[derive(Clone, Copy)]
pub enum ItemTier {
NoTier = 0,
T0 = 100,
T1 = 200,
T2 = 300,
T3 = 400,
T4 = 500,
T5 = 600,
}
impl ItemTier {
pub fn as_str(&self) -> &'static str {
match self {
ItemTier::NoTier => "NotAWeapon",
ItemTier::T0 => "T0",
ItemTier::T1 => "T1",
ItemTier::T2 => "T2",
ItemTier::T3 => "T3",
ItemTier::T4 => "T4",
ItemTier::T5 => "T5",
}
}
}
#[derive(Clone, Copy)]
pub enum ItemType {
NoFunction,
Weapon,
Module,
Movement,
Cosmetic,
}
impl ItemType {
fn as_str(&self) -> &'static str {
match self {
Self::NoFunction => "NotAFunctionalItem",
Self::Weapon => "Weapon",
Self::Module => "Module",
Self::Movement => "Movement",
Self::Cosmetic => "Cosmetic",
}
}
}
pub fn item_key(category: super::weapon_list::ItemCategory, tier: ItemTier) -> i32 {
category.but_bigger() + (tier as i32)
}

View File

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

View File

@@ -0,0 +1,41 @@
use polariton::{operation::Typed, serdes::TypePrefix};
pub struct GameModeConfig {
pub respawn_heal_duration: f32,
pub respawn_full_heal_duration: f32,
pub kill_limit: i32,
pub game_time_minutes: i32,
}
impl GameModeConfig {
pub fn as_transmissible<C>(&self) -> Typed<C> {
Typed::HashMap(vec![
(Typed::Str("respawnHealDuration".into()), Typed::Float(self.respawn_heal_duration)),
(Typed::Str("respawnFullHealDuration".into()), Typed::Float(self.respawn_full_heal_duration)),
(Typed::Str("killLimit".into()), Typed::Int(self.kill_limit)),
(Typed::Str("gameTimeMinutes".into()), Typed::Int(self.game_time_minutes)),
].into())
}
}
pub struct GameModeConfigs {
pub battle_arena: GameModeConfig,
pub elimination: GameModeConfig,
pub the_pit: GameModeConfig,
pub team_deathmatch: GameModeConfig,
}
impl GameModeConfigs {
pub fn as_transmissible<C>(&self) -> Typed<C> {
Typed::Dict(polariton::operation::Dict {
key_ty: TypePrefix::Str,
val_ty: TypePrefix::HashMap,
items: vec![
(Typed::Str("BattleArena".into()), self.battle_arena.as_transmissible()),
(Typed::Str("Elimination".into()), self.elimination.as_transmissible()),
(Typed::Str("ThePit".into()), self.the_pit.as_transmissible()),
(Typed::Str("TeamDeathmatch".into()), self.team_deathmatch.as_transmissible()),
],
})
}
}

View File

@@ -0,0 +1,86 @@
use polariton::{operation::{Arr, Typed}, serdes::TypePrefix};
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<ItemCategory>,
pub uuid: (u32, u32),
pub thumbnail_version: u32,
pub total_robot_cpu: u32,
pub total_cosmetic_cpu: u32,
pub total_robot_ranking: u32,
pub bay_cpu: u32,
pub tutorial_robot: bool, // assumed to be false (when omitted)
pub starter_robot_index: i32, // assumed to be -1 (whem omitted)
pub control_type: ControlType,
pub control_options: ControlOptions,
pub mastery_level: i32,
pub bay_skin_id: String,
pub weapon_order: Vec<i32>,
}
impl GarageSlotInfo {
pub fn as_transmissible<C>(&self) -> Typed<C> {
Typed::HashMap(vec![
(Typed::Str("name".into()), Typed::Str(self.name.clone().into())),
(Typed::Str("numberCubes".into()), Typed::Int(self.cubes as i32)),
(Typed::Str("crfId".into()), Typed::Int(self.crf_id as i32)),
(Typed::Str("wasRated".into()), Typed::Bool(self.was_rated.into())),
(Typed::Str("movementCategories".into()), Typed::Arr(Arr {
ty: TypePrefix::Int, // int
items: self.movement_categories.iter().map(|x| Typed::Int(x.but_bigger() as i32)).collect(),
})),
(Typed::Str("uniqueId1".into()), Typed::Int(self.uuid.0 as i32)),
(Typed::Str("uniqueId2".into()), Typed::Int(self.uuid.1 as i32)),
(Typed::Str("thumbnailVersion".into()), Typed::Int(self.thumbnail_version as i32)),
(Typed::Str("totalRobotCPU".into()), Typed::Int(self.total_robot_cpu as i32)),
(Typed::Str("totalCosmeticCPU".into()), Typed::Int(self.total_cosmetic_cpu as i32)),
(Typed::Str("totalRobotRanking".into()), Typed::Int(self.total_robot_ranking as i32)),
(Typed::Str("bayCpu".into()), Typed::Int(self.bay_cpu as i32)),
(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()), 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 {
ty: TypePrefix::Int, // int
items: self.weapon_order.iter().map(|x| Typed::Int(*x)).collect(),
})),
].into())
}
}
#[allow(dead_code)]
#[repr(i32)]
#[derive(Copy, Clone)]
pub enum ControlType {
Camera = 0,
Keyboard = 1,
Count = 2,
}
pub struct ControlOptions {
pub vertical_strafing: bool,
pub sideways_driving: bool,
pub tracks_turn_on_spot: bool,
}
impl ControlOptions {
pub fn as_transmissible<C>(&self) -> Typed<C> {
Typed::Arr(Arr {
ty: TypePrefix::Bool, // bool
items: vec![
Typed::Bool(self.vertical_strafing.into()),
Typed::Bool(self.sideways_driving.into()),
Typed::Bool(self.tracks_turn_on_spot.into()),
],
})
}
}

39
rc_core/src/data/mod.rs Normal file
View File

@@ -0,0 +1,39 @@
pub mod auto_regen;
pub mod campaign;
pub mod cube_list;
pub mod game_mode;
pub mod garage_bay;
pub mod movement_list;
pub mod player_data;
pub mod tech_tree;
pub mod voting;
pub mod weapon_list;
pub mod weapon_upgrade;
pub mod error_codes;
pub fn encode_7_bit_i32(mut src: i32) -> Vec<u8> {
if src == 0 { return vec![0] }
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 fn write_str_for_binreader(s: &str, writer: &mut dyn std::io::Write) -> std::io::Result<usize> {
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)
}
pub fn cube_id_to_str(id: u32) -> String {
hex::encode(id.to_be_bytes()).into()
}

View File

@@ -0,0 +1,455 @@
#![allow(dead_code)]
use polariton::operation::{Typed, Dict};
use polariton::serdes::TypePrefix;
use super::cube_list::ItemTier;
#[derive(Default)]
pub struct MovementCategoryData {
pub horizontal_top_speed: Option<f32>,
pub vertical_top_speed: Option<f32>,
pub min_required_items: Option<i32>,
pub min_item_modifier: Option<f32>,
pub max_hover_height: Option<f32>,
pub light_machine_mass: Option<f32>,
pub heavy_machine_mass: Option<f32>,
pub specifics: MovementCategorySpecificData,
pub stats: Vec<(ItemTier, MovementData)>,
}
impl MovementCategoryData {
pub fn as_transmissible<C>(&self) -> Typed<C> {
let mut out = Vec::new();
self.horizontal_top_speed.map(|x| out.push((Typed::Str("horizontalTopSpeed".into()), Typed::Float(x))));
self.vertical_top_speed.map(|x| out.push((Typed::Str("verticalTopSpeed".into()), Typed::Float(x))));
self.min_required_items.map(|x| out.push((Typed::Str("minRequiredItems".into()), Typed::Int(x))));
self.min_item_modifier.map(|x| out.push((Typed::Str("minItemsModifier".into()), Typed::Float(x))));
self.max_hover_height.map(|x| out.push((Typed::Str("maxHoverHeight".into()), Typed::Float(x))));
self.light_machine_mass.map(|x| out.push((Typed::Str("lightMachineMass".into()), Typed::Float(x))));
self.heavy_machine_mass.map(|x| out.push((Typed::Str("heavyMachineMass".into()), Typed::Float(x))));
out.append(&mut self.specifics.as_transmissible());
for (tier, mov_data) in self.stats.iter() {
out.push((Typed::Str(tier.as_str().into()), mov_data.as_transmissible()));
}
Typed::Dict(Dict {
key_ty: TypePrefix::Str,
val_ty: TypePrefix::Any,
items: out.into(),
})
}
}
#[derive(Default)]
pub enum MovementCategorySpecificData {
#[default]
Wheel,
Hover(HoverCategoryData),
Wing,
Rudder, // same as wing
Thruster,
Propeller, // same as thruster
InsectLeg,
MechLeg(MechLegCategoryData),
SprinterLeg(MechLegCategoryData), // same as mech leg
TankTrack,
Rotor(RotorCategoryData),
Ski,
}
impl MovementCategorySpecificData {
pub fn as_transmissible<C>(&self) -> Vec<(Typed<C>, Typed<C>)> {
match self {
Self::Wheel => Vec::default(),
Self::Hover(x) => x.as_transmissible(),
Self::Wing => Vec::default(),
Self::Rudder => Vec::default(),
Self::Thruster => Vec::default(),
Self::Propeller => Vec::default(),
Self::InsectLeg => Vec::default(),
Self::MechLeg(x) => x.as_transmissible(),
Self::SprinterLeg(x) => x.as_transmissible(),
Self::TankTrack => Vec::default(),
Self::Rotor(x) => x.as_transmissible(),
Self::Ski => Vec::default(),
}
}
}
pub struct HoverCategoryData {
pub height_tolerance: f32,
pub force_y_offset: f32,
pub turning_scale: f32,
pub small_angle_turning_scale: f32,
pub max_vertical_velocity: f32,
pub hover_damping: f32,
pub angular_damping: f32,
pub deceleration_multiplier: f32,
}
impl HoverCategoryData {
pub fn as_transmissible<C>(&self) -> Vec<(Typed<C>, Typed<C>)> {
vec![
(Typed::Str("heightTolerance".into()), Typed::Float(self.height_tolerance)),
(Typed::Str("forceYOffset".into()), Typed::Float(self.force_y_offset)),
(Typed::Str("turningScale".into()), Typed::Float(self.turning_scale)),
(Typed::Str("smallAngleTurningScale".into()), Typed::Float(self.small_angle_turning_scale)),
(Typed::Str("verticalTopSpeed".into()), Typed::Float(self.max_vertical_velocity)),
(Typed::Str("hoverDamping".into()), Typed::Float(self.hover_damping)),
(Typed::Str("angularDamping".into()), Typed::Float(self.angular_damping)),
(Typed::Str("decelerationMultiplier".into()), Typed::Float(self.deceleration_multiplier)),
]
}
}
pub struct MechLegCategoryData {
pub deceleration_multiplier: f32,
}
impl MechLegCategoryData {
pub fn as_transmissible<C>(&self) -> Vec<(Typed<C>, Typed<C>)> {
vec![
(Typed::Str("decelerationMultiplier".into()), Typed::Float(self.deceleration_multiplier)),
]
}
}
pub struct RotorCategoryData {
pub max_turn_rate: f32,
}
impl RotorCategoryData {
pub fn as_transmissible<C>(&self) -> Vec<(Typed<C>, Typed<C>)> {
vec![
(Typed::Str("maxTurnRate".into()), Typed::Float(self.max_turn_rate)),
]
}
}
pub struct MovementData {
pub speed_boost: Option<f32>,
pub max_carry_mass: Option<f32>,
pub horizontal_top_speed: Option<f32>,
pub vertical_top_speed: Option<f32>,
pub specifics: MovementSpecificData,
}
impl MovementData {
pub fn as_transmissible<C>(&self) -> Typed<C> {
let mut out = Vec::new();
self.speed_boost.map(|x| out.push((Typed::Str("speedBoost".into()), Typed::Float(x))));
self.max_carry_mass.map(|x| out.push((Typed::Str("maxCarryMass".into()), Typed::Float(x))));
self.horizontal_top_speed.map(|x| out.push((Typed::Str("horizontalTopSpeed".into()), Typed::Float(x))));
self.vertical_top_speed.map(|x| out.push((Typed::Str("verticalTopSpeed".into()), Typed::Float(x))));
out.append(&mut self.specifics.as_transmissible());
Typed::Dict(Dict {
key_ty: TypePrefix::Str, // str
val_ty: TypePrefix::Any, // any
items: out.into(),
})
}
}
pub enum MovementSpecificData {
Wheel(WheelData),
Hover(HoverData),
Wing(AerofoilData),
Rudder(AerofoilData), // same as wing
Thruster(ThrusterData),
Propeller(ThrusterData), // same as thruster
InsectLeg(InsectLegData),
MechLeg(MechLegData),
SprinterLeg(MechLegData), // same as mech leg
TankTrack(TankTrackData),
Rotor(RotorData),
Ski,
}
impl MovementSpecificData {
pub fn as_transmissible<C>(&self) -> Vec<(Typed<C>, Typed<C>)> {
match self {
Self::Wheel(x) => x.as_transmissible(),
Self::Hover(x) => x.as_transmissible(),
Self::Wing(x) => x.as_transmissible(),
Self::Rudder(x) => x.as_transmissible(),
Self::Thruster(x) => x.as_transmissible(),
Self::Propeller(x) => x.as_transmissible(),
Self::InsectLeg(x) => x.as_transmissible(),
Self::MechLeg(x) => x.as_transmissible(),
Self::SprinterLeg(x) => x.as_transmissible(),
Self::TankTrack(x) => x.as_transmissible(),
Self::Rotor(x) => x.as_transmissible(),
Self::Ski => Vec::default(),
}
}
}
pub struct WheelData {
pub steering_speed_light: f32,
pub steering_speed_heavy: f32,
pub steering_force_multiplier_light: f32,
pub steering_force_multiplier_heavy: f32,
pub lateral_acceleration_light: f32,
pub lateral_acceleration_heavy: f32,
pub time_to_max_acceleration_light: f32,
pub time_to_max_acceleration_heavy: f32,
pub brake_force_light: f32,
pub brake_force_heavy: f32,
}
impl WheelData {
pub fn as_transmissible<C>(&self) -> Vec<(Typed<C>, Typed<C>)> {
vec![
(Typed::Str("steeringSpeedLight".into()), Typed::Float(self.steering_speed_light)),
(Typed::Str("steeringSpeedHeavy".into()), Typed::Float(self.steering_speed_heavy)),
(Typed::Str("steeringForceMultiplierLight".into()), Typed::Float(self.steering_force_multiplier_light)),
(Typed::Str("steeringForceMultiplierHeavy".into()), Typed::Float(self.steering_force_multiplier_heavy)),
(Typed::Str("lateralAccelerationLight".into()), Typed::Float(self.lateral_acceleration_light)),
(Typed::Str("lateralAccelerationHeavy".into()), Typed::Float(self.lateral_acceleration_heavy)),
(Typed::Str("timeToMaxAccelerationLight".into()), Typed::Float(self.time_to_max_acceleration_light)),
(Typed::Str("timeToMaxAccelerationHeavy".into()), Typed::Float(self.time_to_max_acceleration_heavy)),
(Typed::Str("brakeForceLight".into()), Typed::Float(self.brake_force_light)),
(Typed::Str("brakeForceHeavy".into()), Typed::Float(self.brake_force_heavy)),
]
}
}
pub struct HoverData {
pub max_hover_height_light: f32,
pub max_hover_height_heavy: f32,
pub height_change_speed_light: f32,
pub height_change_speed_heavy: f32,
pub turn_torque_light: f32,
pub turn_torque_heavy: f32,
pub acceleration_light: f32,
pub acceleration_heavy: f32,
pub max_angular_velocity_light: f32,
pub max_angular_velocity_heavy: f32,
pub lateral_damping_light: f32,
pub lateral_damping_heavy: f32,
}
impl HoverData {
pub fn as_transmissible<C>(&self) -> Vec<(Typed<C>, Typed<C>)> {
vec![
(Typed::Str("maxHoverHeightLight".into()), Typed::Float(self.max_hover_height_light)),
(Typed::Str("maxHoverHeightHeavy".into()), Typed::Float(self.max_hover_height_heavy)),
(Typed::Str("heightChangeSpeedLight".into()), Typed::Float(self.height_change_speed_light)),
(Typed::Str("heightChangeSpeedHeavy".into()), Typed::Float(self.height_change_speed_heavy)),
(Typed::Str("turnTorqueLight".into()), Typed::Float(self.turn_torque_light)),
(Typed::Str("turnTorqueHeavy".into()), Typed::Float(self.turn_torque_heavy)),
(Typed::Str("accelerationLight".into()), Typed::Float(self.acceleration_light)),
(Typed::Str("accelerationHeavy".into()), Typed::Float(self.acceleration_heavy)),
(Typed::Str("maxAngularVelocityLight".into()), Typed::Float(self.max_angular_velocity_light)),
(Typed::Str("maxAngularVelocityHeavy".into()), Typed::Float(self.max_angular_velocity_heavy)),
(Typed::Str("lateralDampingLight".into()), Typed::Float(self.lateral_damping_light)),
(Typed::Str("lateralDampingHeavy".into()), Typed::Float(self.lateral_damping_heavy)),
]
}
}
pub struct AerofoilData {
pub barrel_speed_light: f32,
pub barrel_speed_heavy: f32,
pub bank_speed_light: f32,
pub bank_speed_heavy: f32,
pub elevation_speed_light: f32,
pub elevation_speed_heavy: f32,
pub rudder_speed_light: f32,
pub rudder_speed_heavy: f32,
pub thrust_light: f32,
pub thrust_heavy: f32,
pub vtol_velocity_light: f32,
pub vtol_velocity_heavy: f32,
}
impl AerofoilData {
pub fn as_transmissible<C>(&self) -> Vec<(Typed<C>, Typed<C>)> {
vec![
(Typed::Str("barrelSpeedLight".into()), Typed::Float(self.barrel_speed_light)),
(Typed::Str("barrelSpeedHeavy".into()), Typed::Float(self.barrel_speed_heavy)),
(Typed::Str("bankSpeedLight".into()), Typed::Float(self.bank_speed_light)),
(Typed::Str("bankSpeedHeavy".into()), Typed::Float(self.bank_speed_heavy)),
(Typed::Str("elevationSpeedLight".into()), Typed::Float(self.elevation_speed_light)),
(Typed::Str("elevationSpeedHeavy".into()), Typed::Float(self.elevation_speed_heavy)),
(Typed::Str("rudderSpeedLight".into()), Typed::Float(self.rudder_speed_light)),
(Typed::Str("rudderSpeedHeavy".into()), Typed::Float(self.rudder_speed_heavy)),
(Typed::Str("thrustLight".into()), Typed::Float(self.thrust_light)),
(Typed::Str("thrustHeavy".into()), Typed::Float(self.thrust_heavy)),
(Typed::Str("vtolVelocityLight".into()), Typed::Float(self.vtol_velocity_light)),
(Typed::Str("vtolVelocityHeavy".into()), Typed::Float(self.vtol_velocity_heavy)),
]
}
}
pub struct ThrusterData {
pub acceleration_delay_light: f32,
pub acceleration_delay_heavy: f32,
}
impl ThrusterData {
pub fn as_transmissible<C>(&self) -> Vec<(Typed<C>, Typed<C>)> {
vec![
(Typed::Str("accelerationDelayLight".into()), Typed::Float(self.acceleration_delay_light)),
(Typed::Str("accelerationDelayHeavy".into()), Typed::Float(self.acceleration_delay_heavy)),
]
}
}
pub struct InsectLegData {
pub ideal_height_light: f32,
pub ideal_height_heavy: f32,
pub ideal_crouching_height_light: f32,
pub ideal_crouching_height_heavy: f32,
pub ideal_height_range_light: f32,
pub ideal_height_range_heavy: f32,
pub jump_height_light: f32,
pub jump_height_heavy: f32,
pub max_upwards_force_light: f32,
pub max_upwards_force_heavy: f32,
pub max_lateral_force_light: f32,
pub max_lateral_force_heavy: f32,
pub max_turning_force_light: f32,
pub max_turning_force_heavy: f32,
pub max_damping_force_light: f32,
pub max_damping_force_heavy: f32,
pub max_stopped_force_light: f32,
pub max_stopped_force_heavy: f32,
pub max_new_stopped_force_light: f32,
pub max_new_stopped_force_heavy: f32,
pub upwards_damping_force_light: f32,
pub upwards_damping_force_heavy: f32,
pub lateral_damp_force_light: f32,
pub lateral_damp_force_heavy: f32,
pub swagger_force_light: f32,
pub swagger_force_heavy: f32,
}
impl InsectLegData {
pub fn as_transmissible<C>(&self) -> Vec<(Typed<C>, Typed<C>)> {
vec![
(Typed::Str("idealHeightLight".into()), Typed::Float(self.ideal_height_light)),
(Typed::Str("idealHeightHeavy".into()), Typed::Float(self.ideal_height_heavy)),
(Typed::Str("idealCrouchingHeightLight".into()), Typed::Float(self.ideal_crouching_height_light)),
(Typed::Str("idealCrouchingHeightHeavy".into()), Typed::Float(self.ideal_crouching_height_heavy)),
(Typed::Str("idealHeightRangeLight".into()), Typed::Float(self.ideal_height_range_light)),
(Typed::Str("idealHeightRangeHeavy".into()), Typed::Float(self.ideal_height_range_heavy)),
(Typed::Str("jumpHeightLight".into()), Typed::Float(self.jump_height_light)),
(Typed::Str("jumpHeightHeavy".into()), Typed::Float(self.jump_height_heavy)),
(Typed::Str("maxUpwardsForceLight".into()), Typed::Float(self.max_upwards_force_light)),
(Typed::Str("maxUpwardsForceHeavy".into()), Typed::Float(self.max_upwards_force_heavy)),
(Typed::Str("maxLateralForceLight".into()), Typed::Float(self.max_lateral_force_light)),
(Typed::Str("maxLateralForceHeavy".into()), Typed::Float(self.max_lateral_force_heavy)),
(Typed::Str("maxTurningForceLight".into()), Typed::Float(self.max_turning_force_light)),
(Typed::Str("maxTurningForceHeavy".into()), Typed::Float(self.max_turning_force_heavy)),
(Typed::Str("maxDampingForceLight".into()), Typed::Float(self.max_damping_force_light)),
(Typed::Str("maxDampingForceHeavy".into()), Typed::Float(self.max_damping_force_heavy)),
(Typed::Str("maxStoppedForceLight".into()), Typed::Float(self.max_stopped_force_light)),
(Typed::Str("maxStoppedForceHeavy".into()), Typed::Float(self.max_stopped_force_heavy)),
(Typed::Str("maxNewStoppedForceLight".into()), Typed::Float(self.max_new_stopped_force_light)),
(Typed::Str("maxNewStoppedForceHeavy".into()), Typed::Float(self.max_new_stopped_force_heavy)),
(Typed::Str("upwardsDampingForceLight".into()), Typed::Float(self.upwards_damping_force_light)),
(Typed::Str("upwardsDampingForceHeavy".into()), Typed::Float(self.upwards_damping_force_heavy)),
(Typed::Str("lateralDampForceLight".into()), Typed::Float(self.lateral_damp_force_light)),
(Typed::Str("lateralDampForceHeavy".into()), Typed::Float(self.lateral_damp_force_heavy)),
(Typed::Str("swaggerForceLight".into()), Typed::Float(self.swagger_force_light)),
(Typed::Str("swaggerForceHeavy".into()), Typed::Float(self.swagger_force_heavy)),
]
}
}
pub struct MechLegData {
pub time_grounded_after_jump_light: f32,
pub time_grounded_after_jump_heavy: f32,
pub jump_height_light: f32,
pub jump_height_heavy: f32,
pub turn_acceleration_light: f32,
pub turn_acceleration_heavy: f32,
pub legacy_turn_acceleration_light: f32,
pub legacy_turn_acceleration_heavy: f32,
pub long_jump_speed_scale_light: f32,
pub long_jump_speed_scale_heavy: f32,
pub max_lateral_force_light: f32,
pub max_lateral_force_heavy: f32,
pub max_damping_force_light: f32,
pub max_damping_force_heavy: f32,
}
impl MechLegData {
pub fn as_transmissible<C>(&self) -> Vec<(Typed<C>, Typed<C>)> {
vec![
(Typed::Str("timeGroundedAfterJumpLight".into()), Typed::Float(self.time_grounded_after_jump_light)),
(Typed::Str("timeGroundedAfterJumpHeavy".into()), Typed::Float(self.time_grounded_after_jump_heavy)),
(Typed::Str("jumpHeightLight".into()), Typed::Float(self.jump_height_light)),
(Typed::Str("jumpHeightHeavy".into()), Typed::Float(self.jump_height_heavy)),
(Typed::Str("turnAccelerationLight".into()), Typed::Float(self.turn_acceleration_light)),
(Typed::Str("turnAccelerationHeavy".into()), Typed::Float(self.turn_acceleration_heavy)),
(Typed::Str("legacyTurnAccelerationLight".into()), Typed::Float(self.legacy_turn_acceleration_light)),
(Typed::Str("legacyTurnAccelerationHeavy".into()), Typed::Float(self.legacy_turn_acceleration_heavy)),
(Typed::Str("longJumpSpeedScaleLight".into()), Typed::Float(self.long_jump_speed_scale_light)),
(Typed::Str("longJumpSpeedScaleHeavy".into()), Typed::Float(self.long_jump_speed_scale_heavy)),
(Typed::Str("maxLateralForceLight".into()), Typed::Float(self.max_lateral_force_light)),
(Typed::Str("maxLateralForceHeavy".into()), Typed::Float(self.max_lateral_force_heavy)),
(Typed::Str("maxDampingForceLight".into()), Typed::Float(self.max_damping_force_light)),
(Typed::Str("maxDampingForceHeavy".into()), Typed::Float(self.max_damping_force_heavy)),
]
}
}
pub struct TankTrackData {
pub max_turn_rate_moving_light: f32,
pub max_turn_rate_moving_heavy: f32,
pub max_turn_rate_stopped_light: f32,
pub max_turn_rate_stopped_heavy: f32,
pub turn_acceleration_light: f32,
pub turn_acceleration_heavy: f32,
pub lateral_acceleration_light: f32,
pub lateral_acceleration_heavy: f32,
}
impl TankTrackData {
pub fn as_transmissible<C>(&self) -> Vec<(Typed<C>, Typed<C>)> {
vec![
(Typed::Str("maxTurnRateMovingLight".into()), Typed::Float(self.max_turn_rate_moving_light)),
(Typed::Str("maxTurnRateMovingHeavy".into()), Typed::Float(self.max_turn_rate_moving_heavy)),
(Typed::Str("maxTurnRateStoppedLight".into()), Typed::Float(self.max_turn_rate_stopped_light)),
(Typed::Str("maxTurnRateStoppedHeavy".into()), Typed::Float(self.max_turn_rate_stopped_heavy)),
(Typed::Str("turnAccelerationLight".into()), Typed::Float(self.turn_acceleration_light)),
(Typed::Str("turnAccelerationHeavy".into()), Typed::Float(self.turn_acceleration_heavy)),
(Typed::Str("lateralAccelerationLight".into()), Typed::Float(self.lateral_acceleration_light)),
(Typed::Str("lateralAccelerationHeavy".into()), Typed::Float(self.lateral_acceleration_heavy)),
]
}
}
pub struct RotorData {
pub height_acceleration_light: f32,
pub height_acceleration_heavy: f32,
pub strafe_acceleration_light: f32,
pub strafe_acceleration_heavy: f32,
pub turn_acceleration_light: f32,
pub turn_acceleration_heavy: f32,
pub height_max_change_speed_light: f32,
pub height_max_change_speed_heavy: f32,
pub level_acceleration_light: f32,
pub level_acceleration_heavy: f32,
}
impl RotorData {
pub fn as_transmissible<C>(&self) -> Vec<(Typed<C>, Typed<C>)> {
vec![
(Typed::Str("heightAccelerationLight".into()), Typed::Float(self.height_acceleration_light)),
(Typed::Str("heightAccelerationHeavy".into()), Typed::Float(self.height_acceleration_heavy)),
(Typed::Str("strafeAccelerationLight".into()), Typed::Float(self.strafe_acceleration_light)),
(Typed::Str("strafeAccelerationHeavy".into()), Typed::Float(self.strafe_acceleration_heavy)),
(Typed::Str("turnAccelerationLight".into()), Typed::Float(self.turn_acceleration_light)),
(Typed::Str("turnAccelerationHeavy".into()), Typed::Float(self.turn_acceleration_heavy)),
(Typed::Str("heightMaxChangeSpeedLight".into()), Typed::Float(self.height_max_change_speed_light)),
(Typed::Str("heightMaxChangeSpeedHeavy".into()), Typed::Float(self.height_max_change_speed_heavy)),
(Typed::Str("levelAccelerationLight".into()), Typed::Float(self.level_acceleration_light)),
(Typed::Str("levelAccelerationHeavy".into()), Typed::Float(self.level_acceleration_heavy)),
]
}
}

View File

@@ -0,0 +1,77 @@
use polariton::operation::Typed;
pub struct PlayerData {
pub name: String,
pub display_name: String,
pub mastery: i32,
pub tier: i32,
pub robot_name: String,
pub robot_map: Vec<u8>,
// -- unused i32 here --
pub team: i32,
pub has_premium: bool,
pub robot_uuid: String,
pub cpu: i32,
pub weapon_order: Vec<i32>,
pub colour_map: Vec<u8>,
pub is_ai: bool,
pub spawn_effect: String,
pub death_effect: String,
pub player_rank: i32,
pub weapon_rank: std::collections::HashMap<i32, i32>,
}
impl PlayerData {
fn dump(&self, writer: &mut dyn std::io::Write) -> std::io::Result<usize> {
let mut total_len = super::write_str_for_binreader(&self.name, writer)?;
total_len += super::write_str_for_binreader(&self.display_name, writer)?;
writer.write_all(&self.mastery.to_le_bytes())?;
writer.write_all(&self.tier.to_le_bytes())?;
total_len += super::write_str_for_binreader(&self.robot_name, writer)?;
writer.write_all(&(self.robot_map.len() as i32).to_le_bytes())?;
writer.write_all(&self.robot_map)?;
writer.write_all(&[0xDE, 0xAD, 0xBE, 0xEF])?;
writer.write_all(&self.team.to_le_bytes())?;
writer.write_all(&[self.has_premium as u8])?;
total_len += super::write_str_for_binreader(&self.robot_uuid, writer)?;
writer.write_all(&self.cpu.to_le_bytes())?;
writer.write_all(&(self.weapon_order.len() as i32).to_le_bytes())?;
for weapon_key in self.weapon_order.iter() {
writer.write_all(&weapon_key.to_le_bytes())?;
}
writer.write_all(&(self.colour_map.len() as i32).to_le_bytes())?;
writer.write_all(&self.colour_map)?;
writer.write_all(&[self.is_ai as u8])?;
total_len += super::write_str_for_binreader(&self.spawn_effect, writer)?;
total_len += super::write_str_for_binreader(&self.death_effect, writer)?;
writer.write_all(&self.player_rank.to_le_bytes())?;
writer.write_all(&(self.weapon_rank.len() as i32).to_le_bytes())?;
for (key, val) in self.weapon_rank.iter() {
writer.write_all(&key.to_le_bytes())?;
writer.write_all(&val.to_le_bytes())?;
}
Ok(42 + self.robot_map.len() + (self.weapon_order.len() * 4) + self.colour_map.len() + (self.weapon_rank.len() * 8) + total_len)
}
}
pub struct PlayerDatas {
pub players: Vec<PlayerData>,
}
impl PlayerDatas {
fn dump(&self, writer: &mut dyn std::io::Write) -> std::io::Result<usize> {
writer.write_all(&(self.players.len() as i32).to_le_bytes())?;
let mut total_len = 4;
for data in self.players.iter() {
total_len += data.dump(writer)?;
}
Ok(total_len)
}
pub fn as_transmissible<C>(&self) -> Typed<C> {
let mut buf = Vec::new();
let write_size = self.dump(&mut std::io::Cursor::new(&mut buf)).unwrap();
log::debug!("PlayerDatas serialized to {} bytes: {:?}", write_size, buf);
Typed::Bytes(buf.into())
}
}

View File

@@ -0,0 +1,32 @@
use polariton::{operation::{Arr, Typed}, serdes::TypePrefix};
pub struct TechTreeNode {
pub main_cube_id: i32, // hex
pub position_x: i32,
pub position_y: i32,
pub is_unlocked: bool,
pub is_unlockable: bool,
pub tech_points: u32,
pub neighbours: Vec<i32>, // cube IDs, hex
}
impl TechTreeNode {
pub fn as_transmissible<C>(&self) -> Typed<C> {
Typed::HashMap(vec![
(Typed::Str("mainCubeId".into()), Typed::Str(hex::encode(self.main_cube_id.to_be_bytes()).into())),
(Typed::Str("positionX".into()), Typed::Int(self.position_x)),
(Typed::Str("positionY".into()), Typed::Int(self.position_y)),
(Typed::Str("isUnlocked".into()), Typed::Bool(self.is_unlocked.into())),
(Typed::Str("isUnlockable".into()), Typed::Bool(self.is_unlockable.into())),
(Typed::Str("tp".into()), Typed::Int(self.tech_points as i32)),
(Typed::Str("neighbours".into()), Typed::Arr(Arr {
ty: TypePrefix::Str, // str
items: self.neighbours.iter().map(|cube_id| Typed::Str(hex::encode(cube_id.to_be_bytes()).into())).collect(),
})),
].into())
}
pub fn as_transmissible_key_val<C>(&self) -> (Typed<C>, Typed<C>) {
(Typed::Str(hex::encode(self.main_cube_id.to_be_bytes()).into()), self.as_transmissible())
}
}

View File

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

View File

@@ -0,0 +1,220 @@
#![allow(dead_code)]
use polariton::operation::Typed;
#[derive(Default)]
pub struct WeaponData {
pub damage_inflicted: Option<i32>,
pub protonium_damage_scale: Option<f32>,
pub projectile_speed: Option<f32>,
pub projectile_range: Option<f32>,
pub base_inaccuracy: Option<f32>,
pub base_air_inaccuracy: Option<f32>,
pub movement_inaccuracy: Option<f32>,
pub movement_max_speed: Option<f32>,
pub movement_min_speed: Option<f32>,
pub gun_rotation_slow: Option<f32>,
pub movement_inaccuracy_decay: Option<f32>,
pub slow_rotation_decay: Option<f32>,
pub quick_rotation_decay: Option<f32>,
pub movement_inaccuracy_recovery: Option<f32>,
pub repeat_fire_inaccuracy_total_degrees: Option<f32>,
pub repeat_fire_inaccuracy_decay: Option<f32>,
pub repeat_fire_innaccuracy_recovery: Option<f32>,
pub fire_instant_accuracy_decay: Option<f32>, // degrees
pub accuracy_non_recover_time: Option<f32>,
pub accuracy_decay: Option<f32>,
pub damage_radius: Option<f32>,
pub plasma_time_to_full_damage: Option<f32>,
pub plasma_starting_radius_scale: Option<f32>,
pub nano_dps: Option<f32>,
pub nano_hps: Option<f32>,
pub tesla_damage: Option<f32>,
pub tesla_charges: Option<f32>,
pub aeroflak_proximity_damage: Option<f32>,
pub aeroflak_damage_radius: Option<f32>,
pub aeroflak_explosion_radius: Option<f32>,
pub aeroflak_ground_clearance: Option<f32>,
pub aeroflak_max_stacks: Option<i32>,
pub aeroflak_damage_per_stack: Option<i32>,
pub aeroflak_stack_expire: Option<f32>,
pub shot_cooldown: Option<f32>,
pub smart_rotation_cooldown: Option<f32>,
pub smart_rotation_cooldown_extra: Option<f32>,
pub smart_rotation_max_stacks: Option<f32>,
pub spin_up_time: Option<f32>,
pub spin_down_time: Option<f32>,
pub spin_initial_cooldown: Option<f32>,
pub group_fire_scales: Vec<f32>,
pub mana_cost: Option<f32>,
pub lock_time: Option<f32>,
pub full_lock_release: Option<f32>,
pub change_lock_time: Option<f32>,
pub max_rotation_speed: Option<f32>,
pub initial_rotation_speed: Option<f32>,
pub rotation_acceleration: Option<f32>,
pub nano_healing_priority_time: Option<f32>,
pub module_range: Option<f32>,
pub shield_lifetime: Option<f32>,
pub teleport_time: Option<f32>,
pub camera_time: Option<f32>,
pub camera_delay: Option<f32>,
pub to_invisible_speed: Option<f32>,
pub to_invisible_duration: Option<f32>,
pub to_visible_duration: Option<f32>,
pub countdown_time: Option<f32>,
pub stun_time: Option<f32>,
pub stun_radius: Option<f32>,
pub effect_duration: Option<f32>,
}
impl WeaponData {
pub fn as_transmissible<C>(&self) -> Typed<C> {
let mut out = Vec::new();
self.damage_inflicted.map(|x| out.push((Typed::Str("damageInflicted".into()), Typed::Int(x))));
self.protonium_damage_scale.map(|x| out.push((Typed::Str("protoniumDamageScale".into()), Typed::Float(x))));
self.projectile_speed.map(|x| out.push((Typed::Str("projectileSpeed".into()), Typed::Float(x))));
self.projectile_range.map(|x| out.push((Typed::Str("projectileRange".into()), Typed::Float(x))));
self.base_inaccuracy.map(|x| out.push((Typed::Str("baseInaccuracy".into()), Typed::Float(x))));
self.base_air_inaccuracy.map(|x| out.push((Typed::Str("baseAirInaccuracy".into()), Typed::Float(x))));
self.movement_inaccuracy.map(|x| out.push((Typed::Str("movementInaccuracy".into()), Typed::Float(x))));
self.movement_max_speed.map(|x| out.push((Typed::Str("movementMaxThresholdSpeed".into()), Typed::Float(x))));
self.movement_min_speed.map(|x| out.push((Typed::Str("movementMinThresholdSpeed".into()), Typed::Float(x))));
self.gun_rotation_slow.map(|x| out.push((Typed::Str("gunRotationThresholdSlow".into()), Typed::Float(x))));
self.movement_inaccuracy_decay.map(|x| out.push((Typed::Str("movementInaccuracyDecayTime".into()), Typed::Float(x))));
self.slow_rotation_decay.map(|x| out.push((Typed::Str("slowRotationInaccuracyDecayTime".into()), Typed::Float(x))));
self.quick_rotation_decay.map(|x| out.push((Typed::Str("quickRotationInaccuracyDecayTime".into()), Typed::Float(x))));
self.movement_inaccuracy_recovery.map(|x| out.push((Typed::Str("movementInaccuracyRecoveryTime".into()), Typed::Float(x))));
self.repeat_fire_inaccuracy_total_degrees.map(|x| out.push((Typed::Str("repeatFireInaccuracyTotalDegrees".into()), Typed::Float(x))));
self.repeat_fire_inaccuracy_decay.map(|x| out.push((Typed::Str("repeatFireInaccuracyDecayTime".into()), Typed::Float(x))));
self.repeat_fire_innaccuracy_recovery.map(|x| out.push((Typed::Str("repeatFireInaccuracyRecoveryTime".into()), Typed::Float(x))));
self.fire_instant_accuracy_decay.map(|x| out.push((Typed::Str("fireInstantAccuracyDecayDegrees".into()), Typed::Float(x)))); // degrees
self.accuracy_non_recover_time.map(|x| out.push((Typed::Str("accuracyNonRecoverTime".into()), Typed::Float(x))));
self.accuracy_decay.map(|x| out.push((Typed::Str("accuracyDecayTime".into()), Typed::Float(x))));
self.damage_radius.map(|x| out.push((Typed::Str("damageRadius".into()), Typed::Float(x))));
self.plasma_time_to_full_damage.map(|x| out.push((Typed::Str("plasmaTimeToFullDamage".into()), Typed::Float(x))));
self.plasma_starting_radius_scale.map(|x| out.push((Typed::Str("plasmaStartingRadiusScale".into()), Typed::Float(x))));
self.nano_dps.map(|x| out.push((Typed::Str("nanoDPS".into()), Typed::Float(x))));
self.nano_hps.map(|x| out.push((Typed::Str("nanoHPS".into()), Typed::Float(x))));
self.tesla_damage.map(|x| out.push((Typed::Str("teslaDamage".into()), Typed::Float(x))));
self.tesla_charges.map(|x| out.push((Typed::Str("teslaCharges".into()), Typed::Float(x))));
self.aeroflak_proximity_damage.map(|x| out.push((Typed::Str("aeroflakProximityDamage".into()), Typed::Float(x))));
self.aeroflak_damage_radius.map(|x| out.push((Typed::Str("aeroflakDamageRadius".into()), Typed::Float(x))));
self.aeroflak_explosion_radius.map(|x| out.push((Typed::Str("aeroflakExplosionRadius".into()), Typed::Float(x))));
self.aeroflak_ground_clearance.map(|x| out.push((Typed::Str("aeroflakGroundClearance".into()), Typed::Float(x))));
self.aeroflak_max_stacks.map(|x| out.push((Typed::Str("aeroflakBuffMaxStacks".into()), Typed::Int(x))));
self.aeroflak_damage_per_stack.map(|x| out.push((Typed::Str("aeroflakBuffDamagePerStack".into()), Typed::Int(x))));
self.aeroflak_stack_expire.map(|x| out.push((Typed::Str("aeroflakBuffTimeToExpire".into()), Typed::Float(x))));
self.shot_cooldown.map(|x| out.push((Typed::Str("cooldownBetweenShots".into()), Typed::Float(x))));
self.smart_rotation_cooldown.map(|x| out.push((Typed::Str("smartRotationCooldown".into()), Typed::Float(x))));
self.smart_rotation_cooldown_extra.map(|x| out.push((Typed::Str("smartRotationExtraCooldownTime".into()), Typed::Float(x))));
self.smart_rotation_max_stacks.map(|x| out.push((Typed::Str("smartRotationMaxStacks".into()), Typed::Float(x))));
self.spin_up_time.map(|x| out.push((Typed::Str("spinUpTime".into()), Typed::Float(x))));
self.spin_down_time.map(|x| out.push((Typed::Str("spinDownTime".into()), Typed::Float(x))));
self.spin_initial_cooldown.map(|x| out.push((Typed::Str("spinInitialCooldown".into()), Typed::Float(x))));
if !self.group_fire_scales.is_empty() {
let typed_arr: Vec<Typed<C>> = self.group_fire_scales.iter().map(|x| Typed::Float(*x)).collect();
out.push((Typed::Str("groupFireScales".into()), Typed::Arr(polariton::operation::Arr {
ty: polariton::serdes::TypePrefix::Float,
items: typed_arr,
})));
}
self.mana_cost.map(|x| out.push((Typed::Str("manaCost".into()), Typed::Float(x))));
self.lock_time.map(|x| out.push((Typed::Str("lockTime".into()), Typed::Float(x))));
self.full_lock_release.map(|x| out.push((Typed::Str("fullLockRelease".into()), Typed::Float(x))));
self.change_lock_time.map(|x| out.push((Typed::Str("changeLockTime".into()), Typed::Float(x))));
self.max_rotation_speed.map(|x| out.push((Typed::Str("maxRotationSpeed".into()), Typed::Float(x))));
self.initial_rotation_speed.map(|x| out.push((Typed::Str("initialRotationSpeed".into()), Typed::Float(x))));
self.rotation_acceleration.map(|x| out.push((Typed::Str("rotationAcceleration".into()), Typed::Float(x))));
self.nano_healing_priority_time.map(|x| out.push((Typed::Str("nanoHealingPriorityTime".into()), Typed::Float(x))));
self.module_range.map(|x| out.push((Typed::Str("moduleRange".into()), Typed::Float(x))));
self.shield_lifetime.map(|x| out.push((Typed::Str("shieldLifetime".into()), Typed::Float(x))));
self.teleport_time.map(|x| out.push((Typed::Str("teleportTime".into()), Typed::Float(x))));
self.camera_time.map(|x| out.push((Typed::Str("cameraTime".into()), Typed::Float(x))));
self.camera_delay.map(|x| out.push((Typed::Str("cameraDelay".into()), Typed::Float(x))));
self.to_invisible_speed.map(|x| out.push((Typed::Str("toInvisibleSpeed".into()), Typed::Float(x))));
self.to_invisible_duration.map(|x| out.push((Typed::Str("toInvisibleDuration".into()), Typed::Float(x))));
self.to_visible_duration.map(|x| out.push((Typed::Str("toVisibleDuration".into()), Typed::Float(x))));
self.countdown_time.map(|x| out.push((Typed::Str("countdownTime".into()), Typed::Float(x))));
self.stun_time.map(|x| out.push((Typed::Str("stunTime".into()), Typed::Float(x))));
self.stun_radius.map(|x| out.push((Typed::Str("stunRadius".into()), Typed::Float(x))));
self.effect_duration.map(|x| out.push((Typed::Str("effectDuration".into()), Typed::Float(x))));
Typed::HashMap(out.into())
}
}
#[repr(u32)]
#[derive(Clone, Copy)]
pub enum ItemCategory {
NoFunction = 0,
Wheel = 1,
Hover = 2,
Wing = 3,
Rudder = 4,
Thruster = 5,
InsectLeg = 6,
MechLeg = 7,
Ski = 8,
TankTrack = 9,
Rotor = 10,
SprinterLeg = 11,
Propeller = 12,
Laser = 100,
Plasma = 200,
Mortar = 250,
Rail = 300,
Nano = 400,
Tesla = 500,
Aeroflak = 600,
Ion = 650,
Seeker = 701,
Chaingun = 750,
ShieldModule = 800,
GhostModule = 801,
BlinkModule = 802,
EmpModule = 803,
WindowmakerModule = 804,
EnergyModule = 900,
}
impl ItemCategory {
pub fn as_str(&self) -> &'static str {
match self {
ItemCategory::NoFunction => "NotAFunctionalItem",
ItemCategory::Wheel => "Wheel",
ItemCategory::Hover => "Hover",
ItemCategory::Wing => "Wing",
ItemCategory::Rudder => "Rudder",
ItemCategory::Thruster => "Thruster",
ItemCategory::InsectLeg => "InsectLeg",
ItemCategory::MechLeg => "MechLeg",
ItemCategory::Ski => "Ski",
ItemCategory::TankTrack => "TankTrack",
ItemCategory::Rotor => "Rotor",
ItemCategory::SprinterLeg => "SprinterLeg",
ItemCategory::Propeller => "Propeller",
ItemCategory::Laser => "Laser",
ItemCategory::Plasma => "Plasma",
ItemCategory::Mortar => "Mortar",
ItemCategory::Rail => "Rail",
ItemCategory::Nano => "Nano",
ItemCategory::Tesla => "Tesla",
ItemCategory::Aeroflak => "Aeroflak",
ItemCategory::Ion => "Ion",
ItemCategory::Seeker => "Seeker",
ItemCategory::Chaingun => "Chaingun",
ItemCategory::ShieldModule => "ShieldModule",
ItemCategory::GhostModule => "GhostModule",
ItemCategory::BlinkModule => "BlinkModule",
ItemCategory::EmpModule => "EmpModule",
ItemCategory::WindowmakerModule => "WindowmakerModule",
ItemCategory::EnergyModule => "EnergyModule",
}
}
pub fn but_bigger(&self) -> i32 {
(*self as i32) * 100_000
}
}

View File

@@ -0,0 +1,29 @@
use polariton::{operation::{Dict, Typed}, serdes::TypePrefix};
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<C>(&self) -> Typed<C> {
Typed::Dict(Dict {
key_ty: TypePrefix::Str, // str
val_ty: TypePrefix::Any, // 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)),
],
})
}
}