summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authortroido <troido@protonmail.com>2020-02-03 20:16:09 +0100
committertroido <troido@protonmail.com>2020-02-03 20:16:09 +0100
commit53f358f73c37e86f4db9e7bd7af309697dc7237e (patch)
treed118cdfb10e1519995a92ac0c58db1051c41325d
parent30509956d4274b2565052dc045eec3742a159357 (diff)
only send changed cells, not the whole field each time
-rw-r--r--Cargo.toml1
-rw-r--r--src/assemblages.rs2
-rw-r--r--src/components.rs32
-rw-r--r--src/pos.rs20
-rw-r--r--src/room.rs7
-rw-r--r--src/systems/makefloor.rs6
-rw-r--r--src/systems/moving.rs15
-rw-r--r--src/systems/view.rs96
-rw-r--r--src/worldmessages.rs21
9 files changed, 136 insertions, 64 deletions
diff --git a/Cargo.toml b/Cargo.toml
index 979981d..b2c9889 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -14,3 +14,4 @@ users = "0.8"
specs = { version = "0.15", features = ["specs-derive"] }
rand = "0.7"
serde_json = "1.0"
+serde = { version = "1.0", features = ["derive"] }
diff --git a/src/assemblages.rs b/src/assemblages.rs
index a80e5c9..b43548c 100644
--- a/src/assemblages.rs
+++ b/src/assemblages.rs
@@ -50,7 +50,7 @@ impl Grass {
}
-assemblage!(Player {name: String}; Visible{sprite: "player".to_string(), height: 1.0}, Played{name: name.to_string()});
+assemblage!(Player {name: String}; Visible{sprite: "player".to_string(), height: 1.0}, Played::new(name.to_string()));
impl Player {
pub fn new(name: &str) -> Player {
diff --git a/src/components.rs b/src/components.rs
index 3b17f0c..18de7f0 100644
--- a/src/components.rs
+++ b/src/components.rs
@@ -1,16 +1,38 @@
use specs::{
DenseVecStorage,
+ VecStorage,
+ FlaggedStorage,
Component
};
use super::controls::Control;
+use super::pos::Pos;
-#[derive(Component, Debug, Clone)]
+
+#[derive(Debug, Clone)]
+pub struct Position{
+ pub pos: Pos,
+ pub prev: Option<Pos>
+}
+impl Position {
+ pub fn new(pos: Pos) -> Position {
+ Position{pos, prev: None}
+ }
+}
+
+impl Component for Position {
+ type Storage = FlaggedStorage<Self, VecStorage<Self>>;
+}
+
+#[derive(Debug, Clone)]
pub struct Visible {
pub sprite: String,
pub height: f32
}
+impl Component for Visible {
+ type Storage = FlaggedStorage<Self, VecStorage<Self>>;
+}
#[derive(Component, Debug)]
pub struct Controller(pub Control);
@@ -20,5 +42,11 @@ pub struct Blocking;
#[derive(Component, Debug)]
pub struct Played {
- pub name: String
+ pub name: String,
+ pub is_new: bool
+}
+impl Played {
+ pub fn new(name: String) -> Played {
+ Played{name, is_new: true}
+ }
}
diff --git a/src/pos.rs b/src/pos.rs
index df63570..12c71bb 100644
--- a/src/pos.rs
+++ b/src/pos.rs
@@ -1,18 +1,17 @@
-
use std::ops::Add;
use serde_json::{Value, json};
-use specs::{Component, VecStorage};
+use serde::{Serialize, Serializer, ser::SerializeTuple};
use super::util::{clamp, ToJson};
-#[derive(Component, Debug, Hash, PartialEq, Eq, Clone, Copy)]
-#[storage(VecStorage)]
+#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy)]
pub struct Pos {
pub x: i32,
pub y: i32
}
+
impl Pos {
pub fn new(x: i32, y: i32) -> Pos {
@@ -27,6 +26,19 @@ impl Pos {
}
}
+
+impl Serialize for Pos {
+ fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: Serializer,
+ {
+ let mut tup = serializer.serialize_tuple(2)?;
+ tup.serialize_element(&self.x)?;
+ tup.serialize_element(&self.y)?;
+ tup.end()
+ }
+}
+
impl Add<Pos> for Pos {
type Output = Pos;
diff --git a/src/room.rs b/src/room.rs
index da92d69..8341eba 100644
--- a/src/room.rs
+++ b/src/room.rs
@@ -12,6 +12,7 @@ use specs::{
use super::controls::Action;
use super::pos::Pos;
+use super::components::Position;
use super::assemblages::Assemblage;
use super::worldmessages::WorldMessage;
use super::resources::{
@@ -49,7 +50,7 @@ impl <'a, 'b>Room<'a, 'b> {
.with(MakeFloor, "makefloor", &[])
.with(Move, "move", &["makefloor", "controlinput"])
.with(ClearControllers, "clearcontrollers", &["move"])
- .with(View, "view", &["move"])
+ .with(View::default(), "view", &["move"])
.build();
dispatcher.setup(&mut world);
@@ -69,7 +70,7 @@ impl <'a, 'b>Room<'a, 'b> {
let assemblages = self.world.remove::<NewEntities>().unwrap_or(NewEntities{assemblages: Vec::new()}).assemblages;
self.world.insert(NewEntities{assemblages: Vec::new()});
for (pos, assemblage) in assemblages{
- assemblage.build(self.world.create_entity()).with(pos).build();
+ assemblage.build(self.world.create_entity()).with(Position::new(pos)).build();
}
self.world.maintain();
}
@@ -84,7 +85,7 @@ impl <'a, 'b>Room<'a, 'b> {
}
pub fn add_obj(&mut self, template: &dyn Assemblage, (x, y): (i32, i32)) -> Entity {
- template.build(self.world.create_entity()).with(Pos{x, y}).build()
+ template.build(self.world.create_entity()).with(Position::new(Pos{x, y})).build()
}
}
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<ReaderId<ComponentEvent>>,
+ 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<Pos, Vec<Visible>> = 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<Pos> = 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<String>)> = 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<WorldUpdate> = 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::<Position>::fetch(&world).register_reader()
+ );
+ }
}
-
fn draw_room(cells: HashMap<Pos, Vec<Visible>>, (width, height): (i32, i32)) -> (Vec<usize>, Vec<Vec<String>>){
let size = width * height;
diff --git a/src/worldmessages.rs b/src/worldmessages.rs
index 8feb29f..8d9d8c8 100644
--- a/src/worldmessages.rs
+++ b/src/worldmessages.rs
@@ -1,5 +1,6 @@
use serde_json::{Value, json};
+use serde::Serialize;
use super::util::ToJson;
use super::pos::Pos;
@@ -18,35 +19,27 @@ impl ToJson for WorldMessage {
#[derive(Clone)]
pub enum WorldUpdate {
Field(FieldMessage),
- Pos(Pos)
+ Pos(Pos),
+ Change(Vec<(Pos, Vec<String>)>)
}
impl ToJson for WorldUpdate {
fn to_json(&self) -> Value {
match self {
- WorldUpdate::Field(msg) => Value::Array(vec![Value::String("field".to_string()), msg.to_json()]),
- WorldUpdate::Pos(pos) => Value::Array(vec![Value::String("playerpos".to_string()), pos.to_json()])
+ WorldUpdate::Field(msg) => json!(["field", msg]),
+ WorldUpdate::Pos(pos) => json!(["playerpos", pos]),
+ WorldUpdate::Change(changes) => json!(["changecells", changes])
}
}
}
-#[derive(Clone)]
+#[derive(Clone, Serialize)]
pub struct FieldMessage {
pub width: i32,
pub height: i32,
pub field: Vec<usize>,
pub mapping: Vec<Vec<String>>
}
-impl ToJson for FieldMessage {
- fn to_json(&self) -> Value {
- json!({
- "width": self.width,
- "height": self.height,
- "field": self.field,
- "mapping": self.mapping
- })
- }
-}