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

Add social server and implement all op codes up until chat room connection blocks further requests

This commit is contained in:
NGnius (Graham)
2025-02-23 16:10:21 -05:00
parent d8885d811f
commit 2907376722
76 changed files with 3052 additions and 7 deletions

View File

@@ -0,0 +1,33 @@
#![allow(dead_code)]
#[repr(u8)]
pub enum GameMode {
BattleArena = 0,
SuddenDeath = 1,
Pit = 2,
TestMode = 3,
SinglePlayer = 4,
TeamDeathmatch = 5,
Campaign = 6,
}
impl GameMode {
pub fn as_str(&self) -> &'static str {
match self {
GameMode::BattleArena => "BattleArena",
GameMode::SuddenDeath => "SuddenDeath",
GameMode::Pit => "Pit",
GameMode::TestMode => "TestMode",
GameMode::SinglePlayer => "SinglePlayerTDM",
GameMode::TeamDeathmatch => "TeamDeathmatch",
GameMode::Campaign => "Campaign",
}
}
}
#[repr(u8)]
pub enum MapVisibility {
Good = 0,
Poor = 1,
Bad = 2, // VeryPoor
}

View File

@@ -0,0 +1,93 @@
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,
}
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<MovementCategory>,
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: i32, // enum???
pub control_options: Vec<bool>,
pub mastery_level: i32,
pub bay_skin_id: String,
pub weapon_order: Vec<i32>,
}
impl GarageSlotInfo {
pub fn as_transmissible(&self) -> Typed {
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: 105, // int
items: self.movement_categories.iter().map(|x| Typed::Int((*x as i32) * 100_000)).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)),
(Typed::Str("controlOptions".into()), Typed::Arr(Arr {
ty: 111, // bool
items: self.control_options.iter().map(|&x| Typed::Bool(x.into())).collect(),
})),
(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: 105, // int
items: self.weapon_order.iter().map(|x| Typed::Int(*x)).collect(),
})),
].into())
}
}

View File

@@ -0,0 +1,124 @@
#![allow(dead_code)]
use std::io::Write;
use polariton::operation::Typed;
pub struct ItemShopBundle {
pub sku: String,
pub bundle_name_key: String,
pub sprite: String,
pub is_sprite_full_size: bool,
pub category: ItemShopCategory,
pub currency: CurrencyType, // str
pub price: i32,
pub discount_time: i64, // seconds since unix epoch
pub discount_price: i32,
pub recurrence: ItemShopRecurrence,
pub owns_required_cube: bool,
//pub is_discounted: bool,
pub is_limited_edition: bool,
}
impl ItemShopBundle {
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<usize> {
let sku_bytes = self.sku.as_bytes();
let mut total_len = writer.write(&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(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(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(currency_bytes)?;
total_len += writer.write(&self.price.to_le_bytes())?;
total_len += writer.write(&self.discount_time.to_le_bytes())?;
total_len += writer.write(&self.discount_price.to_le_bytes())?;
total_len += writer.write(&(self.recurrence as i32).to_le_bytes())?;
total_len += writer.write(&[self.owns_required_cube as u8])?;
total_len += writer.write(&(self.category as i32).to_le_bytes())?;
total_len += writer.write(&[self.is_limited_edition as u8])?;
Ok(total_len)
}
pub fn as_transmissible_vec(items: Vec<Self>) -> Typed {
let mut buf = Vec::new();
let mut writer = std::io::Cursor::new(&mut buf);
writer.write(&(items.len() as i32).to_le_bytes()).unwrap();
for item in items.iter() {
item.dump(&mut writer).unwrap();
}
Typed::Bytes(buf.into())
}
}
#[repr(i32)]
#[derive(Copy, Clone)]
pub enum ItemShopCategory {
Cube = 0,
GarageBaySkin = 1,
Bundle = 2,
DeathEffect = 3,
SpawnEffect = 4,
Emotigram = 5,
}
#[repr(i32)]
#[derive(Copy, Clone)]
pub enum ItemShopRecurrence {
Daily = 0,
Weekly = 1,
}
#[repr(i32)]
#[derive(Copy, Clone)]
pub enum CurrencyType {
Robits = 0,
CosmeticCredits = 1,
}
impl CurrencyType {
pub fn as_str(&self) -> &'static str {
match self {
Self::Robits => "Robits",
Self::CosmeticCredits => "CosmeticCredits",
}
}
}
fn encode_7_bit_i32(mut src: i32) -> Vec<u8> {
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
}

View File

@@ -12,3 +12,7 @@ pub mod cpu_limits;
pub mod cosmetic_limits;
pub mod taunts_config;
pub mod customisation_info;
pub mod garage_bay;
pub mod custom_games;
pub mod tech_tree;
pub mod item_shop_bundle;

View File

@@ -0,0 +1,28 @@
use polariton::operation::{Typed, Arr};
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(&self) -> Typed {
Typed::HashMap(vec![
(Typed::Str("mainCubeId".into()), Typed::Str(hex::encode(self.main_cube_id.to_le_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: 115, // str
items: self.neighbours.iter().map(|cube_id| Typed::Str(hex::encode(cube_id.to_le_bytes()).into())).collect(),
})),
].into())
}
}