From cf9392a33bb99ae581f818d3ddb8be1231521a02 Mon Sep 17 00:00:00 2001 From: Katharina Fey Date: Sat, 6 Feb 2021 19:40:53 +0100 Subject: rstnode: restructure project into workspace and sub-crates --- games/rstnode/rst-core/src/data.rs | 279 +++++++++++++++++++++++++++++++++++++ 1 file changed, 279 insertions(+) create mode 100644 games/rstnode/rst-core/src/data.rs (limited to 'games/rstnode/rst-core/src/data.rs') diff --git a/games/rstnode/rst-core/src/data.rs b/games/rstnode/rst-core/src/data.rs new file mode 100644 index 000000000000..5ce5517c2b07 --- /dev/null +++ b/games/rstnode/rst-core/src/data.rs @@ -0,0 +1,279 @@ +//! Data structures for the game + +use crate::io::Io; +use async_std::sync::Arc; +use rand::seq::SliceRandom; +use rand::thread_rng; +use serde::{Deserialize, Serialize}; +use std::{ + collections::BTreeMap, + sync::atomic::{AtomicBool, AtomicU16, AtomicU32}, +}; + +pub type NodeId = usize; + +/// A node is a computer on the network graph +/// +/// It's owned by a player, and has some upgrade state, as well as +/// base stats. +#[derive(Serialize, Deserialize)] +pub struct Node { + /// Each node has a unique ID by which it's addressed + pub id: NodeId, + /// The current health + pub health: AtomicU32, + /// The max health + pub max_health: AtomicU32, + /// The owner of this node + pub owner: Owner, + /// Upgrade state + pub type_: Upgrade, + /// Number of links on the map + pub links: u8, + /// Active link states + pub link_states: Vec>, + /// Input buffer + #[serde(skip)] + pub buffer: Vec, +} + +pub type LinkId = usize; + +/// A one-to-one link between two nodes +#[derive(Serialize, Deserialize)] +pub struct Link { + /// This link ID + id: LinkId, + /// Node 1 + a: NodeId, + /// Node 2 + b: NodeId, + /// The step length + length: usize, + /// Packets present on this link + #[serde(skip)] + pp: Vec<(Packet, AtomicU32)>, + /// Actual Rx, Tx pair + #[serde(skip)] + io: Io, +} + +pub type PacketId = usize; + +/// A packet going across the network +pub struct Packet { + /// The packet ID + id: PacketId, + /// Declare this packet to be removed + dead: AtomicBool, + /// Each packet is owned by a player + owner: Arc, + /// What type of packet this is + data_: PacketType, +} + +pub type PlayerId = usize; + +/// A player who's having fun +#[derive(Serialize, Deserialize)] +pub struct Player { + /// A unique player ID (per match) + pub id: PlayerId, + /// The player name + pub name: String, + /// Player color + pub color: Color, + /// The player's money + pub money: AtomicU16, +} + +/// Optionally, players can create teams +#[derive(Serialize, Deserialize)] +pub struct Team { + /// Name of the team + name: String, + /// Unified color of the team + color: Color, + /// All team members by their ID + roster: Vec, +} + +/// An RGB color without alpha +#[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +pub struct Color(u8, u8, u8); + +impl Color { + pub fn black() -> Self { + Self(50, 50, 50) + } + + pub fn red() -> Self { + Self(250, 50, 50) + } + + pub fn green() -> Self { + Self(100, 250, 100) + } + + pub fn blue() -> Self { + Self(100, 100, 250) + } + + pub fn teal() -> Self { + Self(150, 250, 250) + } + + pub fn purple() -> Self { + Self(150, 100, 250) + } + + pub fn orange() -> Self { + Self(250, 200, 100) + } + + pub fn yellow() -> Self { + Self(250, 250, 100) + } + + pub fn white() -> Self { + Self(225, 225, 225) + } +} + +pub trait ColorPalette { + /// Create a new color palette + fn palette() -> Self; + /// Get a palette without a certain colour + fn without(&mut self, b: &Color); + /// Mix a color back into the available palette + fn remix(&mut self, new: Color); +} + +impl ColorPalette for Vec { + fn palette() -> Self { + let mut rng = thread_rng(); + let mut pal = vec![ + Color::black(), + Color::red(), + Color::green(), + Color::blue(), + Color::teal(), + Color::purple(), + Color::orange(), + Color::yellow(), + Color::white(), + ]; + pal.shuffle(&mut rng); + pal + } + + /// Drop a colour from the palette + fn without(&mut self, b: &Color) { + if let Some(pos) = self.into_iter().rposition(|a| a == b) { + self.remove(pos); + } + } + + fn remix(&mut self, new: Color) { + let mut rng = thread_rng(); + self.push(new); + self.shuffle(&mut rng); + } +} + +/// Describes ownership state +#[derive(Serialize, Deserialize)] +pub enum Owner { + /// Nobody owns this + Neutral, + /// A player owns this + Player(Player), +} + +/// Encodes upgrade level without numbers +#[derive(Copy, Clone, Serialize, Deserialize)] +pub enum Level { + /// 1 + One, + /// 2 + Two, + /// 3 (wow) + Three, +} + +/// Describes upgrade state +#[derive(Copy, Clone, Serialize, Deserialize)] +pub enum Upgrade { + /// A basic node + Base, + /// Battle (attack/defence) nodes + Guard(Level), + /// These nodes make money + Compute(Level), + /// Good at packet switching + Relay(Level), +} + +/// Possible types of packets +pub enum PacketType { + /// A keepalive packet + /// + /// These are sent by all nodes if their neighbours are either + /// friendly or neutral, and used to keep the network alive. + /// Sending them costs nothing, and when they are received, they + /// yield a small amount of funds, and restoring health of a node. + Ping, + /// A non exploit capture + /// + /// This is a packet that can be sent out by any node (except a + /// switch) to claim a neutral node on the network. The path to + /// the node needs to consist only of friendlies, and if an enemy + /// node processes this type, nothing happens. + Capture, + /// A compute packet + /// + /// The first value is the target compute value, which each + /// compute node adds on to. The second value is the current. If + /// a compute packet passes through a compromised or enemy node, + /// it might subtract from the second value, before palling it on. + Compute { + max: u16, + curr: AtomicU16, + step: u16, + }, + /// A special wrapper packet generated by guards + /// + /// Sometimes, when a hostily attack packet encounters a guard, it + /// manages to capture the attack, and forwards it to a random + /// compute node. If the node manages to handle the packet, + /// without it getting dropped in the meantime), it yields a + /// specified reward, like a computation would. + Payload { inner: Box, reward: u16 }, + /// A reset attack packet + /// + /// When encountering a hostile node, it will make that node drop + /// all packets in it's buffers. + Reset, + /// Cross-node-scripting attack + /// + /// Decreases the strength of a node, also having a small chance + /// of spawning a new packet into a random output buffer. When + /// applied to a neutral node, it makes capturing nodes go faster. + CNS, + /// Node-in-the-middle attack + /// + /// Infect the routing behaviour of a node to route all traffic to + /// a specified enemy node instead + Nitm, + /// Virus infection attack + /// + /// Infects a node to capture it's earnings, both active and + /// passive, for a short time, without taking on it's costs. + Virus, + /// A total control exploit + /// + /// This is very hard to do, and a node will basically always + /// resist it, but if successful, transforms the node into a guard + /// node and yields control to the attackinng player. + TakeOver, +} -- cgit v1.2.3