shop bois
This commit is contained in:
parent
52b1e14541
commit
2fa7310aaa
@ -23,6 +23,7 @@ export const setResolution = value => ({ type: 'SET_RESOLUTION', value });
|
|||||||
export const setShowLog = value => ({ type: 'SET_SHOW_LOG', value });
|
export const setShowLog = value => ({ type: 'SET_SHOW_LOG', value });
|
||||||
export const setShowNav = value => ({ type: 'SET_SHOW_NAV', value });
|
export const setShowNav = value => ({ type: 'SET_SHOW_NAV', value });
|
||||||
export const setSkip = value => ({ type: 'SET_SKIP', value });
|
export const setSkip = value => ({ type: 'SET_SKIP', value });
|
||||||
|
export const setShop = value => ({ type: 'SET_SHOP', value });
|
||||||
export const setTeam = value => ({ type: 'SET_SELECTED_CONSTRUCTS', value: Array.from(value) });
|
export const setTeam = value => ({ type: 'SET_SELECTED_CONSTRUCTS', value: Array.from(value) });
|
||||||
export const setVboxHighlight = value => ({ type: 'SET_VBOX_HIGHLIGHT', value });
|
export const setVboxHighlight = value => ({ type: 'SET_VBOX_HIGHLIGHT', value });
|
||||||
export const setWs = value => ({ type: 'SET_WS', value });
|
export const setWs = value => ({ type: 'SET_WS', value });
|
||||||
|
|||||||
@ -96,7 +96,7 @@ function AccountStatus(args) {
|
|||||||
{saw(pingColour(ping))}
|
{saw(pingColour(ping))}
|
||||||
<div class="ping-text">{ping}ms</div>
|
<div class="ping-text">{ping}ms</div>
|
||||||
</div>
|
</div>
|
||||||
<h3 class="account-header">{`¤${account.credits}`}</h3>
|
<h3 class="account-header">{`¤${account.balance}`}</h3>
|
||||||
<Elements>
|
<Elements>
|
||||||
<StripeBitsBtn account={account} />
|
<StripeBitsBtn account={account} />
|
||||||
</Elements>
|
</Elements>
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
const anime = require('animejs').default;
|
const anime = require('animejs').default;
|
||||||
|
|
||||||
function idle(id) {
|
function idle(id) {
|
||||||
return false;
|
|
||||||
const duration = anime.random(2000, 18000);
|
const duration = anime.random(2000, 18000);
|
||||||
const target = document.getElementById(id);
|
const target = document.getElementById(id);
|
||||||
return anime({
|
return anime({
|
||||||
|
|||||||
@ -31,7 +31,7 @@ class ConstructAvatar extends Component {
|
|||||||
<div
|
<div
|
||||||
class="avatar"
|
class="avatar"
|
||||||
id={this.props.construct.id}
|
id={this.props.construct.id}
|
||||||
style={{ 'background-image': `url(/imgs/32809d3b-60e6-4d37-a183-e5d33374613b.svg)` }}
|
style={{ 'background-image': `url(/imgs/${this.props.construct.img}.svg)` }}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,12 +6,19 @@ const actions = require('./../actions');
|
|||||||
const addState = connect(
|
const addState = connect(
|
||||||
function receiveState(state) {
|
function receiveState(state) {
|
||||||
const {
|
const {
|
||||||
// ws,
|
ws,
|
||||||
account,
|
account,
|
||||||
|
shop,
|
||||||
} = state;
|
} = state;
|
||||||
|
|
||||||
|
function mtxBuy(mtx) {
|
||||||
|
return ws.sendMtxBuy(mtx.variant);
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
account,
|
account,
|
||||||
|
shop,
|
||||||
|
mtxBuy,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -29,29 +36,37 @@ const addState = connect(
|
|||||||
function Inventory(args) {
|
function Inventory(args) {
|
||||||
const {
|
const {
|
||||||
account,
|
account,
|
||||||
|
shop,
|
||||||
|
|
||||||
setMtxActive,
|
setMtxActive,
|
||||||
|
mtxBuy,
|
||||||
} = args;
|
} = args;
|
||||||
|
|
||||||
|
if (!shop) return false;
|
||||||
|
|
||||||
|
const useMtx = (item, i) => (
|
||||||
|
<figure key={i} onClick={() => setMtxActive(item)} >
|
||||||
|
<figcaption>{item}</figcaption>
|
||||||
|
<button>¤1</button>
|
||||||
|
</figure>
|
||||||
|
);
|
||||||
|
|
||||||
|
const availableMtx = (item, i) => (
|
||||||
|
<figure key={i} onClick={() => mtxBuy(item)} >
|
||||||
|
<figcaption>{item.variant}</figcaption>
|
||||||
|
<button>¤{item.credits}</button>
|
||||||
|
</figure>
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div class="inventory">
|
<div class="inventory">
|
||||||
<h1>¤ {account.credits}</h1>
|
<h1>¤ {account.balance}</h1>
|
||||||
<div class='list'>
|
<div class='list'>
|
||||||
<figure onClick={() => setMtxActive('Reimage')} >
|
{shop.owned.map(useMtx)}
|
||||||
<figcaption>Reimage</figcaption>
|
</div>
|
||||||
<button>¤1</button>
|
<h1>Shop</h1>
|
||||||
</figure>
|
<div class='list'>
|
||||||
<figure onClick={() => setMtxActive('Rename')} >
|
{shop.available.map(availableMtx)}
|
||||||
<figcaption>Rename</figcaption>
|
|
||||||
<button>¤1</button>
|
|
||||||
</figure>
|
|
||||||
<figure>
|
|
||||||
<figcaption>Invader Architecture</figcaption>
|
|
||||||
<button>∞</button>
|
|
||||||
</figure>
|
|
||||||
<figure>
|
|
||||||
<figcaption>Molecular Architecture</figcaption>
|
|
||||||
<button>∞</button>
|
|
||||||
</figure>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -111,6 +111,10 @@ function registerEvents(store) {
|
|||||||
store.dispatch(actions.setAccount(account));
|
store.dispatch(actions.setAccount(account));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function setShop(v) {
|
||||||
|
store.dispatch(actions.setShop(v));
|
||||||
|
}
|
||||||
|
|
||||||
function clearCombiner() {
|
function clearCombiner() {
|
||||||
store.dispatch(actions.setInfo([]));
|
store.dispatch(actions.setInfo([]));
|
||||||
store.dispatch(actions.setCombiner([null, null, null]));
|
store.dispatch(actions.setCombiner([null, null, null]));
|
||||||
@ -233,6 +237,7 @@ function registerEvents(store) {
|
|||||||
setInstanceList,
|
setInstanceList,
|
||||||
setItemInfo,
|
setItemInfo,
|
||||||
setPing,
|
setPing,
|
||||||
|
setShop,
|
||||||
setWs,
|
setWs,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@ -35,6 +35,7 @@ module.exports = {
|
|||||||
reclaiming: createReducer(false, 'SET_RECLAIMING'),
|
reclaiming: createReducer(false, 'SET_RECLAIMING'),
|
||||||
resolution: createReducer(null, 'SET_RESOLUTION'),
|
resolution: createReducer(null, 'SET_RESOLUTION'),
|
||||||
skip: createReducer(false, 'SET_SKIP'),
|
skip: createReducer(false, 'SET_SKIP'),
|
||||||
|
shop: createReducer(false, 'SET_SHOP'),
|
||||||
team: createReducer([null, null, null], 'SET_SELECTED_CONSTRUCTS'),
|
team: createReducer([null, null, null], 'SET_SELECTED_CONSTRUCTS'),
|
||||||
vboxHighlight: createReducer([], 'SET_VBOX_HIGHLIGHT'),
|
vboxHighlight: createReducer([], 'SET_VBOX_HIGHLIGHT'),
|
||||||
ws: createReducer(null, 'SET_WS'),
|
ws: createReducer(null, 'SET_WS'),
|
||||||
|
|||||||
@ -124,6 +124,10 @@ function createSocket(events) {
|
|||||||
// events.clearMtxActive();
|
// events.clearMtxActive();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function sendMtxBuy(mtx) {
|
||||||
|
send(['MtxBuy', { mtx }]);
|
||||||
|
}
|
||||||
|
|
||||||
// -------------
|
// -------------
|
||||||
// Incoming
|
// Incoming
|
||||||
// -------------
|
// -------------
|
||||||
@ -133,6 +137,10 @@ function createSocket(events) {
|
|||||||
sendAccountInstances();
|
sendAccountInstances();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function onAccountShop(shop) {
|
||||||
|
events.setShop(shop);
|
||||||
|
}
|
||||||
|
|
||||||
function onAccountInstances(list) {
|
function onAccountInstances(list) {
|
||||||
events.setAccountInstances(list);
|
events.setAccountInstances(list);
|
||||||
setTimeout(sendAccountInstances, 5000);
|
setTimeout(sendAccountInstances, 5000);
|
||||||
@ -198,6 +206,7 @@ function createSocket(events) {
|
|||||||
AccountState: onAccount,
|
AccountState: onAccount,
|
||||||
AccountConstructs: onAccountConstructs,
|
AccountConstructs: onAccountConstructs,
|
||||||
AccountInstances: onAccountInstances,
|
AccountInstances: onAccountInstances,
|
||||||
|
AccountShop: onAccountShop,
|
||||||
GameState: onGameState,
|
GameState: onGameState,
|
||||||
InstanceState: onInstanceState,
|
InstanceState: onInstanceState,
|
||||||
ItemInfo: onItemInfo,
|
ItemInfo: onItemInfo,
|
||||||
@ -308,6 +317,7 @@ function createSocket(events) {
|
|||||||
sendVboxUnequip,
|
sendVboxUnequip,
|
||||||
sendItemInfo,
|
sendItemInfo,
|
||||||
sendMtxApply,
|
sendMtxApply,
|
||||||
|
sendMtxBuy,
|
||||||
startInstanceStateTimeout,
|
startInstanceStateTimeout,
|
||||||
startGameStateTimeout,
|
startGameStateTimeout,
|
||||||
connect,
|
connect,
|
||||||
|
|||||||
@ -9,7 +9,7 @@ exports.up = async knex => {
|
|||||||
table.string('token', 64).notNullable();
|
table.string('token', 64).notNullable();
|
||||||
table.timestamp('token_expiry').notNullable();
|
table.timestamp('token_expiry').notNullable();
|
||||||
|
|
||||||
table.bigInteger('credits')
|
table.bigInteger('balance')
|
||||||
.defaultTo(0)
|
.defaultTo(0)
|
||||||
.notNullable();
|
.notNullable();
|
||||||
|
|
||||||
@ -23,7 +23,7 @@ exports.up = async knex => {
|
|||||||
|
|
||||||
await knex.schema.raw(`
|
await knex.schema.raw(`
|
||||||
ALTER TABLE accounts
|
ALTER TABLE accounts
|
||||||
ADD CHECK (credits > 0);
|
ADD CHECK (balance > 0);
|
||||||
`);
|
`);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -14,6 +14,7 @@ use instance::{Instance, instance_delete};
|
|||||||
use mtx::{Mtx, FREE_MTX};
|
use mtx::{Mtx, FREE_MTX};
|
||||||
use pg::Db;
|
use pg::Db;
|
||||||
|
|
||||||
|
|
||||||
use failure::Error;
|
use failure::Error;
|
||||||
use failure::{err_msg, format_err};
|
use failure::{err_msg, format_err};
|
||||||
|
|
||||||
@ -23,13 +24,13 @@ static PASSWORD_MIN_LEN: usize = 11;
|
|||||||
pub struct Account {
|
pub struct Account {
|
||||||
pub id: Uuid,
|
pub id: Uuid,
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub credits: u32,
|
pub balance: u32,
|
||||||
pub subscribed: bool,
|
pub subscribed: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn select(tx: &mut Transaction, id: Uuid) -> Result<Account, Error> {
|
pub fn select(tx: &mut Transaction, id: Uuid) -> Result<Account, Error> {
|
||||||
let query = "
|
let query = "
|
||||||
SELECT id, name, credits, subscribed
|
SELECT id, name, balance, subscribed
|
||||||
FROM accounts
|
FROM accounts
|
||||||
WHERE id = $1;
|
WHERE id = $1;
|
||||||
";
|
";
|
||||||
@ -40,18 +41,18 @@ pub fn select(tx: &mut Transaction, id: Uuid) -> Result<Account, Error> {
|
|||||||
let row = result.iter().next()
|
let row = result.iter().next()
|
||||||
.ok_or(format_err!("account not found {:?}", id))?;
|
.ok_or(format_err!("account not found {:?}", id))?;
|
||||||
|
|
||||||
let db_credits: i64 = row.get(2);
|
let db_balance: i64 = row.get(2);
|
||||||
let credits = u32::try_from(db_credits)
|
let balance = u32::try_from(db_balance)
|
||||||
.or(Err(format_err!("user {:?} has unparsable balance {:?}", id, db_credits)))?;
|
.or(Err(format_err!("user {:?} has unparsable balance {:?}", id, db_balance)))?;
|
||||||
|
|
||||||
let subscribed: bool = row.get(3);
|
let subscribed: bool = row.get(3);
|
||||||
|
|
||||||
Ok(Account { id, name: row.get(1), credits, subscribed })
|
Ok(Account { id, name: row.get(1), balance, subscribed })
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_token(db: &Db, token: String) -> Result<Account, Error> {
|
pub fn from_token(db: &Db, token: String) -> Result<Account, Error> {
|
||||||
let query = "
|
let query = "
|
||||||
SELECT id, name, subscribed, credits
|
SELECT id, name, subscribed, balance
|
||||||
FROM accounts
|
FROM accounts
|
||||||
WHERE token = $1
|
WHERE token = $1
|
||||||
AND token_expiry > now();
|
AND token_expiry > now();
|
||||||
@ -66,17 +67,17 @@ pub fn from_token(db: &Db, token: String) -> Result<Account, Error> {
|
|||||||
let id: Uuid = row.get(0);
|
let id: Uuid = row.get(0);
|
||||||
let name: String = row.get(1);
|
let name: String = row.get(1);
|
||||||
let subscribed: bool = row.get(2);
|
let subscribed: bool = row.get(2);
|
||||||
let db_credits: i64 = row.get(3);
|
let db_balance: i64 = row.get(3);
|
||||||
|
|
||||||
let credits = u32::try_from(db_credits)
|
let balance = u32::try_from(db_balance)
|
||||||
.or(Err(format_err!("user {:?} has unparsable balance {:?}", id, db_credits)))?;
|
.or(Err(format_err!("user {:?} has unparsable balance {:?}", id, db_balance)))?;
|
||||||
|
|
||||||
Ok(Account { id, name, credits, subscribed })
|
Ok(Account { id, name, balance, subscribed })
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn login(tx: &mut Transaction, name: &String, password: &String) -> Result<Account, Error> {
|
pub fn login(tx: &mut Transaction, name: &String, password: &String) -> Result<Account, Error> {
|
||||||
let query = "
|
let query = "
|
||||||
SELECT id, password, name, credits, subscribed
|
SELECT id, password, name, balance, subscribed
|
||||||
FROM accounts
|
FROM accounts
|
||||||
WHERE name = $1
|
WHERE name = $1
|
||||||
";
|
";
|
||||||
@ -102,17 +103,17 @@ pub fn login(tx: &mut Transaction, name: &String, password: &String) -> Result<A
|
|||||||
let id: Uuid = row.get(0);
|
let id: Uuid = row.get(0);
|
||||||
let hash: String = row.get(1);
|
let hash: String = row.get(1);
|
||||||
let name: String = row.get(2);
|
let name: String = row.get(2);
|
||||||
let db_credits: i64 = row.get(3);
|
let db_balance: i64 = row.get(3);
|
||||||
let subscribed: bool = row.get(4);
|
let subscribed: bool = row.get(4);
|
||||||
|
|
||||||
if !verify(password, &hash)? {
|
if !verify(password, &hash)? {
|
||||||
return Err(err_msg("password does not match"));
|
return Err(err_msg("password does not match"));
|
||||||
}
|
}
|
||||||
|
|
||||||
let credits = u32::try_from(db_credits)
|
let balance = u32::try_from(db_balance)
|
||||||
.or(Err(format_err!("user {:?} has unparsable balance {:?}", id, db_credits)))?;
|
.or(Err(format_err!("user {:?} has unparsable balance {:?}", id, db_balance)))?;
|
||||||
|
|
||||||
Ok(Account { id, name, credits, subscribed })
|
Ok(Account { id, name, balance, subscribed })
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_token(tx: &mut Transaction, id: Uuid) -> Result<String, Error> {
|
pub fn new_token(tx: &mut Transaction, id: Uuid) -> Result<String, Error> {
|
||||||
@ -133,7 +134,7 @@ pub fn new_token(tx: &mut Transaction, id: Uuid) -> Result<String, Error> {
|
|||||||
let result = tx
|
let result = tx
|
||||||
.query(query, &[&token, &id])?;
|
.query(query, &[&token, &id])?;
|
||||||
|
|
||||||
let row = result.iter().next()
|
result.iter().next()
|
||||||
.ok_or(format_err!("account not updated {:?}", id))?;
|
.ok_or(format_err!("account not updated {:?}", id))?;
|
||||||
|
|
||||||
Ok(token)
|
Ok(token)
|
||||||
@ -142,9 +143,9 @@ pub fn new_token(tx: &mut Transaction, id: Uuid) -> Result<String, Error> {
|
|||||||
pub fn credit(tx: &mut Transaction, id: Uuid, credits: i64) -> Result<String, Error> {
|
pub fn credit(tx: &mut Transaction, id: Uuid, credits: i64) -> Result<String, Error> {
|
||||||
let query = "
|
let query = "
|
||||||
UPDATE accounts
|
UPDATE accounts
|
||||||
SET credits = credits + $1
|
SET balance = balance + $1
|
||||||
WHERE id = $2
|
WHERE id = $2
|
||||||
RETURNING credits, name;
|
RETURNING balance, name;
|
||||||
";
|
";
|
||||||
|
|
||||||
let result = tx
|
let result = tx
|
||||||
@ -153,38 +154,41 @@ pub fn credit(tx: &mut Transaction, id: Uuid, credits: i64) -> Result<String, Er
|
|||||||
let row = result.iter().next()
|
let row = result.iter().next()
|
||||||
.ok_or(format_err!("account not updated {:?}", id))?;
|
.ok_or(format_err!("account not updated {:?}", id))?;
|
||||||
|
|
||||||
let db_credits: i64 = row.get(0);
|
let db_balance: i64 = row.get(0);
|
||||||
let total = u32::try_from(db_credits)
|
let balance = u32::try_from(db_balance)
|
||||||
.or(Err(format_err!("user {:?} has unparsable balance {:?}", id, db_credits)))?;
|
.or(Err(format_err!("user {:?} has unparsable balance {:?}", id, db_balance)))?;
|
||||||
|
|
||||||
let name: String = row.get(1);
|
let name: String = row.get(1);
|
||||||
|
|
||||||
info!("account credited name={:?} credited={:?} total={:?}", name, credits, total);
|
info!("account credited name={:?} credited={:?} balance={:?}", name, credits, balance);
|
||||||
|
|
||||||
Ok(name)
|
Ok(name)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn debit(tx: &mut Transaction, id: Uuid, credits: i64) -> Result<Account, Error> {
|
pub fn debit(tx: &mut Transaction, id: Uuid, debit: i64) -> Result<Account, Error> {
|
||||||
let query = "
|
let query = "
|
||||||
UPDATE accounts
|
UPDATE accounts
|
||||||
SET credits = credits - $1
|
SET balance = balance - $1
|
||||||
WHERE id = $2
|
WHERE id = $2
|
||||||
RETURNING id, name, credits, subscribed
|
RETURNING id, name, balance, subscribed
|
||||||
";
|
";
|
||||||
|
|
||||||
let result = tx
|
let result = tx
|
||||||
.query(query, &[&credits, &id])?;
|
.query(query, &[&debit, &id])?;
|
||||||
|
|
||||||
let row = result.iter().next()
|
let row = result.iter().next()
|
||||||
.ok_or(format_err!("account not found {:?}", id))?;
|
.ok_or(format_err!("account not found {:?}", id))?;
|
||||||
|
|
||||||
let db_credits: i64 = row.get(2);
|
|
||||||
let credits = u32::try_from(db_credits)
|
let name: String = row.get(1);
|
||||||
.or(Err(format_err!("user {:?} has unparsable balance {:?}", id, db_credits)))?;
|
let db_balance: i64 = row.get(2);
|
||||||
|
let balance = u32::try_from(db_balance)
|
||||||
|
.or(Err(format_err!("user {:?} has unparsable balance {:?}", id, db_balance)))?;
|
||||||
|
|
||||||
let subscribed: bool = row.get(3);
|
let subscribed: bool = row.get(3);
|
||||||
|
|
||||||
Ok(Account { id, name: row.get(1), credits, subscribed })
|
info!("account debited name={:?} debited={:?} balance={:?}", name, debit, balance);
|
||||||
|
Ok(Account { id, name: row.get(1), balance, subscribed })
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_subscribed(tx: &mut Transaction, id: Uuid, subscribed: bool) -> Result<String, Error> {
|
pub fn set_subscribed(tx: &mut Transaction, id: Uuid, subscribed: bool) -> Result<String, Error> {
|
||||||
|
|||||||
@ -11,7 +11,7 @@ use skill::{Skill, Cast, Immunity, Disable, Event};
|
|||||||
use effect::{Cooldown, Effect, Colour};
|
use effect::{Cooldown, Effect, Colour};
|
||||||
use spec::{Spec};
|
use spec::{Spec};
|
||||||
use item::{Item};
|
use item::{Item};
|
||||||
use img::{img_molecular_write};
|
use img;
|
||||||
|
|
||||||
#[derive(Debug,Clone,Serialize,Deserialize)]
|
#[derive(Debug,Clone,Serialize,Deserialize)]
|
||||||
pub struct Colours {
|
pub struct Colours {
|
||||||
@ -883,7 +883,7 @@ pub fn construct_spawn(tx: &mut Transaction, account: Uuid, name: String) -> Res
|
|||||||
|
|
||||||
let _returned = result.iter().next().ok_or(err_msg("no row returned"))?;
|
let _returned = result.iter().next().ok_or(err_msg("no row returned"))?;
|
||||||
|
|
||||||
img_molecular_write(construct.img)?;
|
img::molecular_write(construct.img)?;
|
||||||
|
|
||||||
info!("spawned construct account={:} construct={:?}", account, construct);
|
info!("spawned construct account={:} construct={:?}", account, construct);
|
||||||
return Ok(construct);
|
return Ok(construct);
|
||||||
|
|||||||
@ -9,7 +9,7 @@ use std::io::prelude::*;
|
|||||||
use failure::Error;
|
use failure::Error;
|
||||||
use failure::err_msg;
|
use failure::err_msg;
|
||||||
|
|
||||||
pub fn img_molecular_write(id: Uuid) -> Result<Uuid, Error> {
|
pub fn molecular_write(id: Uuid) -> Result<Uuid, Error> {
|
||||||
let mut rng = thread_rng();
|
let mut rng = thread_rng();
|
||||||
|
|
||||||
for _i in 0..100 {
|
for _i in 0..100 {
|
||||||
@ -27,9 +27,7 @@ pub fn img_molecular_write(id: Uuid) -> Result<Uuid, Error> {
|
|||||||
return Err(err_msg("too many missing molecules. wrong directory?"))
|
return Err(err_msg("too many missing molecules. wrong directory?"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn invader_write(id: Uuid) -> Result<Uuid, Error> {
|
||||||
|
|
||||||
fn invader_img_write(id: Uuid) -> Result<Uuid, Error> {
|
|
||||||
let mut rng = thread_rng();
|
let mut rng = thread_rng();
|
||||||
let mut svg = Vec::new();
|
let mut svg = Vec::new();
|
||||||
|
|
||||||
@ -86,17 +84,17 @@ fn invader_img_write(id: Uuid) -> Result<Uuid, Error> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[cfg(test)]
|
// #[cfg(test)]
|
||||||
mod tests {
|
// mod tests {
|
||||||
use super::*;
|
// use super::*;
|
||||||
|
|
||||||
#[test]
|
// #[test]
|
||||||
fn invader_img_test() {
|
// fn invader_img_test() {
|
||||||
for i in 0..100 {
|
// for i in 0..100 {
|
||||||
invader_img_write(Uuid::new_v4()).unwrap();
|
// invader_img_write(Uuid::new_v4()).unwrap();
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -18,8 +18,7 @@ use mob::{bot_player, instance_mobs};
|
|||||||
use game::{Game, Phase, game_get, game_write};
|
use game::{Game, Phase, game_get, game_write};
|
||||||
use item::{Item};
|
use item::{Item};
|
||||||
use rpc::{RpcResult};
|
use rpc::{RpcResult};
|
||||||
|
use img;
|
||||||
use img::{img_molecular_write};
|
|
||||||
|
|
||||||
#[derive(Debug,Clone,Copy,PartialEq,Serialize,Deserialize)]
|
#[derive(Debug,Clone,Copy,PartialEq,Serialize,Deserialize)]
|
||||||
enum InstancePhase {
|
enum InstancePhase {
|
||||||
@ -706,7 +705,7 @@ pub fn instance_new(tx: &mut Transaction, account: &Account, construct_ids: Vec<
|
|||||||
|
|
||||||
// generate bot imgs only in the real world
|
// generate bot imgs only in the real world
|
||||||
for c in bot.constructs.iter() {
|
for c in bot.constructs.iter() {
|
||||||
img_molecular_write(c.img)?;
|
img::molecular_write(c.img)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut instance = Instance::new()
|
let mut instance = Instance::new()
|
||||||
|
|||||||
@ -2,7 +2,6 @@ use std::convert::TryFrom;
|
|||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
// use rand::prelude::*;
|
// use rand::prelude::*;
|
||||||
|
|
||||||
use serde_cbor::{from_slice};
|
|
||||||
use postgres::transaction::Transaction;
|
use postgres::transaction::Transaction;
|
||||||
|
|
||||||
use failure::Error;
|
use failure::Error;
|
||||||
@ -12,17 +11,32 @@ use account;
|
|||||||
use account::Account;
|
use account::Account;
|
||||||
|
|
||||||
use construct::{Construct, construct_select, construct_write};
|
use construct::{Construct, construct_select, construct_write};
|
||||||
use img::{img_molecular_write};
|
use img;
|
||||||
|
|
||||||
pub const FREE_MTX: [MtxVariant; 2] = [
|
pub const FREE_MTX: [MtxVariant; 1] = [
|
||||||
MtxVariant::Rename,
|
MtxVariant::Rename,
|
||||||
MtxVariant::Reimage,
|
|
||||||
];
|
];
|
||||||
|
|
||||||
#[derive(Debug,Copy,Clone,Serialize,Deserialize)]
|
pub const SHOP_LISTINGS: [Listing; 2] = [
|
||||||
|
Listing { variant: MtxVariant::ArchitectureMolecular, credits: 10 },
|
||||||
|
Listing { variant: MtxVariant::ArchitectureInvader, credits: 10 },
|
||||||
|
];
|
||||||
|
|
||||||
|
#[derive(Debug,Clone,PartialEq,Serialize,Deserialize)]
|
||||||
|
pub struct Shop {
|
||||||
|
owned: Vec<MtxVariant>,
|
||||||
|
available: Vec<Listing>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug,Copy,Clone,PartialEq,Serialize,Deserialize)]
|
||||||
|
pub struct Listing {
|
||||||
|
variant: MtxVariant,
|
||||||
|
credits: u16,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug,Copy,Clone,PartialEq,Serialize,Deserialize)]
|
||||||
pub enum MtxVariant {
|
pub enum MtxVariant {
|
||||||
Rename,
|
Rename,
|
||||||
Reimage,
|
|
||||||
ArchitectureMolecular,
|
ArchitectureMolecular,
|
||||||
ArchitectureInvader,
|
ArchitectureInvader,
|
||||||
}
|
}
|
||||||
@ -40,7 +54,6 @@ impl TryFrom<String> for MtxVariant {
|
|||||||
fn try_from(v: String) -> Result<MtxVariant, Error> {
|
fn try_from(v: String) -> Result<MtxVariant, Error> {
|
||||||
match v.as_ref() {
|
match v.as_ref() {
|
||||||
"Rename" => Ok(MtxVariant::Rename),
|
"Rename" => Ok(MtxVariant::Rename),
|
||||||
"Reimage" => Ok(MtxVariant::Reimage),
|
|
||||||
"ArchitectureMolecular" => Ok(MtxVariant::ArchitectureMolecular),
|
"ArchitectureMolecular" => Ok(MtxVariant::ArchitectureMolecular),
|
||||||
"ArchitectureInvader" => Ok(MtxVariant::ArchitectureInvader),
|
"ArchitectureInvader" => Ok(MtxVariant::ArchitectureInvader),
|
||||||
_ => Err(format_err!("mtx variant not found variant={:?}", v)),
|
_ => Err(format_err!("mtx variant not found variant={:?}", v)),
|
||||||
@ -57,25 +70,20 @@ pub struct Mtx {
|
|||||||
|
|
||||||
pub fn apply(tx: &mut Transaction, account: &Account, variant: MtxVariant, construct_id: Uuid) -> Result<Vec<Construct>, Error> {
|
pub fn apply(tx: &mut Transaction, account: &Account, variant: MtxVariant, construct_id: Uuid) -> Result<Vec<Construct>, Error> {
|
||||||
let mtx = select(tx, variant, account.id)?;
|
let mtx = select(tx, variant, account.id)?;
|
||||||
let construct = construct_select(tx, construct_id, account.id)?;
|
let mut construct = construct_select(tx, construct_id, account.id)?;
|
||||||
|
|
||||||
match mtx.variant {
|
|
||||||
MtxVariant::Reimage => reimage(tx, construct)?,
|
|
||||||
_ => unimplemented!(),
|
|
||||||
};
|
|
||||||
|
|
||||||
account::debit(tx, account.id, 1)?;
|
account::debit(tx, account.id, 1)?;
|
||||||
account::account_constructs(tx, account)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn reimage(tx: &mut Transaction, mut construct: Construct) -> Result<Construct, Error> {
|
|
||||||
construct = construct.new_img();
|
construct = construct.new_img();
|
||||||
|
match mtx.variant {
|
||||||
|
MtxVariant::ArchitectureInvader => img::invader_write(construct.img)?,
|
||||||
|
MtxVariant::ArchitectureMolecular => img::molecular_write(construct.img)?,
|
||||||
|
MtxVariant::Rename => unimplemented!(),
|
||||||
|
// _ => unimplemented!(),
|
||||||
|
};
|
||||||
|
|
||||||
img_molecular_write(construct.img)?;
|
construct_write(tx, construct)?;
|
||||||
|
account::account_constructs(tx, account)
|
||||||
construct = construct_write(tx, construct)?;
|
|
||||||
|
|
||||||
Ok(construct)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn select(tx: &mut Transaction, variant: MtxVariant, account: Uuid) -> Result<Mtx, Error> {
|
pub fn select(tx: &mut Transaction, variant: MtxVariant, account: Uuid) -> Result<Mtx, Error> {
|
||||||
@ -111,32 +119,6 @@ impl Mtx {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn account_list(tx: &mut Transaction, account: Uuid) -> Result<Vec<Mtx>, Error> {
|
|
||||||
let query = "
|
|
||||||
SELECT data, id
|
|
||||||
FROM mtx
|
|
||||||
WHERE account = $1;
|
|
||||||
";
|
|
||||||
|
|
||||||
let result = tx
|
|
||||||
.query(query, &[&account])?;
|
|
||||||
|
|
||||||
let values = result.into_iter().filter_map(|row| {
|
|
||||||
let bytes: Vec<u8> = row.get(0);
|
|
||||||
// let id: Uuid = row.get(1);
|
|
||||||
|
|
||||||
match from_slice::<Mtx>(&bytes) {
|
|
||||||
Ok(i) => Some(i),
|
|
||||||
Err(e) => {
|
|
||||||
warn!("{:?}", e);
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}).collect::<Vec<Mtx>>();
|
|
||||||
|
|
||||||
return Ok(values);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn delete(tx: &mut Transaction, id: Uuid) -> Result<(), Error> {
|
pub fn delete(tx: &mut Transaction, id: Uuid) -> Result<(), Error> {
|
||||||
let query = "
|
let query = "
|
||||||
DELETE
|
DELETE
|
||||||
@ -193,3 +175,54 @@ impl Mtx {
|
|||||||
// return Ok(self);
|
// return Ok(self);
|
||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn account_shop(tx: &mut Transaction, account: &Account) -> Result<Shop, Error> {
|
||||||
|
let query = "
|
||||||
|
SELECT variant
|
||||||
|
FROM mtx
|
||||||
|
WHERE account = $1;
|
||||||
|
";
|
||||||
|
|
||||||
|
let result = tx
|
||||||
|
.query(query, &[&account.id])?;
|
||||||
|
|
||||||
|
let mut owned = vec![];
|
||||||
|
|
||||||
|
for row in result.iter() {
|
||||||
|
let v_str: String = row.get(0);
|
||||||
|
let variant = match MtxVariant::try_from(v_str) {
|
||||||
|
Ok(v) => v,
|
||||||
|
Err(e) => {
|
||||||
|
warn!("{:?}", e);
|
||||||
|
continue;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
owned.push(variant);
|
||||||
|
};
|
||||||
|
|
||||||
|
let available = SHOP_LISTINGS.iter()
|
||||||
|
.filter(|l| !owned.contains(&l.variant))
|
||||||
|
.map(|l| *l)
|
||||||
|
.collect::<Vec<Listing>>();
|
||||||
|
|
||||||
|
debug!("account shop acount={:?} owned={:?} available={:?}",
|
||||||
|
account.name, owned, available);
|
||||||
|
|
||||||
|
return Ok(Shop { owned, available });
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn buy(tx: &mut Transaction, account: &Account, mtx: MtxVariant) -> Result<Shop, Error> {
|
||||||
|
let listing = SHOP_LISTINGS
|
||||||
|
.iter()
|
||||||
|
.find(|l| l.variant == mtx)
|
||||||
|
.ok_or(format_err!("mtx variant not found variant={:?}", mtx))?;
|
||||||
|
|
||||||
|
let account = account::debit(tx, account.id, listing.credits as i64)?;
|
||||||
|
|
||||||
|
Mtx::new(mtx, account.id)
|
||||||
|
.insert(tx)?;
|
||||||
|
|
||||||
|
info!("account purchased mtx account={:?} mtx={:?} cost={:?} balance={:?}",
|
||||||
|
account.name, mtx, listing.credits, account.balance);
|
||||||
|
account_shop(tx, &account)
|
||||||
|
}
|
||||||
@ -24,6 +24,7 @@ pub enum RpcResult {
|
|||||||
AccountState(Account),
|
AccountState(Account),
|
||||||
AccountConstructs(Vec<Construct>),
|
AccountConstructs(Vec<Construct>),
|
||||||
AccountInstances(Vec<Instance>),
|
AccountInstances(Vec<Instance>),
|
||||||
|
AccountShop(mtx::Shop),
|
||||||
GameState(Game),
|
GameState(Game),
|
||||||
ItemInfo(ItemInfoCtr),
|
ItemInfo(ItemInfoCtr),
|
||||||
|
|
||||||
@ -43,12 +44,14 @@ enum RpcRequest {
|
|||||||
|
|
||||||
MtxConstructApply { mtx: mtx::MtxVariant, construct_id: Uuid },
|
MtxConstructApply { mtx: mtx::MtxVariant, construct_id: Uuid },
|
||||||
MtxAccountApply { mtx: mtx::MtxVariant },
|
MtxAccountApply { mtx: mtx::MtxVariant },
|
||||||
|
MtxBuy { mtx: mtx::MtxVariant },
|
||||||
|
|
||||||
GameState { id: Uuid },
|
GameState { id: Uuid },
|
||||||
GameReady { id: Uuid },
|
GameReady { id: Uuid },
|
||||||
GameSkill { game_id: Uuid, construct_id: Uuid, target_construct_id: Option<Uuid>, skill: Skill },
|
GameSkill { game_id: Uuid, construct_id: Uuid, target_construct_id: Option<Uuid>, skill: Skill },
|
||||||
|
|
||||||
AccountState {},
|
AccountState {},
|
||||||
|
AccountShop {},
|
||||||
AccountConstructs {},
|
AccountConstructs {},
|
||||||
AccountInstances {},
|
AccountInstances {},
|
||||||
|
|
||||||
@ -100,6 +103,10 @@ pub fn receive(data: Vec<u8>, db: &Db, _client: &mut WebSocket<TcpStream>, begin
|
|||||||
RpcRequest::AccountInstances {} =>
|
RpcRequest::AccountInstances {} =>
|
||||||
Ok(RpcResult::AccountInstances(account_instances(&mut tx, &account)?)),
|
Ok(RpcResult::AccountInstances(account_instances(&mut tx, &account)?)),
|
||||||
|
|
||||||
|
// RpcRequest::AccountShop {} =>
|
||||||
|
// Ok(RpcResult::AccountShop(mtx::account_shop(&mut tx, &account)?)),
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// RpcRequest::ConstructDelete" => handle_construct_delete(data, &mut tx, account),
|
// RpcRequest::ConstructDelete" => handle_construct_delete(data, &mut tx, account),
|
||||||
|
|
||||||
@ -145,6 +152,9 @@ pub fn receive(data: Vec<u8>, db: &Db, _client: &mut WebSocket<TcpStream>, begin
|
|||||||
RpcRequest::MtxConstructApply { mtx, construct_id } =>
|
RpcRequest::MtxConstructApply { mtx, construct_id } =>
|
||||||
Ok(RpcResult::AccountConstructs(mtx::apply(&mut tx, account, mtx, construct_id)?)),
|
Ok(RpcResult::AccountConstructs(mtx::apply(&mut tx, account, mtx, construct_id)?)),
|
||||||
|
|
||||||
|
RpcRequest::MtxBuy { mtx } =>
|
||||||
|
Ok(RpcResult::AccountShop(mtx::buy(&mut tx, account, mtx)?)),
|
||||||
|
|
||||||
_ => Err(format_err!("unknown request request={:?}", request)),
|
_ => Err(format_err!("unknown request request={:?}", request)),
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -155,7 +165,8 @@ pub fn receive(data: Vec<u8>, db: &Db, _client: &mut WebSocket<TcpStream>, begin
|
|||||||
return response;
|
return response;
|
||||||
},
|
},
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
Err(format_err!("invalid message data={:?}", data))
|
warn!("{:?}", e);
|
||||||
|
Err(err_msg("invalid message"))
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -19,6 +19,7 @@ use serde_cbor::{to_vec};
|
|||||||
|
|
||||||
use net::TOKEN_HEADER;
|
use net::TOKEN_HEADER;
|
||||||
use rpc;
|
use rpc;
|
||||||
|
use mtx;
|
||||||
use pg::PgPool;
|
use pg::PgPool;
|
||||||
use account;
|
use account;
|
||||||
|
|
||||||
@ -66,10 +67,22 @@ pub fn start(pool: PgPool) {
|
|||||||
Some(t) => {
|
Some(t) => {
|
||||||
let db = ws_pool.get()
|
let db = ws_pool.get()
|
||||||
.expect("unable to get db connection");
|
.expect("unable to get db connection");
|
||||||
|
|
||||||
|
|
||||||
match account::from_token(&db, t) {
|
match account::from_token(&db, t) {
|
||||||
Ok(a) => {
|
Ok(a) => {
|
||||||
let state = to_vec(&rpc::RpcResult::AccountState(a.clone())).unwrap();
|
let state = to_vec(&rpc::RpcResult::AccountState(a.clone())).unwrap();
|
||||||
websocket.write_message(Binary(state)).unwrap();
|
websocket.write_message(Binary(state)).unwrap();
|
||||||
|
|
||||||
|
let mut tx = db.transaction().unwrap();
|
||||||
|
let shop = mtx::account_shop(&mut tx, &a).unwrap();
|
||||||
|
let shop = to_vec(&rpc::RpcResult::AccountShop(shop)).unwrap();
|
||||||
|
|
||||||
|
websocket.write_message(Binary(shop)).unwrap();
|
||||||
|
|
||||||
|
// tx doesn't change anything
|
||||||
|
tx.commit().unwrap();
|
||||||
|
|
||||||
Some(a)
|
Some(a)
|
||||||
},
|
},
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user