Merge branch 'release/1.2.0'

This commit is contained in:
ntr 2019-09-04 17:02:49 +10:00
commit 9c395bf825
18 changed files with 393 additions and 58 deletions

View File

@ -1 +1 @@
1.1.0
1.2.0

View File

@ -4,7 +4,6 @@
* ACP
* essential
* serde serialize privatise
* DO postgres
* mobile styles
* can't reset password without knowing password =\
@ -13,10 +12,8 @@
* background colour changes depending on time of day
* bug fixes
* pvp 1st player ready up doesn't get put in game
* pvp 1st round doesn't resolve until warden timer completes
* bot game grind
* stress test
@ -65,12 +62,6 @@ mobile info page
reconnect based on time delta
consolidate game and instance
ah man
the ready screen should totally be
your constructs facing off against the other guy
the chatwheel
and a ready button
*SERVER*
* vbox drops chances
* 50% spec, 25% colour etc
@ -78,7 +69,6 @@ and a ready button
* mnml tv
## LATER
* chat
* elo + leaderboards
* constants
* change to ownership pattern

View File

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

View File

@ -24,6 +24,7 @@ ssh -q "$TARGET" ls -lah "$SERVER_BIN_DIR"
echo "syncing client $VERSION"
rsync -a --delete --delete-excluded "$MNML_PATH/client/dist/" "$TARGET:$CLIENT_DIST_DIR/$VERSION/"
ssh -q "$TARGET" ln -nfs "$CLIENT_DIST_DIR/$VERSION" "$CLIENT_PUBLIC_DIR"
ssh -q "$TARGET" ls -lah "$CLIENT_DIST_DIR"
echo "restarting mnml service"
ssh -q -t "$TARGET" sudo service mnml restart && sleep 1 && systemctl --no-pager status mnml

View File

@ -60,6 +60,16 @@
height: 1em;
}
.instance .info figure {
display: inline;
height: 0.5em;
}
.instance .info figcaption {
font-size: 1em;
}
.instance .constructs {
grid-area: constructs;
}

View File

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

View File

