pub mod config;
pub mod console;
pub mod database;
mod display;
pub mod net_msg;
pub mod replay;
pub use teehistorian;
pub use twsnap;
pub use display::DisplayChunk;
use crate::console::Command;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use twsnap::time::Instant;
use twsnap::Snap;
use uuid::Uuid;
use vek::Vec2;
#[derive(Clone, Debug, PartialEq, Eq, Default, Serialize, Deserialize)]
#[repr(C)]
pub struct Input {
pub direction: i32,
pub target_x: i32,
pub target_y: i32,
pub jump: i32,
pub fire: i32,
pub hook: i32,
pub player_flags: i32,
pub wanted_weapon: i32,
pub next_weapon: i32,
pub prev_weapon: i32,
}
impl Input {
pub fn new() -> Input {
Input {
direction: 0,
target_x: 0,
target_y: -1,
jump: 0,
fire: 0,
hook: 0,
player_flags: 0,
wanted_weapon: 0,
next_weapon: 0,
prev_weapon: 0,
}
}
fn disallow_target_center(mut self) -> Self {
if self.target_x == 0 && self.target_y == 0 {
self.target_y = -1;
}
self
}
fn count_presses(mut cur: i32, mut prev: i32) -> i32 {
let mut count = 0;
prev &= 63; cur &= 63;
while prev != cur {
prev = (prev + 1) & 63;
if prev & 1 != 0 {
count += 1;
}
}
count
}
pub fn count_weapon_next(&self, prev: &Input) -> i32 {
Input::count_presses(self.next_weapon, prev.next_weapon)
}
pub fn count_weapon_prev(&self, prev: &Input) -> i32 {
Input::count_presses(self.prev_weapon, prev.prev_weapon)
}
pub fn count_weapon_fire(&self, prev: &Input) -> i32 {
Input::count_presses(self.fire, prev.fire)
}
pub fn cursor(&self) -> Vec2<f32> {
Vec2::new(self.target_x as f32, self.target_y as f32)
}
pub fn firing(&self) -> bool {
(self.fire & 1) != 0
}
pub fn spec_cam_active(&self) -> bool {
(self.player_flags & (1 << 5)) != 0
}
}
impl From<[i32; 10]> for Input {
fn from(input: [i32; 10]) -> Self {
Input {
direction: input[0],
target_x: input[1],
target_y: input[2],
jump: input[3],
fire: input[4],
hook: input[5],
player_flags: input[6],
wanted_weapon: input[7],
next_weapon: input[8],
prev_weapon: input[9],
}
.disallow_target_center()
}
}
impl Input {
pub fn add_input_diff(&mut self, input_diff: [i32; 10]) {
self.direction += input_diff[0];
self.target_x += input_diff[1];
self.target_y += input_diff[2];
self.jump += input_diff[3];
self.fire += input_diff[4];
self.hook += input_diff[5];
self.player_flags += input_diff[6];
self.wanted_weapon += input_diff[7];
self.next_weapon += input_diff[8];
self.prev_weapon += input_diff[9];
}
}
pub trait Game {
fn player_join(&mut self, id: u32);
fn player_ready(&mut self, id: u32);
fn player_input(&mut self, id: u32, input: &Input);
fn player_leave(&mut self, id: u32);
fn on_net_msg(&mut self, id: u32, msg: &net_msg::ClNetMessage);
fn on_command(&mut self, id: u32, command: &Command);
fn swap_tees(&mut self, id1: u32, id2: u32);
fn tick(&mut self, cur_time: Instant);
fn is_empty(&self) -> bool;
}
pub trait Snapper {
fn snap(&self, snapshot: &mut Snap);
}
#[derive(Deserialize, Debug)]
pub struct ThHeader {
pub game_uuid: Uuid,
pub server_version: String,
pub prng_description: Option<String>,
pub start_time: String,
pub map_name: String,
pub map_sha256: Option<String>,
pub map_crc: String,
pub map_size: String,
pub version_minor: Option<String>,
pub config: HashMap<String, String>,
pub tuning: HashMap<String, String>,
}
impl ThHeader {
pub fn from_buf(buf: &[u8]) -> Self {
let buf = String::from_utf8_lossy(buf);
serde_json::from_str(&buf).unwrap()
}
}
pub fn normalize(v: Vec2<f32>) -> Vec2<f32> {
let divisor = v.magnitude();
if divisor == 0.0 {
return Vec2::zero();
}
let l = 1.0 / divisor;
v * l
}