From 53f358f73c37e86f4db9e7bd7af309697dc7237e Mon Sep 17 00:00:00 2001 From: troido Date: Mon, 3 Feb 2020 20:16:09 +0100 Subject: only send changed cells, not the whole field each time --- src/systems/makefloor.rs | 6 +-- src/systems/moving.rs | 15 +++++--- src/systems/view.rs | 96 ++++++++++++++++++++++++++++++++---------------- 3 files changed, 77 insertions(+), 40 deletions(-) (limited to 'src/systems') diff --git a/src/systems/makefloor.rs b/src/systems/makefloor.rs index b6fedd9..209d965 100644 --- a/src/systems/makefloor.rs +++ b/src/systems/makefloor.rs @@ -8,7 +8,7 @@ use specs::{ Join }; -use super::super::pos::Pos; +use super::super::components::Position; use super::super::resources::{ Floor @@ -17,11 +17,11 @@ use super::super::resources::{ pub struct MakeFloor; impl <'a> System<'a> for MakeFloor { - type SystemData = (Entities<'a>, Write<'a, Floor>, ReadStorage<'a, Pos>); + type SystemData = (Entities<'a>, Write<'a, Floor>, ReadStorage<'a, Position>); fn run(&mut self, (entities, mut floor, positions): Self::SystemData) { floor.cells.clear(); for (ent, pos) in (&entities, &positions).join() { - floor.cells.entry(*pos).or_insert(Vec::new()).push(ent); + floor.cells.entry(pos.pos).or_insert(Vec::new()).push(ent); } } } diff --git a/src/systems/moving.rs b/src/systems/moving.rs index 38588d5..2ea0650 100644 --- a/src/systems/moving.rs +++ b/src/systems/moving.rs @@ -11,7 +11,8 @@ use super::super::pos::Pos; use super::super::components::{ Controller, - Blocking + Blocking, + Position }; use super::super::controls::{ @@ -27,12 +28,12 @@ use super::super::resources::{ pub struct Move; impl <'a> System<'a> for Move { - type SystemData = (ReadStorage<'a, Controller>, WriteStorage<'a, Pos>, Read<'a, Size>, ReadStorage<'a, Blocking>, Read<'a, Floor>); - fn run(&mut self, (controller, mut pos, size, blocking, floor): Self::SystemData) { - for (controller, pos) in (&controller, &mut pos).join(){ + type SystemData = (ReadStorage<'a, Controller>, WriteStorage<'a, Position>, Read<'a, Size>, ReadStorage<'a, Blocking>, Read<'a, Floor>); + fn run(&mut self, (controllers, mut positions, size, blocking, floor): Self::SystemData) { + for (controller, mut pos) in (&controllers, &mut positions.restrict_mut()).join(){ match &controller.0 { Control::Move(direction) => { - let newpos = (*pos + direction.to_position()).clamp(Pos::new(0, 0), Pos::new(size.width - 1, size.height - 1)); + let newpos = (pos.get_unchecked().pos + direction.to_position()).clamp(Pos::new(0, 0), Pos::new(size.width - 1, size.height - 1)); let mut blocked = false; for ent in floor.cells.get(&newpos).unwrap_or(&Vec::new()) { if blocking.get(*ent).is_some(){ @@ -41,7 +42,9 @@ impl <'a> System<'a> for Move { } } if !blocked { - pos.clone_from(&newpos); + let mut pos_mut = pos.get_mut_unchecked(); + pos_mut.prev = Some(pos_mut.pos); + pos_mut.pos = newpos.clone(); } } _ => {} diff --git a/src/systems/view.rs b/src/systems/view.rs index 209b1a5..b854348 100644 --- a/src/systems/view.rs +++ b/src/systems/view.rs @@ -1,8 +1,14 @@ -use std::collections::HashMap; +use std::collections::{HashMap, HashSet}; use specs::{ + BitSet, + storage::ComponentEvent, + ReaderId, + World, + SystemData, ReadStorage, + WriteStorage, Read, Write, System, @@ -10,39 +16,29 @@ use specs::{ }; use super::super::pos::Pos; - -use super::super::components::{ - Visible, - Played -}; - -use super::super::resources::{ - Size, - Output -}; - -use super::super::worldmessages::{ - WorldMessage, - WorldUpdate, - FieldMessage -}; +use super::super::components::{Visible, Played, Position}; +use super::super::resources::{Size, Output}; +use super::super::worldmessages::{WorldMessage, WorldUpdate, FieldMessage}; +#[derive(Default)] +pub struct View { + reader_id: Option>, + dirty: BitSet +} -pub struct View; impl <'a> System<'a> for View { - type SystemData = (ReadStorage<'a, Pos>, ReadStorage<'a, Visible>, Read<'a, Size>, ReadStorage<'a, Played>, Write<'a, Output>); - fn run(&mut self, (positions, visible, size, players, mut output): Self::SystemData) { - + type SystemData = (ReadStorage<'a, Position>, ReadStorage<'a, Visible>, Read<'a, Size>, WriteStorage<'a, Played>, Write<'a, Output>); + fn run(&mut self, (positions, visible, size, mut players, mut output): Self::SystemData) { let mut cells: HashMap> = HashMap::new(); for (pos, vis) in (&positions, &visible).join(){ - cells.entry(*pos).or_insert(Vec::new()).push(vis.clone()); - cells.get_mut(pos).unwrap().sort_by(|a, b| b.height.partial_cmp(&a.height).unwrap()); + cells.entry(pos.pos).or_insert(Vec::new()).push(vis.clone()); + cells.get_mut(&pos.pos).unwrap().sort_by(|a, b| b.height.partial_cmp(&a.height).unwrap()); } let width = size.width; let height = size.height; - let (values, mapping) = draw_room(cells, (width, height)); + let (values, mapping) = draw_room(cells.clone(), (width, height)); let field = WorldUpdate::Field(FieldMessage{ width, @@ -50,19 +46,57 @@ impl <'a> System<'a> for View { field: values, mapping }); + + + self.dirty.clear(); + { + let events = positions.channel().read(self.reader_id.as_mut().unwrap()); + for event in events { + match event { + ComponentEvent::Modified(id) | ComponentEvent::Inserted(id) | ComponentEvent::Removed(id) => { + self.dirty.add(*id); + } + }; + } + } + let mut changed: HashSet = HashSet::new(); + for (pos, _) in (&positions, &self.dirty).join(){ + changed.insert(pos.pos); + if let Some(prev) = pos.prev{ + changed.insert(prev); + } + } + let has_changed: bool = changed.len() > 0; + let mut changes: Vec<(Pos, Vec)> = Vec::new(); + for pos in changed { + changes.push((pos, cells.get(&pos).unwrap().iter().map(|v| v.sprite.clone()).collect())); + } + let changed_msg = WorldUpdate::Change(changes); + + output.output.clear(); - for (player, pos) in (&players, &positions).join() { - - let message = WorldMessage{updates: vec![ - field.clone(), - WorldUpdate::Pos(*pos) - ]}; + for (mut player, pos) in (&mut players, &positions).join() { + let mut updates: Vec = Vec::new(); + if player.is_new { + updates.push(field.clone()); + } else if has_changed { + updates.push(changed_msg.clone()); + } + updates.push(WorldUpdate::Pos(pos.pos)); + let message = WorldMessage{updates}; output.output.insert(player.name.clone(), message); + player.is_new = false; } } + + fn setup(&mut self, world: &mut World) { + Self::SystemData::setup(world); + self.reader_id = Some( + WriteStorage::::fetch(&world).register_reader() + ); + } } - fn draw_room(cells: HashMap>, (width, height): (i32, i32)) -> (Vec, Vec>){ let size = width * height; -- cgit