Skip to content

Commit

Permalink
Improved communication channel between mio & game loop. Majorly flawe…
Browse files Browse the repository at this point in the history
…d adding players algorithm is major chokepoint now.
  • Loading branch information
Rizato committed Apr 2, 2016
1 parent a325844 commit f8e4851
Show file tree
Hide file tree
Showing 7 changed files with 232 additions and 172 deletions.
142 changes: 71 additions & 71 deletions src/conn/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ use std::cell::RefCell;
use std::fs::File;
use std::io::BufReader;
use std::sync::Arc;
use std::sync::mpsc::Sender;
use std::sync::mpsc::{Sender, Receiver, channel};
use std;

/// This module contains all of the client facing code. It handles all of the MIO stuff, and user
Expand All @@ -53,6 +53,7 @@ use std;
//Setting the server as the first token
pub const SERVER: mio::Token = mio::Token(0);
pub const TIMEOUT: mio::Token = mio::Token(1);

/// enum for the current state of the connection. Not Logged in, Logged in, and Closed.
enum State {
Expand All @@ -79,78 +80,84 @@ pub struct Server {
//Tried removing the Arc here
connections: Slab<Connection>,
games: Arc<RefCell<Game>>,
recv: Receiver<Msg>,
send: Sender<Msg>,
}

impl Server {
/// Declares a new server with a tcp connection
pub fn new(tcp: TcpListener) -> Server {
let slab = Slab::new_starting_at(mio::Token(1), 1024);
let slab = Slab::new_starting_at(mio::Token(2), 1024);
let (s, r) = channel::<Msg>();
Server {
server: tcp,
connections: slab,
games: Arc::new(RefCell::new(Game::new())),
games: Arc::new(RefCell::new(Game::new(s.clone()))),
send: s,
recv: r,
}
}
}

impl mio::Handler for Server {
type Timeout = ();
type Message = Msg;

/// This function is the primary way the gameloop speaks to the clients. It sends a message on
/// the main channel, and this thing reads the message and figures out what to do, and who to send
/// it to.
fn notify(&mut self, event_loop: &mut mio::EventLoop<Server>, msg: Self::Message) {
match msg {
Msg::TextOutput(token, result, message) => {
// Write message
if self.connections.contains(token) {
self.connections[token].write_text_out(result, &message);
}
if self.connections.contains(token) {
self.connections[token].reregister_writable(event_loop);
}
},
Msg::Screen(token, screen) => {
//Write screen
if self.connections.contains(token) {
self.connections[token].write_zipped_screen(screen);
}
if self.connections.contains(token) {
self.connections[token].reregister_writable(event_loop);
}
},
Msg::SendCommand(token, send) => {
//Tell it to send a command
//TODO Revamp this. We should not send this but once.
if self.connections.contains(token) {
self.connections[token].send_command(send);
}
},
Msg::Hp(token, hp) => {
if self.connections.contains(token) {
self.connections[token].write_stat_all(hp, 500, 100, 100, 25, 1000000, 3000000, 6, 10);
}
if self.connections.contains(token) {
self.connections[token].reregister_writable(event_loop);
}
},
Msg::Shout(msg) => {
let mut tokens = vec![];
for t in self.connections.iter() {
if t.token.as_usize() != 0 {
tokens.push(t.token);
type Timeout = mio::Token;
type Message = ();

fn timeout(&mut self, event_loop: &mut mio::EventLoop<Server>, timeout: mio::Token) {
loop {
match self.recv.try_recv() {
Ok(msg) => {
match msg {
Msg::TextOutput(token, result, message) => {
// Write message
if self.connections.contains(token) {
self.connections[token].write_text_out(result, &message);
}
if self.connections.contains(token) {
self.connections[token].reregister_writable(event_loop);
}
},
Msg::Screen(token, screen) => {
//Write screen
if self.connections.contains(token) {
self.connections[token].write_zipped_screen(screen);
}
if self.connections.contains(token) {
self.connections[token].reregister_writable(event_loop);
}
},
Msg::Hp(token, hp) => {
if self.connections.contains(token) {
self.connections[token].write_stat_all(hp, 500, 100, 100, 25, 1000000, 3000000, 6, 10);
}
if self.connections.contains(token) {
self.connections[token].reregister_writable(event_loop);
}
},
Msg::Shout(msg) => {
let mut tokens = vec![];
for t in self.connections.iter() {
if t.token.as_usize() != 0 {
tokens.push(t.token);
}
}
for token in tokens {
self.connections[token].write_text_out(4,&msg);
self.connections[token].reregister_writable(event_loop);
}
},
_ => {
panic!("Oh no!");
}
}
}
for token in tokens {
self.connections[token].write_text_out(4,&msg);
self.connections[token].reregister_writable(event_loop);
}
},
_ => {
panic!("Oh no!");
},
Err(_) => {
break;
},
}
}
//Essentially this is acting as a coroutine to yield so other messages can be handled.
let _ = event_loop.timeout_ms(TIMEOUT, 1);
}

fn ready(&mut self, event_loop: &mut mio::EventLoop<Server>, token: mio::Token, events: mio::EventSet){
Expand All @@ -177,7 +184,7 @@ impl mio::Handler for Server {
println!("Something def fucked up");
//event_loop.shutdown();
},
};
}
},
_ => {
//otherwise, call the server's ready connection.
Expand Down Expand Up @@ -216,7 +223,6 @@ struct Connection {
socket: TcpStream,
token: mio::Token,
to_client_queue: Vec<ByteBuf>,
from_client_queue: Vec<String>,
event_set: mio::EventSet,
state: State,
}
Expand All @@ -229,7 +235,6 @@ impl Connection{
name: "".to_string(),
token: token,
to_client_queue: vec![],
from_client_queue: vec![],
event_set: mio::EventSet::readable(),
state: State::NotLoggedIn,
}
Expand All @@ -245,16 +250,9 @@ impl Connection{
},
}
}

fn send_command(&mut self, send: Sender<Msg>) {
if self.from_client_queue.len() > 0 {
let command = self.from_client_queue.pop().unwrap();
send.send(Msg::Command(self.token.clone(), command));
}
}

fn quit(&mut self, event_loop: &mut mio::EventLoop<Server>) {
let game_loop = self.games.borrow_mut().get_or_create_game_loop("map", event_loop);
let game_loop = self.games.borrow_mut().get_or_create_game_loop("map");
game_loop.borrow_mut().remove(self.token.clone());
}

Expand Down Expand Up @@ -313,10 +311,12 @@ impl Connection{
let mut m = format!("{} shouts: {} ", self.name, msg).to_string();
//Doing this the trivially easy way, just doing a notification for
//that gets pushed to everyone
let send = event_loop.channel();
let send = self.games.borrow_mut().send.clone();
send.send(Msg::Shout(m));
} else {
self.from_client_queue.push(command.to_string());
let game_loop = self.games.borrow_mut().get_or_create_game_loop("map");
game_loop.borrow_mut().send_command(Msg::Command(self.token.clone(),
command.to_string()));
}
n = n - (2 + length);
}
Expand Down Expand Up @@ -449,7 +449,7 @@ impl Connection{
println!("Tiles");
self.reregister_writable(event_loop);
println!("Writable");
let game_loop = self.games.borrow_mut().get_or_create_game_loop("map", event_loop);
let game_loop = self.games.borrow_mut().get_or_create_game_loop("map");
game_loop.borrow_mut().join(self.token.clone(), self.name.clone());
println!("Looped");
//This is here only while it is a single user. Normally, these would be added to the game_loop, not set.
Expand Down
1 change: 1 addition & 0 deletions src/game/characters/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ use game::gamemap::GameMap;
/// deciding what tile to draw.
#[derive(Clone)]
pub enum Direction {
All,
North,
South,
East,
Expand Down
1 change: 1 addition & 0 deletions src/game/characters/projectile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,7 @@ impl Projectile {
Direction::NorthEast => {"NE"},
Direction::SouthWest => {"SW"},
Direction::SouthEast => {"SE"},
_ => {"S"},
};
format!("{}{}1",self.tile, direction)
//format!("{}",self.tile)
Expand Down
75 changes: 33 additions & 42 deletions src/game/gameloop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ use std::thread;
use std::thread::sleep;
use std::time::Duration;
use std::sync::RwLock;
use std::sync::Mutex;
use std::sync::Arc;

use game::gamemap::GameMap;
Expand All @@ -44,16 +45,18 @@ pub struct GameLoop {
//Map with all items & tiles
game_map: Arc<RwLock<GameMap>>,
connections: Arc<RwLock<Vec<mio::Token>>>,
send: mio::Sender<Msg>,
command_queue: Arc<Mutex<Vec<Msg>>>,
to_game_send: Sender<Msg>,
}

impl GameLoop {
///creates a new game loop
pub fn new(mapname : &str, send: mio::Sender<Msg>) -> GameLoop {
pub fn new(mapname : &str, send: Sender<Msg>) -> GameLoop {
let mut gloop = GameLoop {
game_map: Arc::new(RwLock::new(GameMap::new(mapname).unwrap())),
connections: Arc::new(RwLock::new(vec![])),
send: send,
command_queue: Arc::new(Mutex::new(vec![])),
to_game_send: send,
};
gloop.start();
gloop
Expand All @@ -72,41 +75,32 @@ impl GameLoop {
pub fn start(&mut self) {
let game_map = self.game_map.clone();
let connections = self.connections.clone();
let to_mio = self.send.clone();
let commands = self.command_queue.clone();
let to_mio = self.to_game_send.clone();
thread::spawn(move || {
let (send, recv) = channel();
//TODO give this sender to someone.
loop {
let mut threads = vec![];
thread::sleep(Duration::from_millis(20));
println!("Creating conns");
let mutex = connections.read().unwrap();
for connection in mutex.iter(){
let s = send.clone();
let c = connection.clone();
let t = to_mio.clone();
threads.push(thread::spawn(move|| {
let _ = t.send(Msg::SendCommand(c, s));
}));
}
for t in threads {
t.join().unwrap();
}
let mut map = game_map.write().unwrap();
//This can cause DOS by keeping the commands from executing
println!("Reading commands");
'outer: loop {
match recv.try_recv() {
Ok(Msg::Command(token, command)) => {
//println!("{}", command);
&map.push_command(token, command);
},
_ => {
//println!("Nothin.");
break 'outer;
}
}
//Putting this in a scope so that the commands can be repopulated when it is executing.
{
let mut c = commands.lock().unwrap();
for m in c.drain(..) {
match m {
Msg::Command(token, command) => {
//println!("{}", command);
&map.push_command(token.clone(), command.clone());
},
_ => {
//println!("Nothin.");
},
}
}
}
//TODO get these responses in there somehow
let mutex = connections.read().unwrap();
let responses = map.execute(&mutex);
//Cannot seem to decontruct tuples in a loop. Doing the index version instead of
//iterating
Expand All @@ -124,18 +118,11 @@ impl GameLoop {
}
let screen = map.send_portion(conn.clone());
//Need to see response from sender
match to_mio.send(Msg::Screen(conn.clone(), screen.clone())) {
Err(mio::NotifyError::Io(_)) => {
println!("IO");
},
Err(mio::NotifyError::Full(_)) => {
println!("FUll");
},
Err(mio::NotifyError::Closed(_)) => {
println!("Closed");
},
Ok(_) => {
},
match screen {
Some(s) => {
to_mio.send(Msg::Screen(conn.clone(), s));
},
None => {},
}
}
println!("Finished Loop");
Expand All @@ -161,4 +148,8 @@ impl GameLoop {
}
}
}

pub fn send_command(&mut self, message: Msg) {
self.command_queue.lock().unwrap().push(message);
}
}
Loading

0 comments on commit f8e4851

Please sign in to comment.