aboutsummaryrefslogtreecommitdiff
path: root/client/src/world
diff options
context:
space:
mode:
authormetamuffin <yvchraiqi@protonmail.com>2022-06-09 09:46:00 +0200
committermetamuffin <yvchraiqi@protonmail.com>2022-06-09 09:46:00 +0200
commit7a0d09e5cd0075e2a0d3db4505d7ec77dff35ae0 (patch)
tree5586745b7a9b871b31512cba9f964dabda4651f0 /client/src/world
downloadtwclient-7a0d09e5cd0075e2a0d3db4505d7ec77dff35ae0.tar
twclient-7a0d09e5cd0075e2a0d3db4505d7ec77dff35ae0.tar.bz2
twclient-7a0d09e5cd0075e2a0d3db4505d7ec77dff35ae0.tar.zst
(reset git)
Diffstat (limited to 'client/src/world')
-rw-r--r--client/src/world/map.rs135
-rw-r--r--client/src/world/mod.rs132
2 files changed, 267 insertions, 0 deletions
diff --git a/client/src/world/map.rs b/client/src/world/map.rs
new file mode 100644
index 0000000..fb67918
--- /dev/null
+++ b/client/src/world/map.rs
@@ -0,0 +1,135 @@
+use ::map as mapfile;
+use anyhow::Error;
+use common::{num::Cast, vec};
+use log::{info, log};
+use ndarray::Array2;
+use std::{
+ collections::{hash_map, HashMap},
+ fs::File,
+ mem,
+};
+
+pub use mapfile::format;
+pub use mapfile::{
+ format::Tile,
+ reader::{self, Color, LayerTilemapType},
+};
+pub const TILE_NUM: u32 = 16;
+
+pub struct Layer {
+ pub color: Color,
+ pub image: Option<usize>,
+ pub tiles: Array2<Tile>,
+ pub kind: LayerTilemapType,
+}
+
+pub struct Map {
+ pub layers: Vec<Layer>,
+ pub tilesets: HashMap<Option<usize>, Array2<Color>>,
+}
+
+impl Map {
+ pub fn empty() -> Self {
+ Self {
+ layers: Vec::new(),
+ tilesets: HashMap::new(),
+ }
+ }
+
+ pub fn load(file: File) -> Result<Self, Error> {
+ info!("loading map");
+ let datafile = datafile::Reader::new(file).unwrap();
+ let mut map = mapfile::Reader::from_datafile(datafile);
+
+ let mut layers = vec![];
+ for group_idx in map.group_indices() {
+ let group = map.group(group_idx).unwrap();
+
+ if group.parallax_x != 100
+ || group.parallax_y != 100
+ || group.offset_x != 0
+ || group.offset_y != 0
+ || group.clipping.is_some()
+ {
+ continue;
+ }
+
+ for layer_idx in group.layer_indices {
+ let layer = map.layer(layer_idx).unwrap();
+
+ let tilemap = if let reader::LayerType::Tilemap(t) = layer.t {
+ t
+ } else {
+ continue;
+ };
+ let normal = if let Some(n) = tilemap.type_.to_normal() {
+ n
+ } else {
+ continue;
+ };
+ let tiles = map.layer_tiles(tilemap.tiles(normal.data)).unwrap();
+ layers.push(Layer {
+ color: normal.color,
+ image: normal.image,
+ kind: tilemap.type_,
+ tiles,
+ });
+ }
+ }
+
+ let mut tilesets = HashMap::new();
+ for layer in &layers {
+ match tilesets.entry(layer.image) {
+ hash_map::Entry::Occupied(_) => {}
+ hash_map::Entry::Vacant(v) => {
+ let data = match layer.image {
+ None => Array2::from_elem(
+ (1, 1),
+ Color {
+ alpha: 255,
+ red: 255,
+ blue: 255,
+ green: 0,
+ },
+ ),
+ Some(image_idx) => {
+ let image = map.image(image_idx).unwrap();
+ let height = image.height.usize();
+ let width = image.width.usize();
+ match image.data {
+ Some(d) => {
+ let data = map.image_data(d).unwrap();
+ if data.len() % mem::size_of::<Color>() != 0 {
+ panic!("image shape invalid");
+ }
+ let data: Vec<Color> = unsafe { vec::transmute(data) };
+ Array2::from_shape_vec((height, width), data).unwrap()
+ }
+ None => {
+ continue;
+ // let image_name = map.image_name(image.name)?;
+ // // WARN? Unknown external image
+ // // WARN! Wrong dimensions
+ // str::from_utf8(&image_name).ok()
+ // .and_then(sanitize)
+ // .map(&mut external_tileset_loader)
+ // .transpose()?
+ // .unwrap_or(None)
+ // .unwrap_or_else(|| Array2::from_elem((1, 1), Color::white()))
+ }
+ }
+ }
+ };
+ v.insert(data);
+ }
+ }
+ }
+
+ info!(
+ "{} layers + {} tilesets loaded",
+ layers.len(),
+ tilesets.len()
+ );
+ Ok(Self { tilesets, layers })
+ }
+}
diff --git a/client/src/world/mod.rs b/client/src/world/mod.rs
new file mode 100644
index 0000000..ae985a6
--- /dev/null
+++ b/client/src/world/mod.rs
@@ -0,0 +1,132 @@
+use gamenet::{
+ enums::{Emote, Team, Weapon},
+ SnapObj,
+};
+
+use self::map::Map;
+use crate::client::{helper::get_map_path, ClientMesgOut};
+use std::{collections::BTreeMap, fs::File};
+
+pub mod map;
+
+pub use gamenet::enums;
+
+#[derive(Debug)]
+pub struct Tee {
+ pub local: bool,
+ pub latency: i32,
+ pub score: i32,
+
+ pub team: Team,
+ pub weapon: Weapon,
+ pub armor: i32,
+ pub ammo: i32,
+ pub emote: Emote,
+ pub attack_tick: i32,
+
+ pub tick: i32,
+ pub angle: i32,
+ pub x: i32,
+ pub y: i32,
+ pub vel_x: i32,
+ pub vel_y: i32,
+ pub hook_x: i32,
+ pub hook_y: i32,
+ pub hook_dx: i32,
+ pub hook_dy: i32,
+ pub hook_player: i32,
+ pub hook_state: i32,
+}
+
+impl Default for Tee {
+ fn default() -> Self {
+ Self {
+ x: Default::default(),
+ y: Default::default(),
+ local: false,
+ team: Team::Spectators,
+ latency: Default::default(),
+ score: Default::default(),
+ weapon: Weapon::Shotgun,
+ armor: Default::default(),
+ ammo: Default::default(),
+ attack_tick: Default::default(),
+ emote: Emote::Normal,
+ tick: Default::default(),
+ angle: Default::default(),
+ vel_x: Default::default(),
+ vel_y: Default::default(),
+ hook_x: Default::default(),
+ hook_y: Default::default(),
+ hook_dx: Default::default(),
+ hook_dy: Default::default(),
+ hook_player: Default::default(),
+ hook_state: Default::default(),
+ }
+ }
+}
+
+pub struct World {
+ pub map: Map,
+ pub tees: BTreeMap<u16, Tee>,
+}
+
+impl World {
+ pub fn new() -> Self {
+ Self {
+ map: Map::empty(),
+ tees: BTreeMap::new(),
+ }
+ }
+
+ pub fn update(&mut self, m: &ClientMesgOut) {
+ match m {
+ ClientMesgOut::MapChange { name, crc } => {
+ let file = File::open(get_map_path(name.as_str(), *crc)).unwrap();
+ self.map = Map::load(file).unwrap();
+ }
+ ClientMesgOut::Snaps(s) => {
+ self.tees.clear();
+ for (id, o) in s {
+ match o {
+ SnapObj::ClientInfo(_o) => {
+ // TODO
+ }
+ SnapObj::PlayerInfo(o) => {
+ let e = self.tees.entry(*id).or_default();
+ e.local = o.local == 1;
+ e.team = o.team;
+ e.latency = o.latency;
+ e.score = o.score;
+ }
+ SnapObj::Character(c) => {
+ let e = self.tees.entry(*id).or_default();
+ e.ammo = c.ammo_count;
+ e.weapon = c.weapon;
+ e.emote = c.emote;
+ e.attack_tick = c.attack_tick;
+
+ e.x = c.character_core.x;
+ e.y = c.character_core.y;
+ e.vel_x = c.character_core.vel_x;
+ e.vel_y = c.character_core.vel_y;
+
+ e.tick = c.character_core.tick;
+ e.hook_x = c.character_core.hook_x;
+ e.hook_y = c.character_core.hook_y;
+ e.hook_player = c.character_core.hooked_player;
+ e.hook_dx = c.character_core.hook_dx;
+ e.hook_dy = c.character_core.hook_dy;
+ e.hook_state = c.character_core.hook_state;
+ }
+ _ => (),
+ }
+ }
+ }
+ }
+ }
+
+ pub fn local_tee(&self) -> Option<&Tee> {
+ self.tees.values().find(|e| e.local)
+ }
+}