Merge tag '1.13.0' into develop

1.13.0
This commit is contained in:
ntr 2020-01-31 10:52:17 +10:00
commit 40f3bb5be6
20 changed files with 178 additions and 132 deletions

View File

@ -1 +1 @@
1.12.4 1.13.0

View File

@ -5,6 +5,9 @@ _ntr_
* can't reset password without knowing password =\ * can't reset password without knowing password =\
* hard reload client on version change * hard reload client on version change
decay reflected not applied
black out timer when game finished
* audio * audio
* animation effects * animation effects
* vbox combine / buy / equip etc * vbox combine / buy / equip etc

View File

@ -1,6 +1,6 @@
{ {
"name": "mnml-client", "name": "mnml-client",
"version": "1.12.4", "version": "1.13.0",
"description": "", "description": "",
"main": "index.js", "main": "index.js",
"scripts": { "scripts": {

View File

@ -27,6 +27,3 @@ ssh -q "$TARGET" ls -lah "$CLIENT_DIST_DIR"
echo "restarting mnml service" echo "restarting mnml service"
ssh -q -t "$TARGET" sudo service mnml restart && sleep 1 && systemctl --no-pager status mnml ssh -q -t "$TARGET" sudo service mnml restart && sleep 1 && systemctl --no-pager status mnml
echo "restarting nginx service"
ssh -q -t "$TARGET" sudo service nginx restart && sleep 1 && systemctl --no-pager status nginx

View File

@ -1,6 +1,6 @@
{ {
"name": "mnml-client", "name": "mnml-client",
"version": "1.12.4", "version": "1.13.0",
"description": "", "description": "",
"main": "index.js", "main": "index.js",
"scripts": { "scripts": {

View File

@ -45,7 +45,7 @@ function Controls(args) {
const now = animating ? zero : Date.now(); const now = animating ? zero : Date.now();
const end = Date.parse(game.phase_end); const end = Date.parse(game.phase_end);
const timerPct = game.phase_end const timerPct = game.phase_end || !game.phase == 'Finished'
? ((now - zero) / (end - zero) * 100) ? ((now - zero) / (end - zero) * 100)
: 100; : 100;

View File

@ -316,6 +316,7 @@ function createSocket(events) {
case 'no constructs selected': return events.errorPrompt('select_constructs'); case 'no constructs selected': return events.errorPrompt('select_constructs');
case 'node requirements not met': return events.errorPrompt('complete_nodes'); case 'node requirements not met': return events.errorPrompt('complete_nodes');
case 'construct at max skills (4)': return events.errorPrompt('max_skills'); case 'construct at max skills (4)': return events.errorPrompt('max_skills');
case 'instance missing': return window.location.reload();
default: return errorToast(error); default: return errorToast(error);

View File

@ -1,6 +1,6 @@
[package] [package]
name = "mnml_core" name = "mnml_core"
version = "1.12.4" version = "1.13.0"
authors = ["ntr <ntr@smokestack.io>", "mashy <mashy@mnml.gg>"] authors = ["ntr <ntr@smokestack.io>", "mashy <mashy@mnml.gg>"]
[dependencies] [dependencies]

View File

@ -65,7 +65,7 @@ impl ConstructSkill {
#[derive(Debug,Clone,Copy,PartialEq,Serialize,Deserialize)] #[derive(Debug,Clone,Copy,PartialEq,Serialize,Deserialize)]
pub enum EffectMeta { pub enum EffectMeta {
CastOnHit(Skill), // maybe needs source/target CastOnHit(Skill), // maybe needs source/target
CastTick { source: Uuid, target: Uuid, skill: Skill, speed: usize, amount: usize }, CastTick { source: Uuid, target: Uuid, skill: Skill, speed: usize, amount: usize, id: Uuid },
AddedDamage(usize), AddedDamage(usize),
Multiplier(usize), Multiplier(usize),
} }
@ -100,12 +100,19 @@ impl ConstructEffect {
pub fn get_skill(&self) -> Option<Skill> { pub fn get_skill(&self) -> Option<Skill> {
match self.meta { match self.meta {
Some(EffectMeta::CastTick { source: _, target: _, skill, speed: _, amount: _ }) => Some(skill), Some(EffectMeta::CastTick { source: _, target: _, skill, speed: _, amount: _, id: _ }) => Some(skill),
Some(EffectMeta::CastOnHit(s)) => Some(s), Some(EffectMeta::CastOnHit(s)) => Some(s),
_ => None, _ => None,
} }
} }
pub fn get_tick_id(&self) -> Option<Uuid> {
match self.meta {
Some(EffectMeta::CastTick { source: _, target: _, skill: _, speed: _, amount: _, id }) => Some(id),
_ => None,
}
}
} }
#[derive(Debug,Clone,Copy,PartialEq,Serialize,Deserialize)] #[derive(Debug,Clone,Copy,PartialEq,Serialize,Deserialize)]
@ -561,7 +568,7 @@ impl Construct {
fn tick_damage(&self, effect: Effect) -> usize { fn tick_damage(&self, effect: Effect) -> usize {
match self.effects.iter().find_map(|ce| match ce.effect == effect { match self.effects.iter().find_map(|ce| match ce.effect == effect {
true => match ce.meta { true => match ce.meta {
Some(EffectMeta::CastTick { source: _, target: _, skill: _, speed: _, amount }) => Some(amount), Some(EffectMeta::CastTick { source: _, target: _, skill: _, speed: _, amount, id: _ }) => Some(amount),
_ => None, _ => None,
}, },
false => None, false => None,
@ -1033,8 +1040,6 @@ impl Construct {
} }
pub fn damage_trigger_casts(&mut self, cast: &Cast, event: &Event) -> Vec<Cast> { pub fn damage_trigger_casts(&mut self, cast: &Cast, event: &Event) -> Vec<Cast> {
if self.is_ko() { return vec![] }
match event { match event {
Event::Damage { construct: _, colour, amount: _, mitigation: _, display: _ } => { Event::Damage { construct: _, colour, amount: _, mitigation: _, display: _ } => {
let mut casts = vec![]; let mut casts = vec![];
@ -1049,6 +1054,9 @@ impl Construct {
}; };
} }
// electrocute is a special case, so we only return after we check it when ko
if self.is_ko() { return casts }
if self.affected(Effect::Absorb) { if self.affected(Effect::Absorb) {
let ConstructEffect { effect: _, duration: _, meta } = let ConstructEffect { effect: _, duration: _, meta } =
self.effects.iter().find(|e| e.effect == Effect::Absorb).unwrap(); self.effects.iter().find(|e| e.effect == Effect::Absorb).unwrap();

View File

@ -125,6 +125,12 @@ impl Effect {
return false; return false;
} }
// electrocute always goes off baybee
// even if you are stunned particularly
if [Skill::Electrocute, Skill::ElectrocutePlus, Skill::ElectrocutePlusPlus].contains(&skill) {
return false;
}
match self { match self {
Effect::Stun => true, Effect::Stun => true,
Effect::Banish => true, Effect::Banish => true,

View File

@ -428,8 +428,12 @@ impl Game {
.cloned() .cloned()
.filter_map(|e| e.meta) .filter_map(|e| e.meta)
.filter_map(move |m| match m { .filter_map(move |m| match m {
EffectMeta::CastTick { source, target, skill, speed, amount: _ } => EffectMeta::CastTick { source, target, skill, speed, amount: _, id } =>
Some(Cast::new(source, c.account, target, skill).set_speed(speed)), Some(
Cast::new(source, c.account, target, skill)
.set_speed(speed)
.set_id(id)
),
_ => None, _ => None,
}) })
) )
@ -506,6 +510,20 @@ impl Game {
fn resolve(&mut self, cast: Cast) -> &mut Game { fn resolve(&mut self, cast: Cast) -> &mut Game {
if self.finished() { return self } if self.finished() { return self }
// match tick skills with the effect on the target
// if no match is found the effect must have been removed during this turn
// and the skill should no longer resolve
if cast.skill.is_tick() {
let effect_match = self.construct(cast.target).effects.iter()
.filter_map(|ce| ce.get_tick_id())
.find(|id| cast.id == *id)
.is_some();
if !effect_match {
return self;
}
}
// If the skill is disabled for source nothing else will happen // If the skill is disabled for source nothing else will happen
if let Some(effects) = self.construct(cast.source).disabled(cast.skill) { if let Some(effects) = self.construct(cast.source).disabled(cast.skill) {
self.add_resolution(&cast, &Event::Disable { construct: cast.source, effects }); self.add_resolution(&cast, &Event::Disable { construct: cast.source, effects });
@ -1054,6 +1072,7 @@ mod tests {
.learn(Skill::Block) .learn(Skill::Block)
.learn(Skill::Counter) .learn(Skill::Counter)
.learn(Skill::Siphon) .learn(Skill::Siphon)
.learn(Skill::Purify)
.learn(Skill::Amplify) .learn(Skill::Amplify)
.learn(Skill::Stun) .learn(Skill::Stun)
.learn(Skill::Ruin) .learn(Skill::Ruin)
@ -1069,6 +1088,7 @@ mod tests {
.learn(Skill::Block) .learn(Skill::Block)
.learn(Skill::Counter) .learn(Skill::Counter)
.learn(Skill::Siphon) .learn(Skill::Siphon)
.learn(Skill::Purify)
.learn(Skill::Amplify) .learn(Skill::Amplify)
.learn(Skill::Stun) .learn(Skill::Stun)
.learn(Skill::Block); .learn(Skill::Block);
@ -1874,85 +1894,6 @@ mod tests {
return; return;
} }
// #[test]
// fn tick_removal_test() {
// let mut game = create_test_game();
// let x_player = game.players[0].clone();
// let y_player = game.players[1].clone();
// let x_construct = x_player.constructs[0].clone();
// let y_construct = y_player.constructs[0].clone();
// // make the purify construct super fast so it beats out decay
// game.construct_by_id(y_construct.id).unwrap().speed.force(10000000);
// game.construct_by_id(x_construct.id).unwrap().learn_mut(Skill::Decay);
// while game.construct_by_id(x_construct.id).unwrap().skill_on_cd(Skill::Decay).is_some() {
// game.construct_by_id(x_construct.id).unwrap().reduce_cooldowns();
// }
// game.construct_by_id(x_construct.id).unwrap().learn_mut(Skill::Siphon);
// while game.construct_by_id(x_construct.id).unwrap().skill_on_cd(Skill::Siphon).is_some() {
// game.construct_by_id(x_construct.id).unwrap().reduce_cooldowns();
// }
// game.construct_by_id(y_construct.id).unwrap().learn_mut(Skill::Purify);
// while game.construct_by_id(y_construct.id).unwrap().skill_on_cd(Skill::Purify).is_some() {
// game.construct_by_id(y_construct.id).unwrap().reduce_cooldowns();
// }
// // apply buff
// game.add_skill(x_player.id, x_construct.id, y_construct.id, Skill::Decay).unwrap();
// game.player_ready(x_player.id).unwrap();
// game.player_ready(y_player.id).unwrap();
// game = game.resolve_phase_start();
// assert!(game.construct_by_id(y_construct.id).unwrap().affected(Effect::Decay));
// let Resolution { source: _, target: _, Resolution, stages: _ } = game.Resolutions.last().unwrap().pop().unwrap();
// match Resolution {
// Resolution::Damage { amount: _, skill, mitigation: _, colour: _ } => assert_eq!(skill, Skill::DecayTick),
// _ => panic!("not decay"),
// };
// game.Resolutions.clear();
// // remove
// game.add_skill(y_player.id, y_construct.id, y_construct.id, Skill::Purify).unwrap();
// game.player_ready(x_player.id).unwrap();
// game.player_ready(y_player.id).unwrap();
// game = game.resolve_phase_start();
// while let Some(Resolution { source: _, target: _, Resolution, stages: _ }) = game.Resolutions.last().unwrap().pop() {
// match Resolution {
// Resolution::Damage { amount: _, skill: _, mitigation: _, colour: _ } =>
// panic!("{:?} damage Resolution", Resolution),
// _ => (),
// }
// };
// game.add_skill(y_player.id, x_construct.id, y_construct.id, Skill::Siphon).unwrap();
// game.player_ready(x_player.id).unwrap();
// game.player_ready(y_player.id).unwrap();
// game = game.resolve_phase_start();
// game.Resolutions.clear();
// game.add_skill(y_player.id, y_construct.id, y_construct.id, Skill::Purify).unwrap();
// game.player_ready(x_player.id).unwrap();
// game.player_ready(y_player.id).unwrap();
// game = game.resolve_phase_start();
// while let Some(Resolution { source: _, target: _, Resolution, stages: _ }) = game.Resolutions.last().unwrap().pop() {
// match Resolution {
// Resolution::Damage { amount: _, skill: _, mitigation: _, colour: _ } =>
// panic!("{:#?} {:#?} damage Resolution", game.Resolutions, Resolution),
// _ => (),
// }
// };
// }
#[test] #[test]
fn upkeep_test() { fn upkeep_test() {
let mut game = create_2v2_test_game(); let mut game = create_2v2_test_game();
@ -2269,8 +2210,41 @@ mod tests {
assert!(effect_events == 2); assert!(effect_events == 2);
assert!(electrocute_dmg_events == 1); // second electrocute application deals no damage assert!(electrocute_dmg_events == 1); // second electrocute application deals no damage
}
#[test]
fn electrocute_ko_test() {
let mut game = create_2v2_test_game();
let player_id = game.players[0].id;
let source = game.players[0].constructs[0].id;
let target = game.players[1].constructs[0].id;
game.players[1].constructs[0].blue_life.force(0);
game.players[1].constructs[0].green_life.force(1);
game.resolve(Cast::new(source, player_id, target, Skill::Electrify));
game.resolve(Cast::new(source, player_id, target, Skill::Blast));
let last = game.resolutions.len() - 1;
let resolutions = &game.resolutions[last];
// println!("{:#?}", resolutions);
assert!(resolutions.iter().any(|r| match r.event {
Event::Damage { construct, colour, amount, mitigation: _, display: _ } =>
r.skill == Skill::Electrocute && construct == source && amount > 0 && colour == Colour::Blue,
_ => false,
}));
let effect_events = resolutions.iter().filter(|r| match r.event {
Event::Effect { construct, effect, duration: _, display: _ } =>
construct == source && effect == Effect::Electrocute,
_ => false,
}).count();
// println!("{:?}", effect_events);
assert!(effect_events == 1);
} }
#[test] #[test]
@ -2524,4 +2498,38 @@ mod tests {
assert_eq!(siphon_tick_dmg, siphon_dmg); assert_eq!(siphon_tick_dmg, siphon_dmg);
assert_eq!(siphon_tick_speed, siphon_speed); assert_eq!(siphon_tick_speed, siphon_speed);
} }
#[test]
fn tick_removal_test() {
let mut game = create_test_game();
let player_id = game.players[0].id;
let opponent_id = game.players[1].id;
let source = game.players[0].constructs[0].id;
let target = game.players[1].constructs[0].id;
game.add_skill(player_id, source, target, Skill::Siphon).unwrap();
game.player_ready(player_id).unwrap();
game.player_ready(opponent_id).unwrap();
game = game.resolve_phase_start();
game.add_skill(player_id, source, target, Skill::Purify).unwrap();
game.player_ready(player_id).unwrap();
game.player_ready(opponent_id).unwrap();
game = game.resolve_phase_start();
// println!("{:#?}", game.resolutions);
let last = game.resolutions.len() - 1;
let resolutions = &game.resolutions[last];
// There should be no damage events on the target
assert!(resolutions.iter().any(|r| match r.event {
Event::Damage { construct: _, colour: _, amount: _, mitigation: _, display: _ } => true,
_ => false,
}) == false);
}
} }

View File

@ -41,6 +41,15 @@ impl Cast {
} }
} }
// used for ticks to match
// a cast with an effect
pub fn set_id(self, id: Uuid) -> Cast {
Cast {
id,
..self
}
}
pub fn resolve(self, game: &mut Game) { pub fn resolve(self, game: &mut Game) {
match self.skill { match self.skill {
Skill::Attack => attack(self, game, Attack::Base), Skill::Attack => attack(self, game, Attack::Base),
@ -729,6 +738,13 @@ impl Skill {
pub fn ko_castable(&self) -> bool { pub fn ko_castable(&self) -> bool {
match self { match self {
// electrocute always goes off
Skill::Electrocute|
Skill::ElectrocutePlus |
Skill::ElectrocutePlusPlus |
// ticks happen after death
Skill::ElectrocuteTick | Skill::ElectrocuteTick |
Skill::DecayTick | Skill::DecayTick |
Skill::SiphonTick | Skill::SiphonTick |
@ -1134,7 +1150,7 @@ fn siphon(cast: Cast, game: &mut Game, values: Siphon) {
Action::Effect { Action::Effect {
construct: cast.target, construct: cast.target,
effect: ConstructEffect { effect: Effect::Siphon, duration: values.duration(), meta: effect: ConstructEffect { effect: Effect::Siphon, duration: values.duration(), meta:
Some(EffectMeta::CastTick { source: cast.source, target: cast.target, skill: Skill::SiphonTick, speed: cast.speed, amount }) }, Some(EffectMeta::CastTick { id: Uuid::new_v4(), source: cast.source, target: cast.target, skill: Skill::SiphonTick, speed: cast.speed, amount }) },
} }
); );
@ -1729,7 +1745,7 @@ fn decay(cast: Cast, game: &mut Game, values: Decay) {
Action::Effect { Action::Effect {
construct: cast.target, construct: cast.target,
effect: ConstructEffect { effect: Effect::Decay, duration: values.decay_duration(), meta: effect: ConstructEffect { effect: Effect::Decay, duration: values.decay_duration(), meta:
Some(EffectMeta::CastTick { source: cast.source, target: cast.target, skill: Skill::DecayTick, speed: cast.speed, amount }) }, Some(EffectMeta::CastTick { id: Uuid::new_v4(), source: cast.source, target: cast.target, skill: Skill::DecayTick, speed: cast.speed, amount }) },
} }
); );
@ -1837,7 +1853,7 @@ fn electrocute(cast: Cast, game: &mut Game, values: Electrocute) {
Action::Effect { Action::Effect {
construct: cast.target, construct: cast.target,
effect: ConstructEffect { effect: Effect::Electrocute, duration: values.duration(), meta: effect: ConstructEffect { effect: Effect::Electrocute, duration: values.duration(), meta:
Some(EffectMeta::CastTick { source: cast.source, target: cast.target, skill: Skill::ElectrocuteTick, speed: cast.speed, amount }) }, Some(EffectMeta::CastTick { id: Uuid::new_v4(), source: cast.source, target: cast.target, skill: Skill::ElectrocuteTick, speed: cast.speed, amount }) },
}, },
); );
@ -2362,7 +2378,7 @@ fn triage(cast: Cast, game: &mut Game, values: Triage) {
Action::Effect { Action::Effect {
construct: cast.target, construct: cast.target,
effect: ConstructEffect { effect: Effect::Triage, duration: values.duration(), meta: effect: ConstructEffect { effect: Effect::Triage, duration: values.duration(), meta:
Some(EffectMeta::CastTick { source: cast.source, target: cast.target, skill: Skill::TriageTick, speed: cast.speed, amount }) }, Some(EffectMeta::CastTick { id: Uuid::new_v4(), source: cast.source, target: cast.target, skill: Skill::TriageTick, speed: cast.speed, amount }) },
} }
); );

View File

@ -1,6 +1,6 @@
{ {
"name": "mnml-ops", "name": "mnml-ops",
"version": "1.12.4", "version": "1.13.0",
"description": "", "description": "",
"main": "index.js", "main": "index.js",
"scripts": { "scripts": {

View File

@ -1,6 +1,6 @@
[package] [package]
name = "mnml" name = "mnml"
version = "1.12.4" version = "1.13.0"
authors = ["ntr <ntr@smokestack.io>"] authors = ["ntr <ntr@smokestack.io>"]
[dependencies] [dependencies]

View File

@ -17,7 +17,7 @@ use rpc::RpcMessage;
use warden::{GameEvent}; use warden::{GameEvent};
pub type EventsTx = Sender<Event>; pub type EventsTx = Sender<Event>;
type Id = Uuid; type Id = usize;
// this is pretty heavyweight // this is pretty heavyweight
// but it makes the ergonomics easy // but it makes the ergonomics easy
@ -60,8 +60,13 @@ pub enum Event {
ChatClear(Id, Uuid), ChatClear(Id, Uuid),
} }
// id and account are seperate
// multiple tabs etc can cause the same account to be connected twice
// so even though each client has the same subs etc
// they are treated independently
struct WsClient { struct WsClient {
id: Id, id: Id,
account: Uuid,
tx: Sender<RpcMessage>, tx: Sender<RpcMessage>,
subs: HashSet<Uuid>, subs: HashSet<Uuid>,
chat: Option<(Uuid, String)>, chat: Option<(Uuid, String)>,
@ -103,7 +108,9 @@ impl Events {
Event::Connect(id, account, tx) => { Event::Connect(id, account, tx) => {
info!("connect id={:?} account={:?}", id, account); info!("connect id={:?} account={:?}", id, account);
let client = WsClient { id, let client = WsClient {
id,
account: account.id,
tx, tx,
subs: HashSet::new(), subs: HashSet::new(),
pvp: false, pvp: false,
@ -163,8 +170,8 @@ impl Events {
subs += 1; subs += 1;
let redacted = match msg { let redacted = match msg {
RpcMessage::InstanceState(ref i) => RpcMessage::InstanceState(i.clone().redact(client.id)), RpcMessage::InstanceState(ref i) => RpcMessage::InstanceState(i.clone().redact(client.account)),
RpcMessage::GameState(ref i) => RpcMessage::GameState(i.clone().redact(client.id)), RpcMessage::GameState(ref i) => RpcMessage::GameState(i.clone().redact(client.account)),
_ => msg.clone(), _ => msg.clone(),
}; };
@ -203,7 +210,7 @@ impl Events {
if let Some(opp_req) = match self.clients.iter_mut().find(|(c_id, c)| c.pvp && **c_id != id) { if let Some(opp_req) = match self.clients.iter_mut().find(|(c_id, c)| c.pvp && **c_id != id) {
Some((q_id, q)) => { Some((q_id, q)) => {
q.pvp = false; q.pvp = false;
Some(PvpRequest { id: *q_id, account: q.id, tx: q.tx.clone() }) Some(PvpRequest { id: *q_id, account: q.account, tx: q.tx.clone() })
}, },
None => None, None => None,
} { } {
@ -211,7 +218,7 @@ impl Events {
let c = self.clients.get_mut(&id) let c = self.clients.get_mut(&id)
.ok_or(format_err!("connection not found id={:?}", id))?; .ok_or(format_err!("connection not found id={:?}", id))?;
let player_req = PvpRequest { id: c.id, account: c.id, tx: c.tx.clone() }; let player_req = PvpRequest { id: c.id, account: c.account, tx: c.tx.clone() };
self.warden.send(GameEvent::Match((opp_req, player_req)))?; self.warden.send(GameEvent::Match((opp_req, player_req)))?;
return Ok(()) return Ok(())
@ -221,7 +228,7 @@ impl Events {
let requester = self.clients.get_mut(&id).unwrap(); let requester = self.clients.get_mut(&id).unwrap();
requester.pvp = true; requester.pvp = true;
requester.tx.send(RpcMessage::QueueJoined(()))?; requester.tx.send(RpcMessage::QueueJoined(()))?;
info!("joined game queue id={:?} account={:?}", requester.id, requester.id); info!("joined game queue id={:?} account={:?}", requester.id, requester.account);
return Ok(()); return Ok(());
}, },
@ -231,7 +238,7 @@ impl Events {
.ok_or(format_err!("connection not found id={:?}", id))?; .ok_or(format_err!("connection not found id={:?}", id))?;
let code = names::name().split_whitespace().collect::<Vec<&str>>().join("-"); let code = names::name().split_whitespace().collect::<Vec<&str>>().join("-");
info!("pvp invite request id={:?} account={:?} code={:?}", c.id, c.id, code); info!("pvp invite request id={:?} account={:?} code={:?}", c.id, c.account, code);
c.invite = Some(code.clone()); c.invite = Some(code.clone());
c.tx.send(RpcMessage::Invite(code))?; c.tx.send(RpcMessage::Invite(code))?;
return Ok(()); return Ok(());
@ -250,10 +257,10 @@ impl Events {
Some(ref c) => *c == code, Some(ref c) => *c == code,
None => false, None => false,
}) })
.map(|(_id, c)| PvpRequest { id: c.id, account: c.id, tx: c.tx.clone() }) .map(|(_id, c)| PvpRequest { id: c.id, account: c.account, tx: c.tx.clone() })
.ok_or(format_err!("invite expired code={:?}", code))?; .ok_or(format_err!("invite expired code={:?}", code))?;
let join = PvpRequest { id: c.id, account: c.id, tx: c.tx.clone() }; let join = PvpRequest { id: c.id, account: c.account, tx: c.tx.clone() };
self.warden.send(GameEvent::Match((join, inv)))?; self.warden.send(GameEvent::Match((join, inv)))?;
return Ok(()); return Ok(());
@ -276,7 +283,7 @@ impl Events {
c.pvp = false; c.pvp = false;
c.tx.send(RpcMessage::QueueLeft(()))?; c.tx.send(RpcMessage::QueueLeft(()))?;
info!("left game queue id={:?} account={:?}", c.id, c.id); info!("left game queue id={:?} account={:?}", c.id, c.account);
return Ok(()); return Ok(());
}, },
@ -307,7 +314,7 @@ impl Events {
Some(ref chat) => chat.0 == instance, Some(ref chat) => chat.0 == instance,
None => false, None => false,
}) })
.map(|(_id, c)| (c.id, c.chat.clone().unwrap().1)) .map(|(_id, c)| (c.account, c.chat.clone().unwrap().1))
.collect(); .collect();
return self.event(Event::Push(instance, RpcMessage::InstanceChat(chat_state))); return self.event(Event::Push(instance, RpcMessage::InstanceChat(chat_state)));
@ -326,7 +333,7 @@ impl Events {
Some(ref chat) => chat.0 == instance, Some(ref chat) => chat.0 == instance,
None => false, None => false,
}) })
.map(|(_id, c)| (c.id, c.chat.clone().unwrap().1)) .map(|(_id, c)| (c.account, c.chat.clone().unwrap().1))
.collect(); .collect();
return self.event(Event::Push(instance, RpcMessage::InstanceChat(chat_state))); return self.event(Event::Push(instance, RpcMessage::InstanceChat(chat_state)));

View File

@ -109,6 +109,7 @@ pub fn start() {
#[cfg(unix)] #[cfg(unix)]
setup_logger().unwrap(); setup_logger().unwrap();
dotenv::from_path(Path::new("/etc/mnml/gs.conf")).ok(); dotenv::from_path(Path::new("/etc/mnml/gs.conf")).ok();
info!("starting server");
let pool = pg::create_pool(); let pool = pg::create_pool();
let http_pool = pool.clone(); let http_pool = pool.clone();

View File

@ -248,8 +248,8 @@ pub fn set(tx: &mut Transaction, account: Uuid, email: &String) -> Result<(Uuid,
let existing = tx.query(select_query, &[&id])?; let existing = tx.query(select_query, &[&id])?;
let result = match existing.iter().next() { let result = match existing.iter().next() {
Some(_) => tx.query(insert_query, &[&id, &account, &email, &confirm_token, &recover_token])?, Some(_) => tx.query(update_query, &[&email, &confirm_token, &recover_token, &account])?,
None => tx.query(update_query, &[&email, &confirm_token, &recover_token, &account])?, None => tx.query(insert_query, &[&id, &account, &email, &confirm_token, &recover_token])?,
}; };
match result.iter().next() { match result.iter().next() {

View File

@ -17,6 +17,8 @@ use crossbeam_channel::{unbounded, Sender as CbSender};
use ws::{Builder, CloseCode, Message, Handler, Request, Response, Settings, Sender as WsSender}; use ws::{Builder, CloseCode, Message, Handler, Request, Response, Settings, Sender as WsSender};
use ws::deflate::DeflateHandler; use ws::deflate::DeflateHandler;
use rand::prelude::*;
use account::{Account}; use account::{Account};
use account; use account;
use events::{Event}; use events::{Event};
@ -132,11 +134,10 @@ pub trait User {
} }
struct Connection { struct Connection {
pub id: Uuid, pub id: usize,
pub ws: CbSender<RpcMessage>, pub ws: CbSender<RpcMessage>,
pool: PgPool, pool: PgPool,
stripe: StripeClient, stripe: StripeClient,
// account: Option<Account>,
user: Box<dyn User>, user: Box<dyn User>,
events: CbSender<Event>, events: CbSender<Event>,
} }
@ -199,8 +200,7 @@ impl Handler for Connection {
let db = self.pool.get().unwrap(); let db = self.pool.get().unwrap();
match account::from_token(&db, &cookie.value().to_string()) { match account::from_token(&db, &cookie.value().to_string()) {
Ok(a) => { Ok(a) => {
self.id = a.id; self.user = Box::new(Authenticated::new(self.id, a, self.ws.clone(), self.events.clone(), self.pool.clone()));
self.user = Box::new(Authenticated::new(a, self.ws.clone(), self.events.clone(), self.pool.clone()));
}, },
Err(_) => return unauth(), Err(_) => return unauth(),
} }
@ -243,12 +243,12 @@ pub fn start(pool: PgPool, events_tx: CbSender<Event>, stripe: StripeClient) {
} }
}); });
let mut rng = thread_rng();
let anon_account = Account::anonymous(); let anon_account = Account::anonymous();
let id = anon_account.id;
DeflateHandler::new( DeflateHandler::new(
Connection { Connection {
id, id: rng.gen::<usize>(),
ws: tx.clone(), ws: tx.clone(),
pool: pool.clone(), pool: pool.clone(),
stripe: stripe.clone(), stripe: stripe.clone(),

View File

@ -1,7 +1,6 @@
use mnml_core::mob::anim_test_game; use mnml_core::mob::anim_test_game;
use mnml_core::item::item_info; use mnml_core::item::item_info;
use std::time::Instant; use std::time::Instant;
use uuid::Uuid;
use failure::Error; use failure::Error;
use failure::err_msg; use failure::err_msg;
@ -44,7 +43,7 @@ use rpc::{RpcMessage, RpcRequest, User};
#[derive(Debug,Clone)] #[derive(Debug,Clone)]
pub struct Authenticated { pub struct Authenticated {
pub account: Account, pub account: Account,
pub id: Uuid, pub id: usize,
events: CbSender<Event>, events: CbSender<Event>,
ws: CbSender<RpcMessage>, ws: CbSender<RpcMessage>,
@ -52,9 +51,9 @@ pub struct Authenticated {
} }
impl Authenticated { impl Authenticated {
pub fn new(account: Account, ws: CbSender<RpcMessage>, events: CbSender<Event>, pool: PgPool) -> Authenticated { pub fn new(id: usize, account: Account, ws: CbSender<RpcMessage>, events: CbSender<Event>, pool: PgPool) -> Authenticated {
Authenticated { Authenticated {
id: account.id, id,
account, account,
ws, ws,
events, events,
@ -81,10 +80,10 @@ impl User for Authenticated {
// last minute processing // last minute processing
let msg = match msg { let msg = match msg {
RpcMessage::InstanceState(v) => RpcMessage::InstanceState(v.redact(self.id)), RpcMessage::InstanceState(v) => RpcMessage::InstanceState(v.redact(self.account.id)),
RpcMessage::AccountInstances(v) => RpcMessage::AccountInstances(v) =>
RpcMessage::AccountInstances(v.into_iter().map(|i| i.redact(self.id)).collect()), RpcMessage::AccountInstances(v.into_iter().map(|i| i.redact(self.account.id)).collect()),
RpcMessage::GameState(v) => RpcMessage::GameState(v.redact(self.id)), RpcMessage::GameState(v) => RpcMessage::GameState(v.redact(self.account.id)),
_ => msg, _ => msg,
}; };

View File

@ -1,6 +1,6 @@
{ {
"name": "mnml-studios", "name": "mnml-studios",
"version": "1.12.4", "version": "1.13.0",
"description": "", "description": "",
"main": "index.js", "main": "index.js",
"scripts": { "scripts": {