@ -28,9 +28,16 @@ function InfoComponent(args) {
const regEx = /(RedPower|BluePower|GreenPower|RedLife|BlueLife|GreenLife|SpeedStat)/;
const infoDescription = reactStringReplace(fullInfo.description, regEx, match => shapes[match]());
const itemSource = itemInfo.combos.filter(c => c.item === info);
const itemSourceInfo = itemSource.length
? `${itemSource[0].components[0]} ${itemSource[0].components[1]} ${itemSource[0].components[2]}`
: false;
const itemRegEx = /(Red|Blue|Green)/;
const itemSourceDescription = reactStringReplace(itemSourceInfo, itemRegEx, match => shapes[match]());
return (
<div class="info-skill">
<h2>{fullInfo.item}</h2>
<h3>{itemSourceDescription}</h3>
<div> {infoDescription} </div>
</div>
);

View File

@ -100,9 +100,79 @@ module.exports = {
{square(['red', 'blue'])}
<figcaption>Life</figcaption>
</figure>,
LifeGGPlus: () =>
<figure>
{square(['green'])}
<figcaption>Life+</figcaption>
</figure>,
LifeRRPlus: () =>
<figure>
{square(['red'])}
<figcaption>Life+</figcaption>
</figure>,
// Power Upgrades
LifeBBPlus:() =>
<figure>
{square(['blue'])}
<figcaption>Life+</figcaption>
</figure>,
LifeRGPlus: () =>
<figure>
{square(['red', 'green'])}
<figcaption>Life+</figcaption>
</figure>,
LifeGBPlus: () =>
<figure>
{square(['green', 'blue'])}
<figcaption>Life+</figcaption>
</figure>,
LifeRBPlus:() =>
<figure>
{square(['red', 'blue'])}
<figcaption>Life+</figcaption>
</figure>,
LifeGGPlusPlus: () =>
<figure>
{square(['green'])}
<figcaption>Life++</figcaption>
</figure>,
LifeRRPlusPlus: () =>
<figure>
{square(['red'])}
<figcaption>Life++</figcaption>
</figure>,
LifeBBPlusPlus:() =>
<figure>
{square(['blue'])}
<figcaption>Life++</figcaption>
</figure>,
LifeRGPlusPlus: () =>
<figure>
{square(['red', 'green'])}
<figcaption>Life++</figcaption>
</figure>,
LifeGBPlusPlus: () =>
<figure>
{square(['green', 'blue'])}
<figcaption>Life++</figcaption>
</figure>,
LifeRBPlusPlus:() =>
<figure>
{square(['red', 'blue'])}
<figcaption>Life++</figcaption>
</figure>,
// Powers Upgrades
PowerGG: () =>
<figure>
{circle(['green'])}
@ -138,8 +208,79 @@ module.exports = {
{circle(['red', 'blue'])}
<figcaption>Power</figcaption>
</figure>,
PowerGGPlus: () =>
<figure>
{circle(['green'])}
<figcaption>Power+</figcaption>
</figure>,
// Speed Upgrades
PowerRRPlus: () =>
<figure>
{circle(['red'])}
<figcaption>Power+</figcaption>
</figure>,
PowerBBPlus:() =>
<figure>
{circle(['blue'])}
<figcaption>Power+</figcaption>
</figure>,
PowerRGPlus: () =>
<figure>
{circle(['red', 'green'])}
<figcaption>Power+</figcaption>
</figure>,
PowerGBPlus: () =>
<figure>
{circle(['green', 'blue'])}
<figcaption>Power+</figcaption>
</figure>,
PowerRBPlus:() =>
<figure>
{circle(['red', 'blue'])}
<figcaption>Power+</figcaption>
</figure>,
PowerGGPlusPlus: () =>
<figure>
{circle(['green'])}
<figcaption>Power++</figcaption>
</figure>,
PowerRRPlusPlus: () =>
<figure>
{circle(['red'])}
<figcaption>Power++</figcaption>
</figure>,
PowerBBPlusPlus:() =>
<figure>
{circle(['blue'])}
<figcaption>Power++</figcaption>
</figure>,
PowerRGPlusPlus: () =>
<figure>
{circle(['red', 'green'])}
<figcaption>Power++</figcaption>
</figure>,
PowerGBPlusPlus: () =>
<figure>
{circle(['green', 'blue'])}
<figcaption>Power++</figcaption>
</figure>,
PowerRBPlusPlus:() =>
<figure>
{circle(['red', 'blue'])}
<figcaption>Power++</figcaption>
</figure>,
// Speeds Upgrades
SpeedGG: () =>
<figure>
{triangle(['green'])}
@ -175,4 +316,75 @@ module.exports = {
{triangle(['red', 'blue'])}
<figcaption>Speed</figcaption>
</figure>,
SpeedGGPlus: () =>
<figure>
{triangle(['green'])}
<figcaption>Speed+</figcaption>
</figure>,
SpeedRRPlus: () =>
<figure>
{triangle(['red'])}
<figcaption>Speed+</figcaption>
</figure>,
SpeedBBPlus:() =>
<figure>
{triangle(['blue'])}
<figcaption>Speed+</figcaption>
</figure>,
SpeedRGPlus: () =>
<figure>
{triangle(['red', 'green'])}
<figcaption>Speed+</figcaption>
</figure>,
SpeedGBPlus: () =>
<figure>
{triangle(['green', 'blue'])}
<figcaption>Speed+</figcaption>
</figure>,
SpeedRBPlus:() =>
<figure>
{triangle(['red', 'blue'])}
<figcaption>Speed+</figcaption>
</figure>,
SpeedGGPlusPlus: () =>
<figure>
{triangle(['green'])}
<figcaption>Speed++</figcaption>
</figure>,
SpeedRRPlusPlus: () =>
<figure>
{triangle(['red'])}
<figcaption>Speed++</figcaption>
</figure>,
SpeedBBPlusPlus:() =>
<figure>
{triangle(['blue'])}
<figcaption>Speed++</figcaption>
</figure>,
SpeedRGPlusPlus: () =>
<figure>
{triangle(['red', 'green'])}
<figcaption>Speed++</figcaption>
</figure>,
SpeedGBPlusPlus: () =>
<figure>
{triangle(['green', 'blue'])}
<figcaption>Speed++</figcaption>
</figure>,
SpeedRBPlusPlus:() =>
<figure>
{triangle(['red', 'blue'])}
<figcaption>Speed++</figcaption>
</figure>,
};

View File

@ -305,7 +305,6 @@ function Vbox(args) {
const highlighted = combiner.indexOf(i) > -1;
const classes = `${highlighted ? 'highlight' : ''}`;
if (shapes[v]) {
return (
<button

View File

@ -223,8 +223,8 @@ function createSocket(events) {
ItemInfo: onItemInfo,
Pong: onPong,
QueueRequested: () => console.log('pvp queue request received'),
QueueJoined: () => console.log('you have joined the pvp queue'),
QueueRequested: () => events.notify('pvp queue request received'),
QueueJoined: () => events.notify('you have joined the pvp queue'),
Error: errHandler,
};

View File

@ -228,6 +228,7 @@ function convertItem(v) {
shapes.vboxColour(v.toLowerCase())
);
}
if (shapes[v]) return shapes[v]();
return v || <span>&nbsp;</span>;
// uncomment for double borders in vbox;
// if (v) {

View File

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

View File

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

View File

@ -4,6 +4,7 @@ use std::collections::{HashMap, HashSet};
use uuid::Uuid;
use failure::Error;
use failure::{err_msg, format_err};
use crossbeam_channel::{Sender, Receiver};
@ -28,7 +29,7 @@ type Id = usize;
pub struct PvpRequest {
pub id: Id,
pub tx: Sender<RpcMessage>,
pub account: Account,
pub account: Uuid,
}
pub struct Events {
@ -37,8 +38,6 @@ pub struct Events {
mail: Sender<Mail>,
warden: Sender<GameEvent>,
queue: Option<PvpRequest>,
clients: HashMap<Id, WsClient>,
}
@ -54,13 +53,15 @@ pub enum Event {
Push(Uuid, RpcMessage),
// client events
Queue(PvpRequest),
Queue(Id),
}
struct WsClient {
id: Id,
account: Option<Uuid>,
tx: Sender<RpcMessage>,
subs: HashSet<Uuid>,
pvp: bool,
}
impl Events {
@ -70,7 +71,6 @@ impl Events {
rx,
warden,
mail,
queue: None,
clients: HashMap::new(),
}
}
@ -88,7 +88,7 @@ impl Events {
},
Err(e) => {
return Err(format_err!("events error err={:?}", e));
warn!("events error err={:?}", e);
},
};
}
@ -110,7 +110,12 @@ impl Events {
Event::Connect(id, account, tx) => {
info!("connect id={:?} account={:?}", id, account);
let client = WsClient { id, tx, subs: HashSet::new() };
let account_id = match account {
Some(a) => Some(a.id),
None => None,
};
let client = WsClient { id, tx, account: account_id, subs: HashSet::new(), pvp: false };
self.clients.insert(id, client);
info!("clients={:?}", self.clients.len());
@ -181,24 +186,43 @@ impl Events {
Ok(())
},
Event::Queue(req) => {
info!("queue id={:?} account={:?}", req.id, req.account);
Event::Queue(id) => {
// check whether request is valid
{
let c = self.clients.get(&id)
.ok_or(format_err!("connection not found id={:?}", id))?;
self.queue = match self.queue {
Some(ref q_req) => {
info!("game queue pair found a={:?} b={:?}", req.account, q_req.account);
self.warden.send(GameEvent::Match((req, q_req.clone())))?;
None
},
None => {
info!("joined game queue id={:?} account={:?}", req.id, req.account);
Some(req)
},
};
if let None = c.account {
return Err(err_msg("cannot join pvp queue anonymously"));
}
Ok(())
info!("pvp queue request id={:?} account={:?}", c.id, c.account);
}
// create the req for the already queued opponent
if let Some(opp_req) = match self.clients.iter_mut().find(|(_c_id, c)| c.pvp) {
Some((q_id, q)) => {
q.pvp = false;
Some(PvpRequest { id: *q_id, account: q.account.unwrap(), tx: q.tx.clone() })
},
None => None,
} {
// combine the requests and send to warden
let c = self.clients.get_mut(&id)
.ok_or(format_err!("connection not found id={:?}", id))?;
let player_req = PvpRequest { id: c.id, account: c.account.unwrap(), tx: c.tx.clone() };
self.warden.send(GameEvent::Match((opp_req, player_req)))?;
return Ok(())
}
// or flag the requester as pvp ready
let requester = self.clients.get_mut(&id).unwrap();
requester.pvp = true;
info!("joined game queue id={:?} account={:?}", requester.id, requester.account);
return Ok(());
},
}
}
}

View File

@ -691,9 +691,6 @@ pub fn instance_practice(tx: &mut Transaction, account: &Account) -> Result<Inst
Ok(instance)
}
// pub fn instance_queue(tx: &mut Transaction, a: &Account, b: &Account) -> Result<Instance, Error> {
// }
pub fn pvp(tx: &mut Transaction, a: &Account, b: &Account) -> Result<Instance, Error> {
let mut instance = Instance::new()
// TODO generate nice game names

View File

@ -44,139 +44,229 @@ pub enum Item {
LifeRBPlusPlus,
// Power Upgrades
PowerGG,
PowerRR,
PowerBB,
PowerGG,
PowerRG,
PowerGB,
PowerRB,
PowerRRPlus,
PowerGGPlus,
PowerRRPlus,
PowerBBPlus,
PowerRGPlus,
PowerGBPlus,
PowerRBPlus,
PowerGGPlusPlus,
PowerRRPlusPlus,
PowerBBPlusPlus,
PowerGGPlusPlus,
PowerRGPlusPlus,
PowerGBPlusPlus,
PowerRBPlusPlus,
// Speed Upgrades
SpeedGG,
SpeedRR,
SpeedBB,
SpeedGG,
SpeedRG,
SpeedGB,
SpeedRB,
SpeedGGPlus,
SpeedRRPlus,
SpeedBBPlus,
SpeedGGPlus,
SpeedRGPlus,
SpeedGBPlus,
SpeedRBPlus,
SpeedGGPlusPlus,
SpeedRRPlusPlus,
SpeedBBPlusPlus,
SpeedGGPlusPlus,
SpeedRGPlusPlus,
SpeedGBPlusPlus,
SpeedRBPlusPlus,
Amplify,
#[serde(rename = "Amplify+")]
AmplifyPlus,
#[serde(rename = "Amplify++")]
AmplifyPlusPlus,
Absorb,
#[serde(rename = "Absorb+")]
AbsorbPlus,
#[serde(rename = "Absorb++")]
AbsorbPlusPlus,
Banish,
#[serde(rename = "Banish+")]
BanishPlus,
#[serde(rename = "Banish++")]
BanishPlusPlus,
Bash,
#[serde(rename = "Bash+")]
BashPlus,
#[serde(rename = "Bash++")]
BashPlusPlus,
Blast,
#[serde(rename = "Blast+")]
BlastPlus,
#[serde(rename = "Blast++")]
BlastPlusPlus,
Chaos,
#[serde(rename = "Chaos+")]
ChaosPlus,
#[serde(rename = "Chaos++")]
ChaosPlusPlus,
Sustain,
#[serde(rename = "Sustain+")]
SustainPlus,
#[serde(rename = "Sustain++")]
SustainPlusPlus,
Electrify,
#[serde(rename = "Electrify+")]
ElectrifyPlus,
#[serde(rename = "Electrify++")]
ElectrifyPlusPlus,
Curse,
#[serde(rename = "Curse+")]
CursePlus,
#[serde(rename = "Curse++")]
CursePlusPlus,
Decay,
#[serde(rename = "Decay+")]
DecayPlus,
#[serde(rename = "Decay++")]
DecayPlusPlus,
Hex,
#[serde(rename = "Hex+")]
HexPlus,
#[serde(rename = "Hex++")]
HexPlusPlus,
Haste,
#[serde(rename = "Haste+")]
HastePlus,
#[serde(rename = "Haste++")]
HastePlusPlus,
Heal,
#[serde(rename = "Heal+")]
HealPlus,
#[serde(rename = "Heal++")]
HealPlusPlus,
Hybrid,
#[serde(rename = "Hybrid+")]
HybridPlus,
#[serde(rename = "Hybrid++")]
HybridPlusPlus,
Invert,
#[serde(rename = "Invert+")]
InvertPlus,
#[serde(rename = "Invert++")]
InvertPlusPlus,
Counter,
#[serde(rename = "Counter+")]
CounterPlus,
#[serde(rename = "Counter++")]
CounterPlusPlus,
Purge,
#[serde(rename = "Purge+")]
PurgePlus,
#[serde(rename = "Purge++")]
PurgePlusPlus,
Purify,
#[serde(rename = "Purify+")]
PurifyPlus,
#[serde(rename = "Purify++")]
PurifyPlusPlus,
Reflect,
#[serde(rename = "Reflect+")]
ReflectPlus,
#[serde(rename = "Reflect++")]
ReflectPlusPlus,
Recharge,
#[serde(rename = "Recharge+")]
RechargePlus,
#[serde(rename = "Recharge++")]
RechargePlusPlus,
Ruin,
#[serde(rename = "Ruin+")]
RuinPlus,
#[serde(rename = "Ruin++")]
RuinPlusPlus,
Link,
#[serde(rename = "Link+")]
LinkPlus,
#[serde(rename = "Link++")]
LinkPlusPlus,
Silence,
#[serde(rename = "Silence+")]
SilencePlus,
#[serde(rename = "Silence++")]
SilencePlusPlus,
Slay,
#[serde(rename = "Slay+")]
SlayPlus,
#[serde(rename = "Slay++")]
SlayPlusPlus,
Sleep,
#[serde(rename = "Sleep+")]
SleepPlus,
#[serde(rename = "Sleep++")]
SleepPlusPlus,
Restrict,
#[serde(rename = "Restrict+")]
RestrictPlus,
#[serde(rename = "Restrict++")]
RestrictPlusPlus,
Strike,
#[serde(rename = "Strike+")]
StrikePlus,
#[serde(rename = "Strike++")]
StrikePlusPlus,
Siphon,
#[serde(rename = "Siphon+")]
SiphonPlus,
#[serde(rename = "Siphon++")]
SiphonPlusPlus,
Intercept,
#[serde(rename = "Intercept+")]
InterceptPlus,
#[serde(rename = "Intercept++")]
InterceptPlusPlus,
Break,
#[serde(rename = "Break+")]
BreakPlus,
#[serde(rename = "Break++")]
BreakPlusPlus,
Triage,
#[serde(rename = "Triage+")]
TriagePlus,
#[serde(rename = "Triage++")]
TriagePlusPlus,
}

View File

@ -19,7 +19,7 @@ use ws::{listen, CloseCode, Message, Handler, Request, Response};
use account::{Account};
use account;
use construct::{Construct};
use events::{Event, PvpRequest};
use events::{Event};
use game::{Game, game_state, game_skill, game_ready};
use instance::{Instance, instance_state, instance_practice, instance_ready};
use item::{Item, ItemInfoCtr, item_info};
@ -132,8 +132,7 @@ impl Connection {
// evented but authorization required
match v {
RpcRequest::InstanceQueue {} => {
let pvp = PvpRequest { id: self.id, account: account.clone(), tx: self.ws.clone() };
self.events.send(Event::Queue(pvp))?;
self.events.send(Event::Queue(self.id))?;
return Ok(RpcMessage::QueueRequested(()));
},
_ => (),

View File

@ -8,6 +8,7 @@ use crossbeam_channel::{tick, Sender, Receiver};
use postgres::transaction::Transaction;
use failure::Error;
use account;
use game::{games_need_upkeep, game_update, game_write, game_delete};
use instance;
use instance::{instances_need_upkeep, instances_idle, instance_update, instance_delete};
@ -57,7 +58,7 @@ impl Warden {
},
Err(e) => {
return Err(format_err!("err={:?}", e));
warn!("err={:?}", e);
},
};
}
@ -91,7 +92,11 @@ impl Warden {
let db = self.pool.get()?;
let mut tx = db.transaction()?;
let instance = instance::pvp(&mut tx, &pair.0.account, &pair.1.account)?;
let a = account::select(&db, pair.0.account)?;
let b = account::select(&db, pair.1.account)?;
let instance = instance::pvp(&mut tx, &a, &b)?;
tx.commit()?;
// subscribe users to instance events