Merge branch 'warden'

This commit is contained in:
ntr 2019-05-01 01:00:54 +10:00
commit f9dad4cfb5
28 changed files with 1146 additions and 878 deletions

View File

@ -19,6 +19,7 @@ function GamePanel(props) {
setActiveCryp,
selectSkillTarget,
sendInstanceState,
sendGameReady,
activeCryp,
account,
showLog,
@ -69,18 +70,23 @@ function GamePanel(props) {
onClick={() => toggleLog(!showLog)}>
Log
</button>
<button
className="game-back-btn instance-btn instance-ui-btn right"
onClick={() => sendGameReady()}>
Ready
</button>
</div>
);
function findCryp(id) {
const team = game.teams.find(t => t.cryps.find(c => c.id === id));
const team = game.players.find(t => t.cryps.find(c => c.id === id));
if (team) return team.cryps.find(c => c.id === id);
return null;
}
const otherTeams = game.teams.filter(t => t.id !== account.id);
const otherTeams = game.players.filter(t => t.id !== account.id);
const playerTeam = game.teams.find(t => t.id === account.id);
const playerTeam = game.players.find(t => t.id === account.id);
function stackElement(c, i) {
let skills = game.stack.filter(s => s.source_cryp_id === c.id).map((s, j) => {

View File

@ -23,6 +23,10 @@ const addState = connect(
return false;
}
function sendGameReady() {
ws.sendGameReady(game.id);
}
function sendInstanceState(instanceId) {
if (!instanceId) return false;
return ws.sendInstanceState(instanceId);
@ -42,6 +46,7 @@ const addState = connect(
activeCryp,
selectSkillTarget,
sendInstanceState,
sendGameReady,
};
},

View File

@ -153,15 +153,39 @@ function Info(args) {
);
}
function playerRound(id) {
if (!instance.rounds.length) return null;
return instance.rounds[instance.rounds.length - 1].find(r => r.player_ids.includes(id));
}
function playerText(player) {
const round = playerRound(player.id);
if (!round) {
return player.ready
? 'ready'
: '';
}
if (round.finished) return 'finished';
return player.ready
? 'ready'
: '';
}
function scoreBoard() {
const players = instance.players.map((p, i) =>
const players = instance.players.map((p, i) => {
const pText = playerText(p);
console.log(pText);
return (
<tr key={i}
className={p.ready ? 'ready' : ''}>
<td>{p.name}</td>
<td>{p.score.wins} / {p.score.losses}</td>
<td>{p.ready ? 'ready' : ''}</td>
<td>{pText}</td>
</tr>
);
});
return (
<table>

View File

@ -67,10 +67,11 @@ class InstanceCreateForm extends Component {
<label htmlFor="playerSelect">players</label>
<select id="playerSelect"
disabled={disabled}
value={this.state.players}
onChange={this.playersChange}
>
<option value={1}>pve</option>
<option selected value={2}>2</option>
<option value={2}>2</option>
<option value={4}>4</option>
<option value={8}>8</option>
<option value={16}>16</option>

View File

@ -58,14 +58,14 @@ function Menu(args) {
const instanceJoinHidden = !selectedCryps.every(c => !!c);
const mmSet = (
<button
className={'menu-instance-btn left'}
disabled={instanceJoinHidden}
onClick={() => sendPlayerMmCrypsSet()}>
Set Matchmaking Team
</button>
);
// const mmSet = (
// <button
// className={'menu-instance-btn left'}
// disabled={instanceJoinHidden}
// onClick={() => sendPlayerMmCrypsSet()}>
// Set Matchmaking Team
// </button>
// );
return (
<section className="menu-instance-list" >
@ -85,7 +85,6 @@ function Menu(args) {
</tbody>
</table>
<InstanceCreateForm />
{mmSet}
</section>
);
}

View File

@ -110,7 +110,7 @@ function Vbox(args) {
if (boundTimer) {
clearTimeout(boundTimer);
if (reclaiming && i) sendVboxReclaim(i);
if (reclaiming && vbox.bound[i]) sendVboxReclaim(i);
else if (vbox.bound[i]) {
const insert = combiner.findIndex(j => j === null);
if (insert === -1) return setCombiner([i, null, null]);
@ -128,7 +128,7 @@ function Vbox(args) {
}
function boundClick(e, i) {
if (reclaiming && i) sendVboxReclaim(i);
if (reclaiming && vbox.bound[i]) sendVboxReclaim(i);
else if (vbox.bound[i]) {
const insert = combiner.findIndex(j => j === null);
if (insert === -1) return setCombiner([i, null, null]);
@ -210,6 +210,7 @@ function Vbox(args) {
return setReclaiming(!reclaiming);
}
console.log('reclaiminig', reclaiming)
const classes = `vbox ${activeVar !== null || activeCryp ? 'hidden' : ''}`;
const reclaimClass = `instance-btn instance-ui-btn vbox-btn ${reclaiming ? 'reclaiming' : ''}`;

View File

@ -8,6 +8,7 @@ function setupKeys(store) {
key('esc', () => store.dispatch(actions.setReclaiming(false)));
key('esc', () => store.dispatch(actions.setActiveSkill(null)));
key('esc', () => store.dispatch(actions.setActiveCryp(null)));
key('esc', () => store.dispatch(actions.setInfo([null, null])));
}
module.exports = setupKeys;

View File

@ -74,8 +74,8 @@ function createSocket(events) {
send({ method: 'game_state', params: { id } });
}
function sendGameJoin(gameId, crypIds) {
send({ method: 'game_join', params: { game_id: gameId, cryp_ids: crypIds } });
function sendGameReady(id) {
send({ method: 'game_ready', params: { id } });
}
function sendSpecForget(id, spec) {
@ -331,7 +331,7 @@ function createSocket(events) {
sendAccountInstances,
sendAccountZone,
sendGameState,
sendGameJoin,
sendGameReady,
sendGameSkill,
sendGameTarget,
sendCrypSpawn,

View File

@ -6,6 +6,10 @@ exports.up = async knex => {
table.index('id');
table.timestamps(true, true);
table.binary('data').notNullable();
table.boolean('finished')
.defaultTo(false)
.notNullable()
.index();
});
await knex.schema.createTable('instances', async table => {
@ -15,7 +19,7 @@ exports.up = async knex => {
table.binary('data').notNullable();
table.boolean('open')
.defaultTo(true)
.defaultTo(false)
.notNullable()
.index();
});

View File

@ -10,9 +10,10 @@ serde = "1"
serde_derive = "1"
serde_cbor = "0.9"
chrono = { version = "0.4", features = ["serde"] }
tungstenite = "0.6"
bcrypt = "0.2"
petgraph = { version = "0.4", features = ["serde-1"] }
dotenv = "0.9.0"
env_logger = "*"

View File

@ -32,7 +32,7 @@ Base specs have a base 3 cost
Round #1
All costs are base costs
# Team #1 and Team #2 (They both bought the same things)
# Player #1 and Player #2 (They both bought the same things)
Cryp #1 Strike (Attack + RR), (2 + 1 + 1) = (4) cost
Cryp #1 Empower (Buff + RR), (2 + 1 + 1) = (4) cost
Cryp #3 Attack, 2 cost
@ -51,7 +51,7 @@ The costs of red for round #2 are now (1 + 1) = 2
If they were to buy the same skill setup it would be as follows:
# Team #1 and Team #2 (They both bought the same things)
# Player #1 and Player #2 (They both bought the same things)
Cryp #1 Strike (Attack + RR), (2 + 2 + 2) = (6) cost
Cryp #1 Empower (Buff + RR), (2 + 2 + 2) = (6) cost
Cryp #3 Attack, 2 cost

View File

@ -4,16 +4,16 @@
skill phase:
1.1 -> block (sp 10) -> on self
1.2 -> attack (sp 5) -> on team 2
1.2 -> attack (sp 5) -> on player 2
2.1 -> hex (sp 3) -> on team 1
2.2 -> attack (sp 5) -> on team 1
2.1 -> hex (sp 3) -> on player 1
2.2 -> attack (sp 5) -> on player 1
target phase:
team 2 targets 1.2 on 2.2
player 2 targets 1.2 on 2.2
team 1 targets 2.1 on 1.1
team 1 targets 2.2 on 1.1
player 1 targets 2.1 on 1.1
player 1 targets 2.2 on 1.1
resolve phase:
1.1 <- block
@ -116,7 +116,7 @@ Its members now scour the lands in search of magic, censoring its teaching, purg
* Silence
* Magic resistance
* Information gathering
* team composition
* player composition
* available skills etc
Universal Chaos

View File

@ -1,10 +1,10 @@
### Specs ###
Numbers are placeholder
`Specs get a bonus dependent on the total of Red / Green / Blue in team skills & specs`
`Specs get a bonus dependent on the total of Red / Green / Blue in player skills & specs`
# Example to meet 5 red gem bonus from skills only
In your team Cryp #1 has `Strike`, Cryp #2 has `Slay` and `Heal`, Cryp #3 has `Snare`
In your player Cryp #1 has `Strike`, Cryp #2 has `Slay` and `Heal`, Cryp #3 has `Snare`
- RR skill `Strike` contributes 2 red gems to the total red gems (2 total)
- RG skill `Slay` contributes 1 red gem to the total red gems (3 total)
- GG skill `Heal` contirubtes 0 red gems to the total red gems (3 total)
@ -30,7 +30,7 @@ In your team Cryp #1 has `Strike`, Cryp #2 has `Slay` and `Heal`, Cryp #3 has `S
Cryp #2 -> Give Attack -> Attack
Cryp #3 -> Give Stun -> Stun
Team Total (4 Red + 2 Basic gems)
Player Total (4 Red + 2 Basic gems)
### Round 2
@ -87,12 +87,12 @@ In your team Cryp #1 has `Strike`, Cryp #2 has `Slay` and `Heal`, Cryp #3 has `S
# Basic % GreenLife
`Base` -> 5% inc hp
`Team Bonus` -> 3 basic gems -> +5% // 6 basic gems -> +10% // 12 basic gems -> +15%
`Player Bonus` -> 3 basic gems -> +5% // 6 basic gems -> +10% // 12 basic gems -> +15%
Maximum 35% inc hp
# Basic Speed
`Base` -> 5% inc speed
`Team Bonus` -> 3 basic gems -> +10% // 6 basic gems -> +15% // 12 basic gems -> +20%
`Player Bonus` -> 3 basic gems -> +10% // 6 basic gems -> +15% // 12 basic gems -> +20%
Maximum 50% inc speed
# Basic Class Spec
@ -106,37 +106,37 @@ Generate by combining `Generic Spec (Basic Damage)` with respective RGB
# Red Damage (Dmg + RR)
Add 2 `red gems`
`Base` -> 10% inc red dmg
`Team Bonus` 5 red gems -> +10% // 10 red gems -> +15% // 20 red gems -> +25%
`Player Bonus` 5 red gems -> +10% // 10 red gems -> +15% // 20 red gems -> +25%
Maximum +60% red damage
# Blue Damage (Dmg + BB) #
Add 2 `blue gems`
`Base` -> 10% inc blue dmg
`Team Bonus` 5 blue gems -> +10% // 10 blue gems -> +15% // 20 blue gems -> +25%
`Player Bonus` 5 blue gems -> +10% // 10 blue gems -> +15% // 20 blue gems -> +25%
Maximum +60% blue damage
# Healing (Dmg + GG) #
Add 2 `green gems`
`Base` -> 10% inc healing
`Team Bonus` 5 green gems -> +10% // 10 green gems -> +15% // 20 green gems -> +25%
`Player Bonus` 5 green gems -> +10% // 10 green gems -> +15% // 20 green gems -> +25%
Maximum +60% inc healing
# Red damage and healing (Dmg + RG)
Add 1 red 1 green gem
`Base` -> 5% inc red damage and 5% inc healing
`Team Bonus` (2R + 2G gems) -> +5% + 5% // (5R + 5G gems) -> +10% + 10% % // (10R + 10G) gems -> +15% + 15%
`Player Bonus` (2R + 2G gems) -> +5% + 5% // (5R + 5G gems) -> +10% + 10% % // (10R + 10G) gems -> +15% + 15%
Maximum +35% inc red damage and 35% inc healing
# Red and blue damage (Dmg + RB)
Add 1 red and 1 blue gem
`Base` -> 5% inc red damage and 5% inc healing
`Team Bonus` (2 red + 2 green gems) -> +5% + 5% // (5 red + 5 green gems) -> +10% + 10% % // 20 green gems -> +15% + 15%
`Player Bonus` (2 red + 2 green gems) -> +5% + 5% // (5 red + 5 green gems) -> +10% + 10% % // 20 green gems -> +15% + 15%
Maximum +35% inc damage and 35% inc healing
# Blue damage and healing (Dmg + BG)
Add 1 blue and 1 green gem
`Base` -> 5% inc blue damage and 5% inc healing
`Team Bonus` (2B + 2G gems) -> +5% + 5% // (5B + 5G gems) -> +10% + 10% % // (10B + 10G) gems -> +15% + 15%
`Player Bonus` (2B + 2G gems) -> +5% + 5% // (5B + 5G gems) -> +10% + 10% % // (10B + 10G) gems -> +15% + 15%
Maximum +35% inc blue damage and 35% inc healing
### Increased GreenLife Combos ###
@ -146,37 +146,37 @@ Generate by combining `Generic Spec (Basic GreenLife)` with respective RGB
# Increased % Red Life (Basic %HP + 2R)
Add 2 `red gems`
`Base` -> 10% inc red shield
`Team Bonus` 5 red gems -> +10% // 10 red gems -> +15% // 20 red gems -> +20%
`Player Bonus` 5 red gems -> +10% // 10 red gems -> +15% // 20 red gems -> +20%
Maximum +55% inc red shield
# Increased % Red Life and GreenLife (Basic %HP + 1R1G)
Add 1 red 1 green gem
`Base` -> 5% inc red shield and 5% inc hp
`Team Bonus` (2R + 2G gems) -> +5% + 5% // (5R + 5G gems) -> +10% + 10% % // (10R + 10G) gems -> +15% + 15%
`Player Bonus` (2R + 2G gems) -> +5% + 5% // (5R + 5G gems) -> +10% + 10% % // (10R + 10G) gems -> +15% + 15%
Maximum +35% inc red shield and 35% inc hp
# Increased % Blue Life (Basic %HP + 2B)
Add 2 `blue gems`
`Base` -> 10% inc red shield
`Team Bonus` 5 blue gems -> +10% // 10 blue gems -> +15% // 20 blue gems -> +20%
`Player Bonus` 5 blue gems -> +10% // 10 blue gems -> +15% // 20 blue gems -> +20%
Maximum +55% inc blue shield
# Increased % Blue Life and GreenLife (Basic %HP + 1B1G)
Add `1 blue and 1 green gems`
`Base` -> 5% inc red shield and 5% inc hp
`Team Bonus` (2B + 2G gems) -> +5% + 5% // (5B + 5G gems) -> +10% + 10% % // (10B + 10G) gems -> +15% + 15%
`Player Bonus` (2B + 2G gems) -> +5% + 5% // (5B + 5G gems) -> +10% + 10% % // (10B + 10G) gems -> +15% + 15%
Maximum +35% inc blue shield and 35% inc hp
# Increased % GreenLife (Basic %HP + 2G)
Add `2 green gems`
`Base` -> 10% inc hp
`Team Bonus` 5 green gems -> +10% // 10 green gems -> +15% // 20 green gems -> +20%
`Player Bonus` 5 green gems -> +10% // 10 green gems -> +15% // 20 green gems -> +20%
Maximum +55% inc hp
# Increased % Blue and Red Life (Basic %HP + 1B1R)
Add `1 blue and 1 red gem`
`Base` -> 5% inc red shield and 5% inc hp
`Team Bonus` (2B + 2R gems) -> +5% + 5% // (5B + 5R gems) -> +10% + 10% % // (10B + 10R) gems -> +15% + 15%
`Player Bonus` (2B + 2R gems) -> +5% + 5% // (5B + 5R gems) -> +10% + 10% % // (10B + 10R) gems -> +15% + 15%
Maximum +35% inc blue shield and 35% inc red shield
## Upgraded Attack Spec Combos
@ -185,31 +185,31 @@ Maximum +35% inc blue shield and 35% inc red shield
Cryp Requires `8 red gems`
Adds `6 red gems`
`Base` -> 15% increased strike damage
`Team Bonus` 15 red gems -> +15% // 20 red gems -> +20% // 30 red gems -> +30%
`Player Bonus` 15 red gems -> +15% // 20 red gems -> +20% // 30 red gems -> +30%
Maximum 80% increased strike damage
# Improved Heal (Combine Heal + Healing Spec x 2)
Cryp Requires `8 green gems`
`Base` -> 15% increased heal healing
`Team Bonus` 15 green gems -> +15% // 20 green gems -> +20% // 30 green gems -> +30%
`Player Bonus` 15 green gems -> +15% // 20 green gems -> +20% // 30 green gems -> +30%
Maximum 80% increased heal healing
# Increased Blast Damage (Combine Blast + Blue Spec x 2)
Cryp Requires `8 blue gems`
`Base` -> 15% increased blast damage
`Team Bonus` 15 blue gems -> +15% // 20 blue gems -> +20% // 30 blue gems -> +30%
`Player Bonus` 15 blue gems -> +15% // 20 blue gems -> +20% // 30 blue gems -> +30%
Maximum 80% increased blast damage
# Increased Slay Damage (Combine Slay + Red Damage Spec + Healing Spec)
Cryp Requires `4 red 4 green gems`
`Base` -> 15% increased slay damage
`Team Bonus` (8R + 8G) gems -> +15% // (10R + 10G) gems -> +20% // (15R + 15G) gems -> +30%
`Player Bonus` (8R + 8G) gems -> +15% // (10R + 10G) gems -> +20% // (15R + 15G) gems -> +30%
Maximum 80% increased slay damage
# Increased Banish Damage (Combine Slay + Red Damage Spec + Blue Damage Spec)
Cryp Requires `4 red 4 blue gems`
`Base` -> 15% increased slay damage
`Team Bonus` (8R + 8B) gems -> +15% // (10R + 10B) gems -> +20% // (15R + 15B) gems -> +30%
`Player Bonus` (8R + 8B) gems -> +15% // (10R + 10B) gems -> +20% // (15R + 15B) gems -> +30%
Maximum 80% increased banish damage
## Other Combos
@ -217,7 +217,7 @@ Maximum 80% increased banish damage
# Increased % Red Speed (Basic Speed + 2R)
Add 2 red gems
`Base` -> 15% inc red speed
`Team Bonus` 5 red gems -> +15% // 10 red gems -> +20% // 20 red gems -> +25%
`Player Bonus` 5 red gems -> +15% // 10 red gems -> +20% // 20 red gems -> +25%
Maximum 80% inc red speed
# Nature Affinity (Basic Class spec + 2R)

View File

@ -16,14 +16,22 @@
# WORK WORK
## NOW
*INSTANCES*
*WARDEN*
* games
check updated timestamps
once a second?
add a timestamp to each player
after 30s issue warning (client)
after 1m automove
increment warnings
after 3 warnings forfeit
* instances
add timestamp to each player
after 60s force ready
lobby opens
add player
add player
players ready
on start -> vbox
*CLIENT*
* general
@ -76,6 +84,13 @@ make strike *really* hit first / resolve at same time?
## LATER
* redis for game events
* store instances / games in redis?
* not sure hwo to get sets of player games
* set joined_games_$account [game_id]
* move player -> player
* chat
* notifications
* elo + leaderboards
@ -106,7 +121,7 @@ $$$
* empower on ko
# Mechanic Ideas
teams
players
1v1 2v2 3v3
gem td style attr combinations

View File

@ -122,7 +122,7 @@ impl CrypStat {
// self.recalculate(specs)
// }
pub fn recalculate(&mut self, specs: &Vec<Spec>, team_colours: &Colours) -> &mut CrypStat {
pub fn recalculate(&mut self, specs: &Vec<Spec>, player_colours: &Colours) -> &mut CrypStat {
let specs = specs
.iter()
.filter(|s| s.affects().contains(&self.stat))
@ -131,7 +131,7 @@ impl CrypStat {
// applied with fold because it can be zeroed or multiplied
// but still needs access to the base amount
let value = specs.iter().fold(self.base, |acc, s| s.apply(acc, self.base, team_colours));
let value = specs.iter().fold(self.base, |acc, s| s.apply(acc, self.base, player_colours));
self.value = value;
self.max = value;
@ -259,17 +259,17 @@ impl Cryp {
self
}
pub fn apply_modifiers(&mut self, team_colours: &Colours) -> &mut Cryp {
pub fn apply_modifiers(&mut self, player_colours: &Colours) -> &mut Cryp {
self.specs.sort_unstable();
self.red_damage.recalculate(&self.specs, team_colours);
self.red_life.recalculate(&self.specs, team_colours);
self.blue_damage.recalculate(&self.specs, team_colours);
self.blue_life.recalculate(&self.specs, team_colours);
self.evasion.recalculate(&self.specs, team_colours);
self.speed.recalculate(&self.specs, team_colours);
self.green_damage.recalculate(&self.specs, team_colours);
self.green_life.recalculate(&self.specs, team_colours);
self.red_damage.recalculate(&self.specs, player_colours);
self.red_life.recalculate(&self.specs, player_colours);
self.blue_damage.recalculate(&self.specs, player_colours);
self.blue_life.recalculate(&self.specs, player_colours);
self.evasion.recalculate(&self.specs, player_colours);
self.speed.recalculate(&self.specs, player_colours);
self.green_damage.recalculate(&self.specs, player_colours);
self.green_life.recalculate(&self.specs, player_colours);
self
}
@ -278,6 +278,11 @@ impl Cryp {
self.green_life.value == 0
}
pub fn force_ko(&mut self) -> &mut Cryp {
self.green_life.value = 0;
self
}
pub fn immune(&self, skill: Skill) -> Option<Immunity> {
// also checked in resolve stage so shouldn't happen really
if self.is_ko() {
@ -836,21 +841,21 @@ mod tests {
}
#[test]
fn cryp_team_modifiers_test() {
fn cryp_player_modifiers_test() {
let mut cryp = Cryp::new()
.named(&"team player".to_string());
.named(&"player player".to_string());
cryp.spec_add(Spec::RedDamageI).unwrap();
cryp.spec_add(Spec::GreenDamageI).unwrap();
cryp.spec_add(Spec::BlueDamageI).unwrap();
let team_colours = Colours {
let player_colours = Colours {
red: 5,
green: 15,
blue: 25,
};
cryp.apply_modifiers(&team_colours);
cryp.apply_modifiers(&player_colours);
assert!(cryp.red_damage.value == cryp.red_damage.base + cryp.red_damage.base.pct(20));
assert!(cryp.green_damage.value == cryp.green_damage.base + cryp.green_damage.base.pct(40));

File diff suppressed because it is too large Load Diff

View File

@ -9,12 +9,16 @@ use failure::err_msg;
use std::iter;
// timekeeping
use chrono::prelude::*;
use chrono::Duration;
use rpc::{InstanceLobbyParams, InstanceJoinParams, InstanceReadyParams, InstanceStateParams};
use account::Account;
use player::{Player, Score, player_create, player_get, player_update};
use player::{Player, player_create, player_get, player_global_update};
use cryp::{Cryp, cryp_get};
use mob::{instance_mobs};
use game::{Game, Phase, Team, game_get, game_write, game_instance_new, game_instance_join, game_global_get, game_global_set};
use game::{Game, Phase, game_get, game_write, game_instance_new};
use vbox::{Var};
use rpc::{RpcResult};
use names::{name};
@ -29,7 +33,7 @@ enum InstancePhase {
#[derive(Debug,Clone,Serialize,Deserialize)]
struct Round {
player_ids: Vec<Uuid>,
game_id: Uuid,
game_id: Option<Uuid>,
finished: bool,
}
@ -41,8 +45,10 @@ pub struct Instance {
rounds: Vec<Vec<Round>>,
open: bool,
max_players: usize,
max_rounds: usize,
password: Option<String>,
pub name: String,
phase_start: DateTime<Utc>,
}
impl Instance {
@ -54,8 +60,10 @@ impl Instance {
phase: InstancePhase::Lobby,
open: true,
max_players: 2,
max_rounds: 16,
name: String::new(),
password: None,
phase_start: Utc::now(),
}
}
@ -67,11 +75,44 @@ impl Instance {
phase: InstancePhase::InProgress,
open: false,
max_players: 0,
max_rounds: 1,
name: "Global Matchmaking".to_string(),
password: None,
phase_start: Utc::now(),
}
}
fn phase_timed_out(&self) -> bool {
Utc::now().signed_duration_since(self.phase_start).num_seconds() > 60
}
fn timed_out_players(&self) -> Vec<Uuid> {
self.players
.iter()
.filter(|p| !p.ready)
.filter(|p| self.current_game_id(p.id).is_none())
.map(|p| p.id)
.collect::<Vec<Uuid>>()
}
pub fn upkeep(mut self) -> (Instance, Vec<Game>) {
if self.phase != InstancePhase::InProgress {
return (self, vec![]);
}
if !self.phase_timed_out() {
return (self, vec![]);
}
let new_games = self
.timed_out_players()
.iter()
.filter_map(|p| self.player_ready(*p).unwrap())
.collect::<Vec<Game>>();
(self, new_games)
}
fn set_max_players(mut self, max: usize) -> Result<Instance, Error> {
if max > 16 || max % 2 != 0 {
return Err(err_msg("max players must be divisible by 2 and less than 16"));
@ -90,12 +131,21 @@ impl Instance {
Ok(self)
}
fn set_max_rounds(mut self, rounds: usize) -> Result<Instance, Error> {
if rounds == 0 {
return Err(err_msg("max rounds must be nonzero"));
}
self.max_rounds = rounds;
Ok(self)
}
fn add_bots(mut self) -> Instance {
self.open = false;
self.players = iter::repeat_with(|| {
let bot_id = Uuid::new_v4();
let cryps = instance_mobs(bot_id);
let mut p = Player::new(bot_id, self.id, &name(), cryps).set_bot(true);
let mut p = Player::new(bot_id, &name(), cryps).set_bot(true);
p.set_ready(true);
p
})
@ -114,87 +164,98 @@ impl Instance {
Ok(self)
}
pub fn player_update(mut self, player: Player, ignore_phase: bool) -> Result<Instance, Error> {
if !ignore_phase && self.phase != InstancePhase::InProgress {
return Err(format_err!("instance not in vbox phase ({:?})", self.phase));
}
let i = self.players
.iter()
.position(|p| p.id == player.id)
.ok_or(err_msg("player_id not found"))?;
self.players[i] = player;
Ok(self)
}
fn player_ready(&mut self, player_id: Uuid) -> Result<&mut Instance, Error> {
fn player_ready(&mut self, player_id: Uuid) -> Result<Option<Game>, Error> {
if ![InstancePhase::InProgress, InstancePhase::Lobby].contains(&self.phase) {
return Err(err_msg("instance not in start or vbox phase"));
}
// LOBBY CHECKS
if self.phase == InstancePhase::Lobby {
let i = self.players
.iter_mut()
.position(|p| p.id == player_id)
.ok_or(err_msg("player_id not found"))?;
if self.phase != InstancePhase::Lobby && self.players[i].cryps.iter().all(|c| c.skills.len() == 0) {
return Err(err_msg("your cryps have no skills"));
let v = !self.players[i].ready;
self.players[i].set_ready(v);
match self.can_start() {
true => {
self.start();
return Ok(None);
}
false => return Ok(None),
};
}
// GAME PHASE READY
let i = self.players
.iter_mut()
.position(|p| p.id == player_id)
.ok_or(err_msg("player_id not found"))?;
let v = !self.players[i].ready;
self.players[i].set_ready(v);
if self.phase == InstancePhase::Lobby && self.can_start() {
self.start();
// start the game even if afk noobs have no skills
if !self.phase_timed_out() && self.players[i].cryps.iter().all(|c| c.skills.len() == 0) {
return Err(err_msg("your cryps have no skills"));
}
Ok(self)
// create a game object if both players are ready
// this should only happen once
let all_ready = self.round_ready_check(player_id);
if !all_ready {
return Ok(None);
}
fn player_has_pve_game(&self, player_id: Uuid) -> bool {
let opponent_id = self.current_round(player_id).player_ids
.iter()
.find(|p| **p != player_id)
.expect("unable to find opponent");
let game = self.create_round_game(player_id);
return self.players
.iter()
.find(|p| p.id == *opponent_id)
.expect("unable to find opponent")
.bot;
{
let round_num = self.rounds.len() - 1;
let current_round = self.rounds[round_num]
.iter_mut()
.find(|g| g.player_ids.contains(&player_id))
.unwrap();
current_round.game_id = Some(game.id);
}
fn bot_vs_player_game(&self, player_id: Uuid) -> Result<Game, Error> {
return Ok(Some(game));
}
fn round_ready_check(&mut self, player_id: Uuid) -> bool {
let current_round = self.current_round(player_id);
let bot_id = current_round.player_ids.iter().find(|id| **id != player_id).unwrap();
let plr = self.players.clone().into_iter().find(|p| p.id == player_id).unwrap();
let bot = self.players.clone().into_iter().find(|p| p.id == *bot_id).unwrap();
self.players
.iter()
.filter(|p| current_round.player_ids.contains(&p.id))
.all(|p| p.ready)
}
// maybe just embed the games in the instance
// but seems hella inefficient
fn create_round_game(&self, player_id: Uuid) -> Game {
let current_round = self.current_round(player_id);
let mut game = Game::new();
game.id = current_round.game_id;
game
.set_team_num(2)
.set_team_size(3)
.set_player_num(2)
.set_player_cryps(3)
.set_instance(self.id);
// add the players
let mut plr_team = Team::new(plr.id);
plr_team.set_cryps(plr.cryps);
// create the initiators player
for player in self.players
.clone()
.into_iter()
.filter(|p| current_round.player_ids.contains(&p.id)) {
game.player_add(player).unwrap();
}
let mut bot_team = Team::new(bot.id);
bot_team.set_cryps(bot.cryps);
bot_team.set_bot();
game
.team_add(plr_team)?
.team_add(bot_team)?;
game = game.start();
Ok(game)
assert!(game.can_start());
return game.start();
}
fn can_start(&self) -> bool {
@ -209,120 +270,46 @@ impl Instance {
fn next_round(&mut self) -> &mut Instance {
self.phase = InstancePhase::InProgress;
self.phase_start = Utc::now();
if self.rounds.len() >= self.max_rounds {
return self.finish();
}
self.players.iter_mut().for_each(|p| {
p.ready = false;
p.set_ready(false);
p.vbox.fill();
});
self.generate_rounds();
self.bot_vbox_phase();
self.bot_games_phase();
self.bot_round_actions();
self
}
fn all_ready(&self) -> bool {
self.players.iter().all(|p| p.ready)
fn finish(&mut self) -> &mut Instance {
self.phase = InstancePhase::Finished;
self
}
fn game_finished(&mut self, game: &Game) -> Result<&mut Instance, Error> {
let round_num = self.rounds.len() - 1;
self.rounds[round_num]
.iter_mut()
.find(|r| r.game_id == game.id)
.ok_or(err_msg("could not find matchup in current round"))?
.finished = true;
let winner = game.winner().ok_or(err_msg("game not finished"))?;
for team in game.teams.iter() {
let mut player = self.account_player(team.id)?;
match team.id == winner.id {
true => player.add_win(),
false => player.add_loss(),
};
}
if self.all_games_finished() {
self.next_round();
}
Ok(self)
}
fn all_games_finished(&self) -> bool {
match self.rounds.last() {
Some(r) => r.iter().all(|g| g.finished),
None => true,
}
}
fn bot_vbox_phase(&mut self) -> &mut Instance {
fn bot_round_actions(&mut self) -> &mut Instance {
for bot in self.players.iter_mut().filter(|p| p.bot) {
bot.vbox.fill();
bot.autobuy();
bot.set_ready(true);
}
self
}
fn bot_games_phase(&mut self) -> &mut Instance {
if self.phase != InstancePhase::InProgress {
panic!("instance not in progress phase");
}
let r = self.rounds.len() - 1;
// println!("round num {:?}", r);
// println!("{:?}", self.rounds[r]);
for mut round in self.rounds[r].iter_mut() {
if self.players
let games = self.players
.clone()
.iter()
.filter(|p| round.player_ids.contains(&p.id) && p.bot && p.ready)
.count() == 2 {
// println!("should play a game between {:?}", round.player_ids);
let a = self.players.clone().into_iter().find(|p| p.id == round.player_ids[0]).unwrap();
let b = self.players.clone().into_iter().find(|p| p.id == round.player_ids[1]).unwrap();
// println!("{:?} vs {:?}", a.name, b.name);
let mut game = Game::new();
game
.set_team_num(2)
.set_team_size(3);
// add the players
let mut a_team = Team::new(a.id);
a_team.set_cryps(a.cryps);
a_team.set_bot();
let mut b_team = Team::new(b.id);
b_team.set_cryps(b.cryps);
b_team.set_bot();
game
.team_add(a_team).unwrap()
.team_add(b_team).unwrap();
game = game.start();
assert!(game.finished());
let winner = match game.winner() {
Some(w) => w,
None => panic!("game has no winner {:?}", game),
};
round.finished = true;
for team in game.teams.iter() {
let mut player = self.players.iter_mut().find(|p| p.id == team.id).unwrap();
match team.id == winner.id {
true => player.add_win(),
false => player.add_loss(),
};
}
.filter(|b| b.bot)
.filter_map(|b| self.player_ready(b.id).unwrap())
.collect::<Vec<Game>>();
for game in games {
if game.finished() {
self.game_finished(&game).unwrap();
} else {
println!("{:?} unfishededes", game);
}
}
@ -350,7 +337,7 @@ impl Instance {
.enumerate()
.map(|(i, id)| Round {
player_ids: vec![*id, matched_players[np - (i + 1)]],
game_id: Uuid::new_v4(),
game_id: None,
finished: false,
})
.collect::<Vec<Round>>();
@ -371,32 +358,60 @@ impl Instance {
current_round
}
fn current_game(&mut self, player_id: Uuid) -> Option<Uuid> {
fn current_game_id(&self, player_id: Uuid) -> Option<Uuid> {
if self.phase == InstancePhase::Lobby {
return None;
}
let current_round = self.current_round(player_id);
let can_start = self.players
.iter()
.filter(|p| current_round.player_ids.contains(&p.id))
.all(|p| p.ready);
match can_start {
true => Some(current_round.game_id),
false => None,
}
if current_round.finished || current_round.game_id.is_none() {
return None;
}
fn scores(&self) -> Vec<(String, Score)> {
let mut scores = self.players.iter()
.map(|p| (p.name.clone(), p.score))
.collect::<Vec<(String, Score)>>();
scores.sort_unstable_by_key(|s| s.1.wins);
scores.reverse();
return current_round.game_id;
}
scores
fn game_finished(&mut self, game: &Game) -> Result<&mut Instance, Error> {
let round_num = self.rounds.len() - 1;
self.rounds[round_num]
.iter_mut()
.filter(|r| r.game_id.is_some())
.find(|r| r.game_id.unwrap() == game.id)
.ok_or(err_msg("could not find matchup in current round"))?
.finished = true;
// if you don't win, you lose
// ties can happen if both players forfeit
let winner_id = match game.winner() {
Some(w) => w.id,
None => Uuid::nil(),
};
for player in game.players.iter() {
let mut player = self.account_player(player.id)?;
match player.id == winner_id {
true => player.add_win(),
false => player.add_loss(),
};
}
if self.all_games_finished() {
self.next_round();
}
Ok(self)
}
fn all_ready(&self) -> bool {
self.players.iter().all(|p| p.ready)
}
fn all_games_finished(&self) -> bool {
match self.rounds.last() {
Some(r) => r.iter().all(|g| g.finished),
None => true,
}
}
// PLAYER ACTIONS
@ -407,37 +422,54 @@ impl Instance {
.ok_or(err_msg("account not in instance"))
}
pub fn vbox_action_allowed(&self, account: Uuid) -> Result<(), Error> {
if self.phase == InstancePhase::Lobby {
return Err(err_msg("game not yet started"));
}
if self.current_game_id(account).is_some() {
return Err(err_msg("you cannot perform vbox actions while in a game"));
}
Ok(())
}
pub fn vbox_discard(mut self, account: Uuid) -> Result<Instance, Error> {
self.vbox_action_allowed(account)?;
self.account_player(account)?
.vbox_discard()?;
Ok(self)
}
pub fn vbox_accept(mut self, account: Uuid, group: usize, index: usize) -> Result<Instance, Error> {
self.vbox_action_allowed(account)?;
self.account_player(account)?
.vbox_accept(group, index)?;
Ok(self)
}
pub fn vbox_combine(mut self, account: Uuid, indices: Vec<usize>) -> Result<Instance, Error> {
self.vbox_action_allowed(account)?;
self.account_player(account)?
.vbox_combine(indices)?;
Ok(self)
}
pub fn vbox_reclaim(mut self, account: Uuid, index: usize) -> Result<Instance, Error> {
self.vbox_action_allowed(account)?;
self.account_player(account)?
.vbox_reclaim(index)?;
Ok(self)
}
pub fn vbox_apply(mut self, account: Uuid, index: usize, cryp_id: Uuid) -> Result<Instance, Error> {
self.vbox_action_allowed(account)?;
self.account_player(account)?
.vbox_apply(index, cryp_id)?;
Ok(self)
}
pub fn vbox_unequip(mut self, account: Uuid, target: Var, cryp_id: Uuid) -> Result<Instance, Error> {
self.vbox_action_allowed(account)?;
self.account_player(account)?
.vbox_unequip(target, cryp_id)?;
Ok(self)
@ -485,7 +517,8 @@ pub fn instance_get(tx: &mut Transaction, instance_id: Uuid) -> Result<Instance,
let query = "
SELECT *
FROM instances
WHERE id = $1;
WHERE id = $1
FOR UPDATE;
";
let result = tx
@ -542,6 +575,33 @@ pub fn instance_get_open(tx: &mut Transaction) -> Result<Instance, Error> {
return Ok(instance);
}
pub fn instances_need_upkeep(tx: &mut Transaction) -> Result<Vec<Instance>, Error> {
let query = "
SELECT data, id
FROM instances
WHERE id != '00000000-0000-0000-0000-000000000000';
";
let result = tx
.query(query, &[])?;
let mut list = vec![];
for row in result.into_iter() {
let bytes: Vec<u8> = row.get(0);
let id = row.get(1);
match from_slice::<Instance>(&bytes) {
Ok(i) => list.push(i),
Err(_e) => {
instance_delete(tx, id)?;
}
};
}
return Ok(list);
}
pub fn instance_new(params: InstanceLobbyParams, tx: &mut Transaction, account: &Account) -> Result<Instance, Error> {
let mut instance = match params.players {
1 => Instance::new()
@ -568,84 +628,56 @@ pub fn instance_join(params: InstanceJoinParams, tx: &mut Transaction, account:
.collect::<Result<Vec<Cryp>, Error>>()?;
if cryps.len() != 3 {
return Err(format_err!("incorrect team size. ({:})", 3));
return Err(format_err!("incorrect player size. ({:})", 3));
}
let player = player_create(tx, Player::new(account.id, instance.id, &account.name, cryps), account)?;
let player = player_create(tx, Player::new(account.id, &account.name, cryps), instance.id, account)?;
instance.add_player(player)?;
instance_update(tx, instance)
}
pub fn instance_ready_global(tx: &mut Transaction, _account: &Account, player: Player) -> Result<Game, Error> {
// get the game
let game = match game_global_get(tx) {
Ok(g) => {
println!("received global game {:?}", g.id);
// if there is one try to join
match game_instance_join(tx, player.clone(), g.id) {
Ok(g) => g,
// if fails make a new one
Err(_e) => game_instance_new(tx, vec![player], Uuid::new_v4(), Uuid::nil())?,
}
},
// if not found make a new one
Err(_) => game_instance_new(tx, vec![player], Uuid::new_v4(), Uuid::nil())?,
};
// pub fn instance_ready_global(tx: &mut Transaction, _account: &Account, player: Player) -> Result<Game, Error> {
// // get the game
// let game = match game_global_get(tx) {
// Ok(g) => {
// println!("received global game {:?}", g.id);
// // if there is one try to join
// match game_instance_join(tx, player.clone(), g.id) {
// Ok(g) => g,
// // if fails make a new one
// Err(_e) => game_instance_new(tx, vec![player], Uuid::new_v4(), Uuid::nil())?,
// }
// },
// // if not found make a new one
// Err(_) => game_instance_new(tx, vec![player], Uuid::new_v4(), Uuid::nil())?,
// };
// set the current game
game_global_set(tx, &game)?;
Ok(game)
}
pub fn instance_scores(params: InstanceReadyParams, tx: &mut Transaction, _account: &Account) -> Result<Vec<(String, Score)>, Error> {
let scores = instance_get(tx, params.instance_id)?.scores();
Ok(scores)
}
// // set the current game
// game_global_set(tx, &game)?;
// Ok(game)
// }
pub fn instance_ready(params: InstanceReadyParams, tx: &mut Transaction, account: &Account) -> Result<Instance, Error> {
let mut instance = instance_get(tx, params.instance_id)?;
let player_id = instance.account_player(account.id)?.id;
instance.player_ready(player_id)?;
if let Some(game_id) = instance.current_game(player_id) {
match instance.player_has_pve_game(player_id) {
true => match game_get(tx, game_id) {
Ok(g) => g,
Err(_) => {
let game = instance.bot_vs_player_game(player_id)?;
game_write(&game, tx)?;
game
},
},
false => {
let opponent_id = *instance
.current_round(account.id)
.player_ids
.iter()
.find(|p| **p != account.id)
.expect("could not find opponent");
let a = instance.account_player(account.id)?.clone();
let b = instance.account_player(opponent_id)?.clone();
let teams = vec![a, b];
game_instance_new(tx, teams, game_id, instance.id)?
}
};
if let Some(game) = instance.player_ready(player_id)? {
game_write(tx, &game)?;
}
instance_update(tx, instance)
}
pub fn instance_state(params: InstanceStateParams, tx: &mut Transaction, account: &Account) -> Result<RpcResult, Error> {
let mut instance = instance_get(tx, params.instance_id)?;
let instance = instance_get(tx, params.instance_id)?;
if let Some(game_id) = instance.current_game(account.id) {
if let Some(game_id) = instance.current_game_id(account.id) {
let game = game_get(tx, game_id)?;
// return the game until it's finished
if game.phase != Phase::Finish {
return Ok(RpcResult::GameState(game))
}
}
@ -656,14 +688,14 @@ pub fn instance_state(params: InstanceStateParams, tx: &mut Transaction, account
pub fn global_game_finished(tx: &mut Transaction, game: &Game) -> Result<(), Error> {
let winner = game.winner().ok_or(err_msg("game not finished"))?;
for team in game.teams.iter() {
let mut player = player_get(tx, team.id, Uuid::nil())?;
match team.id == winner.id {
for player in game.players.iter() {
let mut player = player_get(tx, player.id, Uuid::nil())?;
match player.id == winner.id {
true => player.add_win(),
false => player.add_loss(),
};
player.vbox.fill();
player_update(tx, player, true)?;
player_global_update(tx, player, true)?;
}
Ok(())
@ -687,11 +719,12 @@ mod tests {
fn instance_pve_test() {
let mut instance = Instance::new()
.set_max_players(16).expect("unable to set max players")
.set_max_rounds(2).expect("max rounds failure")
.add_bots();
let player_account = Uuid::new_v4();
let cryps = instance_mobs(player_account);
let player = Player::new(player_account, instance.id, &"test".to_string(), cryps).set_bot(true);
let player = Player::new(player_account, &"test".to_string(), cryps).set_bot(true);
let player_id = player.id;
instance.add_player(player).expect("could not add player");
@ -699,21 +732,9 @@ mod tests {
assert_eq!(instance.phase, InstancePhase::Lobby);
instance.player_ready(player_id).unwrap();
assert_eq!(instance.phase, InstancePhase::InProgress);
assert_eq!(instance.phase, InstancePhase::Finished);
assert_eq!(instance.rounds[0].len(), 8);
instance.player_ready(player_id).unwrap();
assert!(instance.all_games_finished());
instance.next_round();
instance.player_ready(player_id).unwrap();
instance.next_round();
instance.player_ready(player_id).unwrap();
assert_eq!(instance.rounds.len(), 3);
assert_eq!(instance.rounds.len(), 2);
}
#[test]
@ -721,7 +742,7 @@ mod tests {
let instance = Instance::new();
let player_account = Uuid::new_v4();
let cryps = instance_mobs(player_account);
let _player = Player::new(player_account, instance.id, &"test".to_string(), cryps).set_bot(true);
let _player = Player::new(player_account, &"test".to_string(), cryps).set_bot(true);
}
#[test]
@ -734,7 +755,7 @@ mod tests {
let player_account = Uuid::new_v4();
let cryps = instance_mobs(player_account);
let player = Player::new(player_account, instance.id, &"a".to_string(), cryps);
let player = Player::new(player_account, &"a".to_string(), cryps);
let a_id = player.id;
instance.add_player(player).expect("could not add player");
@ -742,7 +763,7 @@ mod tests {
let player_account = Uuid::new_v4();
let cryps = instance_mobs(player_account);
let player = Player::new(player_account, instance.id, &"b".to_string(), cryps);
let player = Player::new(player_account, &"b".to_string(), cryps);
let b_id = player.id;
instance.add_player(player).expect("could not add player");
@ -755,5 +776,55 @@ mod tests {
assert_eq!(instance.phase, InstancePhase::InProgress);
assert!(!instance.can_start());
instance.players[0].autobuy();
instance.players[1].autobuy();
instance.player_ready(a_id).expect("a ready");
let game = instance.player_ready(b_id).expect("b ready");
assert!(game.is_some());
}
#[test]
fn instance_upkeep_test() {
let mut instance = Instance::new()
.set_max_players(2)
.expect("could not create instance");
let player_account = Uuid::new_v4();
let cryps = instance_mobs(player_account);
let player = Player::new(player_account, &"a".to_string(), cryps);
let a_id = player.id;
instance.add_player(player).expect("could not add player");
assert!(!instance.can_start());
let player_account = Uuid::new_v4();
let cryps = instance_mobs(player_account);
let player = Player::new(player_account, &"b".to_string(), cryps);
let b_id = player.id;
instance.add_player(player).expect("could not add player");
instance.players[0].autobuy();
instance.player_ready(a_id).expect("a ready");
instance.player_ready(b_id).expect("b ready");
instance.phase_start = Utc::now().checked_sub_signed(Duration::seconds(61)).unwrap();
let (mut instance, new_games) = instance.upkeep();
assert_eq!(new_games.len(), 1);
let game = &new_games[0];
assert!(game.finished());
instance.game_finished(game).unwrap();
assert_eq!(instance.rounds.len(), 2);
assert!(instance.players.iter().all(|p| !p.ready));
println!("{:#?}", instance);
}
}

View File

@ -3,36 +3,32 @@ extern crate uuid;
extern crate tungstenite;
extern crate env_logger;
extern crate bcrypt;
extern crate chrono;
extern crate dotenv;
// extern crate petgraph;
extern crate postgres;
extern crate r2d2;
extern crate r2d2_postgres;
extern crate serde;
extern crate serde_cbor;
#[macro_use]
extern crate serde_derive;
#[macro_use] extern crate serde_derive;
#[macro_use] extern crate failure;
// #[macro_use] extern crate failure_derive;
mod cryp;
mod game;
mod net;
mod skill;
mod spec;
// mod passives;
mod names;
mod rpc;
mod account;
mod instance;
mod player;
// mod zone;
mod mob;
mod util;
mod vbox;
mod warden;
use dotenv::dotenv;
use net::{start};

View File

@ -21,19 +21,19 @@ pub fn generate_mob() -> Cryp {
return mob;
}
// fn quick_game(team_size: usize) -> Vec<Cryp> {
// fn quick_game(player_size: usize) -> Vec<Cryp> {
// iter::repeat_with(||
// generate_mob()
// .set_account(Uuid::nil())
// .learn(Skill::Attack))
// .take(team_size)
// .take(player_size)
// .collect::<Vec<Cryp>>()
// }
pub fn instance_mobs(team_id: Uuid) -> Vec<Cryp> {
pub fn instance_mobs(player_id: Uuid) -> Vec<Cryp> {
iter::repeat_with(||
generate_mob()
.set_account(team_id))
.set_account(player_id))
// .learn(Skill::Attack))
.take(3)
.collect::<Vec<Cryp>>()
@ -104,14 +104,14 @@ pub fn instance_mobs(team_id: Uuid) -> Vec<Cryp> {
// }
// pub fn generate_mob_team(mode: GameMode, cryps: &Vec<Cryp>) -> Team {
// let mut mob_team = Team::new(Uuid::nil());
// pub fn generate_mob_player(mode: GameMode, cryps: &Vec<Cryp>) -> Player {
// let mut mob_player = Player::new(Uuid::nil());
// let cryp_lvl = cryps.iter().max_by_key(|c| c.lvl).unwrap().lvl;
// let team_size = cryps.len();
// let player_size = cryps.len();
// let mobs = match mode {
// GameMode::Normal => quick_game(cryp_lvl, team_size),
// GameMode::Normal => quick_game(cryp_lvl, player_size),
// GameMode::Zone3v2Attack => zone_3v2_attack(cryp_lvl),
// GameMode::Zone2v2Caster => zone_2v2_caster(cryp_lvl),
// GameMode::Zone3v3MeleeMiniboss => zone_3v3_melee_miniboss(cryp_lvl),
@ -119,8 +119,8 @@ pub fn instance_mobs(team_id: Uuid) -> Vec<Cryp> {
// _ => panic!("{:?} not handled for pve mobs", mode),
// };
// mob_team.set_cryps(mobs);
// mob_player.set_cryps(mobs);
// return mob_team;
// return mob_player;
// }

View File

@ -7,7 +7,8 @@ use std::net::{TcpListener, TcpStream};
use serde_cbor::{to_vec};
use std::env;
use std::thread::spawn;
use std::thread::{spawn, sleep};
use std::time::Duration;
use r2d2::{Pool};
use r2d2::{PooledConnection};
@ -19,6 +20,7 @@ pub type Db = PooledConnection<PostgresConnectionManager>;
use rpc::{Rpc};
use util::{startup};
use warden::{warden};
// struct Server {
// client: WebSocket<TcpStream>,
@ -69,9 +71,22 @@ pub fn start() {
}
let server = TcpListener::bind("0.0.0.0:40000").unwrap();
let warden_pool = pool.clone();
spawn(move || {
loop {
let db_connection = warden_pool.get().expect("unable to get db connection");
if let Err(e) = warden(db_connection) {
println!("{:?}", e);
}
sleep(Duration::new(5, 0));
}
});
for stream in server.incoming() {
let db = pool.clone();
spawn (move || {
spawn(move || {
let mut websocket = accept(stream.unwrap()).unwrap();
let rpc = Rpc {};

View File

@ -13,6 +13,7 @@ use cryp::{Cryp, Colours, cryp_get};
use vbox::{Vbox, Var, VarEffect};
use rpc::{PlayerCrypsSetParams};
use instance::{Instance, instance_get, instance_update};
use skill::{Effect};
const DISCARD_COST: u16 = 5;
@ -25,26 +26,26 @@ pub struct Score {
#[derive(Debug,Clone,Serialize,Deserialize)]
pub struct Player {
pub id: Uuid,
pub instance: Uuid,
pub name: String,
pub vbox: Vbox,
pub score: Score,
pub cryps: Vec<Cryp>,
pub bot: bool,
pub ready: bool,
pub warnings: u8,
}
impl Player {
pub fn new(account: Uuid, instance: Uuid, name: &String, cryps: Vec<Cryp>) -> Player {
pub fn new(account: Uuid, name: &String, cryps: Vec<Cryp>) -> Player {
Player {
id: account,
instance,
name: name.clone(),
vbox: Vbox::new(account, instance),
vbox: Vbox::new(),
score: Score { wins: 0, losses: 0 },
cryps,
bot: false,
ready: false,
warnings: 0,
}
}
@ -58,16 +59,26 @@ impl Player {
self
}
pub fn add_warning(&mut self) -> &mut Player {
self.warnings += 1;
self
}
pub fn forfeit(&mut self) -> &mut Player {
for cryp in self.cryps.iter_mut() {
cryp.force_ko();
}
self
}
pub fn add_win(&mut self) -> &mut Player {
self.score.wins += 1;
self.set_ready(false);
self.vbox.balance_add(12);
self
}
pub fn add_loss(&mut self) -> &mut Player {
self.score.losses += 1;
self.set_ready(false);
self.vbox.balance_add(9);
self
}
@ -205,8 +216,8 @@ impl Player {
}
// now the var has been applied
// recalculate the stats of the whole team
let team_colours = self.cryps.iter().fold(Colours::new(), |tc, c| {
// recalculate the stats of the whole player
let player_colours = self.cryps.iter().fold(Colours::new(), |tc, c| {
Colours {
red: tc.red + c.colours.red,
green: tc.green + c.colours.green,
@ -215,7 +226,7 @@ impl Player {
});
for cryp in self.cryps.iter_mut() {
cryp.apply_modifiers(&team_colours);
cryp.apply_modifiers(&player_colours);
}
Ok(self)
@ -241,8 +252,8 @@ impl Player {
}
// now the var has been applied
// recalculate the stats of the whole team
let team_colours = self.cryps.iter().fold(Colours::new(), |tc, c| {
// recalculate the stats of the whole player
let player_colours = self.cryps.iter().fold(Colours::new(), |tc, c| {
Colours {
red: tc.red + c.colours.red,
green: tc.green + c.colours.green,
@ -251,7 +262,7 @@ impl Player {
});
for cryp in self.cryps.iter_mut() {
cryp.apply_modifiers(&team_colours);
cryp.apply_modifiers(&player_colours);
}
self.vbox.bound.push(target);
@ -259,6 +270,32 @@ impl Player {
Ok(self)
}
// GAME METHODS
pub fn skills_required(&self) -> usize {
let required = self.cryps.iter()
.filter(|c| !c.is_ko())
.filter(|c| c.available_skills().len() > 0)
.collect::<Vec<&Cryp>>().len();
// println!("{:} requires {:} skills this turn", self.id, required);
return required;
}
pub fn taunting(&self) -> Option<&Cryp> {
self.cryps.iter()
.find(|c| c.affected(Effect::Taunt))
}
pub fn set_cryps(&mut self, mut cryps: Vec<Cryp>) -> &mut Player {
cryps.sort_unstable_by_key(|c| c.id);
self.cryps = cryps;
self
}
pub fn cryp_by_id(&mut self, id: Uuid) -> Option<&mut Cryp> {
self.cryps.iter_mut().find(|c| c.id == id)
}
}
pub fn player_get(tx: &mut Transaction, account_id: Uuid, instance_id: Uuid) -> Result<Player, Error> {
@ -266,7 +303,8 @@ pub fn player_get(tx: &mut Transaction, account_id: Uuid, instance_id: Uuid) ->
SELECT *
FROM players
WHERE account = $1
AND instance = $2;
AND instance = $2
FOR UPDATE;
";
let result = tx
@ -284,7 +322,7 @@ pub fn player_get(tx: &mut Transaction, account_id: Uuid, instance_id: Uuid) ->
return Ok(data);
}
pub fn player_create(tx: &mut Transaction, player: Player, account: &Account) -> Result<Player, Error> {
pub fn player_create(tx: &mut Transaction, player: Player, instance: Uuid, account: &Account) -> Result<Player, Error> {
let player_bytes = to_vec(&player)?;
let query = "
@ -294,27 +332,19 @@ pub fn player_create(tx: &mut Transaction, player: Player, account: &Account) ->
";
let result = tx
.query(query, &[&Uuid::new_v4(), &player.instance, &account.id, &player_bytes])?;
.query(query, &[&Uuid::new_v4(), &instance, &account.id, &player_bytes])?;
let _returned = result.iter().next().expect("no row written");
println!("wrote player {:} joined instance: {:}", account.name, player.instance);
println!("wrote player {:} joined instance: {:}", account.name, instance);
return Ok(player);
}
pub fn player_update(tx: &mut Transaction, mut player: Player, ignore_phase: bool) -> Result<Player, Error> {
pub fn player_global_update(tx: &mut Transaction, mut player: Player, ignore_phase: bool) -> Result<Player, Error> {
// sort vbox for niceness
player.vbox.bound.sort_unstable();
// update the instance this player is associated with
// if not a global player
if player.instance != Uuid::nil() {
let instance = instance_get(tx, player.instance)?
.player_update(player.clone(), ignore_phase)?;
instance_update(tx, instance)?;
}
let bytes = to_vec(&player)?;
let query = "
@ -353,7 +383,7 @@ pub fn player_delete(tx: &mut Transaction, id: Uuid) -> Result<(), Error> {
pub fn player_mm_cryps_set(params: PlayerCrypsSetParams, tx: &mut Transaction, account: &Account) -> Result<Instance, Error> {
if params.cryp_ids.len() != 3 {
return Err(err_msg("team size is 3"));
return Err(err_msg("player size is 3"));
}
let cryps = params.cryp_ids
@ -364,11 +394,11 @@ pub fn player_mm_cryps_set(params: PlayerCrypsSetParams, tx: &mut Transaction, a
let player = match player_get(tx, account.id, Uuid::nil()) {
Ok(mut p) => {
p.cryps = cryps;
p.vbox = Vbox::new(account.id, Uuid::nil());
player_update(tx, p, false)?
p.vbox = Vbox::new();
player_global_update(tx, p, false)?
},
Err(_) => {
player_create(tx, Player::new(account.id, Uuid::nil(), &account.name, cryps), &account)?
player_create(tx, Player::new(account.id, &account.name, cryps), Uuid::nil(), &account)?
}
};
@ -385,7 +415,7 @@ mod tests {
fn player_bot_vbox_test() {
let player_account = Uuid::new_v4();
let cryps = instance_mobs(player_account);
let mut player = Player::new(player_account, Uuid::new_v4(), &"test".to_string(), cryps).set_bot(true);
let mut player = Player::new(player_account, &"test".to_string(), cryps).set_bot(true);
player.vbox.fill();
player.autobuy();

View File

@ -16,13 +16,13 @@ use failure::err_msg;
use net::Db;
use cryp::{Cryp, cryp_spawn};
use game::{Game, game_state, game_skill};
use game::{Game, game_state, game_skill, game_ready};
use account::{Account, account_create, account_login, account_from_token, account_cryps, account_instances};
use skill::{Skill};
// use zone::{Zone, zone_create, zone_join, zone_close};
use spec::{Spec};
use player::{Score, player_mm_cryps_set, Player};
use instance::{Instance, instance_state, instance_new, instance_ready, instance_join, instance_scores};
use instance::{Instance, instance_state, instance_new, instance_ready, instance_join};
use vbox::{Var, vbox_accept, vbox_apply, vbox_discard, vbox_combine, vbox_reclaim, vbox_unequip};
pub struct Rpc;
@ -71,11 +71,11 @@ impl Rpc {
"game_state" => Rpc::game_state(data, &mut tx, account.unwrap(), client),
"game_skill" => Rpc::game_skill(data, &mut tx, account.unwrap(), client),
"game_ready" => Rpc::game_ready(data, &mut tx, account.unwrap(), client),
"instance_join" => Rpc::instance_join(data, &mut tx, account.unwrap(), client),
"instance_ready" => Rpc::instance_ready(data, &mut tx, account.unwrap(), client),
"instance_new" => Rpc::instance_new(data, &mut tx, account.unwrap(), client),
"instance_scores" => Rpc::instance_scores(data, &mut tx, account.unwrap(), client),
"instance_state" => Rpc::instance_state(data, &mut tx, account.unwrap(), client),
"player_mm_cryps_set" => Rpc::player_mm_cryps_set(data, &mut tx, account.unwrap(), client),
@ -141,6 +141,18 @@ impl Rpc {
return Ok(game_response);
}
fn game_ready(data: Vec<u8>, tx: &mut Transaction, account: Account, _client: &mut WebSocket<TcpStream>) -> Result<RpcResponse, Error> {
let msg = from_slice::<GameStateMsg>(&data).or(Err(err_msg("invalid params")))?;
let game_response = RpcResponse {
method: "game_state".to_string(),
params: RpcResult::GameState(game_ready(msg.params, tx, &account)?)
};
return Ok(game_response);
}
fn cryp_spawn(data: Vec<u8>, tx: &mut Transaction, account: Account, client: &mut WebSocket<TcpStream>) -> Result<RpcResponse, Error> {
let msg = from_slice::<CrypSpawnMsg>(&data).or(Err(err_msg("invalid params")))?;
@ -261,17 +273,6 @@ impl Rpc {
// return Ok(response);
// }
fn instance_scores(data: Vec<u8>, tx: &mut Transaction, account: Account, _client: &mut WebSocket<TcpStream>) -> Result<RpcResponse, Error> {
let msg = from_slice::<InstanceReadyMsg>(&data).or(Err(err_msg("invalid params")))?;
let response = RpcResponse {
method: "instance_scores".to_string(),
params: RpcResult::InstanceScores(instance_scores(msg.params, tx, &account)?)
};
return Ok(response);
}
fn instance_state(data: Vec<u8>, tx: &mut Transaction, account: Account, _client: &mut WebSocket<TcpStream>) -> Result<RpcResponse, Error> {
let msg = from_slice::<InstanceStateMsg>(&data).or(Err(err_msg("invalid params")))?;
match instance_state(msg.params, tx, &account)? {

View File

@ -125,7 +125,7 @@ pub fn resolve(skill: Skill, source: &mut Cryp, target: &mut Cryp, mut resolutio
#[derive(Debug,Clone,PartialEq,Serialize,Deserialize)]
pub struct Cast {
pub id: Uuid,
pub source_team_id: Uuid,
pub source_player_id: Uuid,
pub source_cryp_id: Uuid,
pub target_cryp_id: Uuid,
pub skill: Skill,
@ -134,11 +134,11 @@ pub struct Cast {
}
impl Cast {
pub fn new(source_cryp_id: Uuid, source_team_id: Uuid, target_cryp_id: Uuid, skill: Skill) -> Cast {
pub fn new(source_cryp_id: Uuid, source_player_id: Uuid, target_cryp_id: Uuid, skill: Skill) -> Cast {
return Cast {
id: Uuid::new_v4(),
source_cryp_id,
source_team_id,
source_player_id,
target_cryp_id,
skill,
speed: 0,

View File

@ -68,94 +68,94 @@ impl Spec {
}
}
pub fn apply(&self, modified: u64, base: u64, team_colours: &Colours) -> u64 {
pub fn apply(&self, modified: u64, base: u64, player_colours: &Colours) -> u64 {
match *self {
// Upgrades to Damage Spec
Spec::Damage => modified + base.pct(5),
Spec::RedDamageI => modified + {
let mut pct = 10;
if team_colours.red >= 5 { pct += 10 };
if team_colours.red >= 10 { pct += 20 };
if team_colours.red >= 20 { pct += 40 };
if player_colours.red >= 5 { pct += 10 };
if player_colours.red >= 10 { pct += 20 };
if player_colours.red >= 20 { pct += 40 };
base.pct(pct)
},
Spec::GreenDamageI => modified + {
let mut pct = 10;
if team_colours.green >= 5 { pct += 10 };
if team_colours.green >= 10 { pct += 20 };
if team_colours.green >= 20 { pct += 40 };
if player_colours.green >= 5 { pct += 10 };
if player_colours.green >= 10 { pct += 20 };
if player_colours.green >= 20 { pct += 40 };
base.pct(pct)
},
Spec::BlueDamageI => modified + {
let mut pct = 10;
if team_colours.blue >= 5 { pct += 10 };
if team_colours.blue >= 10 { pct += 20 };
if team_colours.blue >= 20 { pct += 40 };
if player_colours.blue >= 5 { pct += 10 };
if player_colours.blue >= 10 { pct += 20 };
if player_colours.blue >= 20 { pct += 40 };
base.pct(pct)
},
Spec::GRDI => modified + {
let mut pct = 5;
if team_colours.green >= 2 && team_colours.red >= 2 { pct += 10 };
if team_colours.green >= 5 && team_colours.red >= 5 { pct += 15 };
if team_colours.green >= 10 && team_colours.red >= 10 { pct += 30 };
if player_colours.green >= 2 && player_colours.red >= 2 { pct += 10 };
if player_colours.green >= 5 && player_colours.red >= 5 { pct += 15 };
if player_colours.green >= 10 && player_colours.red >= 10 { pct += 30 };
base.pct(pct)
},
Spec::GBDI => modified + {
let mut pct = 5;
if team_colours.green >= 2 && team_colours.blue >= 2 { pct += 10 };
if team_colours.green >= 5 && team_colours.blue >= 5 { pct += 15 };
if team_colours.green >= 10 && team_colours.blue >= 10 { pct += 30 };
if player_colours.green >= 2 && player_colours.blue >= 2 { pct += 10 };
if player_colours.green >= 5 && player_colours.blue >= 5 { pct += 15 };
if player_colours.green >= 10 && player_colours.blue >= 10 { pct += 30 };
base.pct(pct)
},
Spec::RBDI => modified + {
let mut pct = 5;
if team_colours.blue >= 2 && team_colours.red >= 2 { pct += 10 };
if team_colours.blue >= 5 && team_colours.red >= 5 { pct += 15 };
if team_colours.blue >= 10 && team_colours.red >= 10 { pct += 30 };
if player_colours.blue >= 2 && player_colours.red >= 2 { pct += 10 };
if player_colours.blue >= 5 && player_colours.red >= 5 { pct += 15 };
if player_colours.blue >= 10 && player_colours.red >= 10 { pct += 30 };
base.pct(pct)
},
// Upgrades to speed Spec
Spec::Speed => modified + base.pct(5),
Spec::RedSpeedI => modified + {
let mut pct = 5;
if team_colours.red >= 5 { pct += 5 };
if team_colours.red >= 10 { pct += 10 };
if team_colours.red >= 20 { pct += 20 };
if player_colours.red >= 5 { pct += 5 };
if player_colours.red >= 10 { pct += 10 };
if player_colours.red >= 20 { pct += 20 };
base.pct(pct)
},
Spec::GreenSpeedI => modified + {
let mut pct = 5;
if team_colours.green >= 5 { pct += 5 };
if team_colours.green >= 10 { pct += 10 };
if team_colours.green >= 20 { pct += 20 };
if player_colours.green >= 5 { pct += 5 };
if player_colours.green >= 10 { pct += 10 };
if player_colours.green >= 20 { pct += 20 };
base.pct(pct)
},
Spec::BlueSpeedI => modified + {
let mut pct = 5;
if team_colours.blue >= 5 { pct += 5 };
if team_colours.blue >= 10 { pct += 10 };
if team_colours.blue >= 20 { pct += 20 };
if player_colours.blue >= 5 { pct += 5 };
if player_colours.blue >= 10 { pct += 10 };
if player_colours.blue >= 20 { pct += 20 };
base.pct(pct)
},
Spec::GRSpeedI => modified + {
let mut pct = 5;
if team_colours.green >= 2 && team_colours.red >= 2 { pct += 5 };
if team_colours.green >= 5 && team_colours.red >= 5 { pct += 10 };
if team_colours.green >= 10 && team_colours.red >= 10 { pct += 20 };
if player_colours.green >= 2 && player_colours.red >= 2 { pct += 5 };
if player_colours.green >= 5 && player_colours.red >= 5 { pct += 10 };
if player_colours.green >= 10 && player_colours.red >= 10 { pct += 20 };
base.pct(pct)
},
Spec::GBSpeedI => modified + {
let mut pct = 5;
if team_colours.green >= 2 && team_colours.blue >= 2 { pct += 5 };
if team_colours.green >= 5 && team_colours.blue >= 5 { pct += 10 };
if team_colours.green >= 10 && team_colours.blue >= 10 { pct += 20 };
if player_colours.green >= 2 && player_colours.blue >= 2 { pct += 5 };
if player_colours.green >= 5 && player_colours.blue >= 5 { pct += 10 };
if player_colours.green >= 10 && player_colours.blue >= 10 { pct += 20 };
base.pct(pct)
},
Spec::RBSpeedI => modified + {
let mut pct = 5;
if team_colours.blue >= 2 && team_colours.red >= 2 { pct += 5 };
if team_colours.blue >= 5 && team_colours.red >= 5 { pct += 10 };
if team_colours.blue >= 10 && team_colours.red >= 10 { pct += 20 };
if player_colours.blue >= 2 && player_colours.red >= 2 { pct += 5 };
if player_colours.blue >= 5 && player_colours.red >= 5 { pct += 10 };
if player_colours.blue >= 10 && player_colours.red >= 10 { pct += 20 };
base.pct(pct)
},
@ -163,45 +163,45 @@ impl Spec {
Spec::Life => modified + base.pct(5),
Spec::GreenLifeI => modified + {
let mut mult: u64 = 15;
if team_colours.green >= 5 { mult += 25 };
if team_colours.green >= 10 { mult += 50 };
if team_colours.green >= 20 { mult += 75 };
mult * team_colours.green as u64
if player_colours.green >= 5 { mult += 25 };
if player_colours.green >= 10 { mult += 50 };
if player_colours.green >= 20 { mult += 75 };
mult * player_colours.green as u64
},
Spec::RedLifeI => modified + {
let mut mult: u64 = 15;
if team_colours.red >= 5 { mult += 25 };
if team_colours.red >= 10 { mult += 50 };
if team_colours.red >= 20 { mult += 75 };
mult * team_colours.red as u64
if player_colours.red >= 5 { mult += 25 };
if player_colours.red >= 10 { mult += 50 };
if player_colours.red >= 20 { mult += 75 };
mult * player_colours.red as u64
},
Spec::BlueLifeI => modified + {
let mut mult: u64 = 15;
if team_colours.blue >= 5 { mult += 25 };
if team_colours.blue >= 10 { mult += 50 };
if team_colours.blue >= 20 { mult += 75 };
mult * team_colours.blue as u64
if player_colours.blue >= 5 { mult += 25 };
if player_colours.blue >= 10 { mult += 50 };
if player_colours.blue >= 20 { mult += 75 };
mult * player_colours.blue as u64
},
Spec::GRLI => modified + {
let mut mult: u64 = 10;
if team_colours.green >= 2 && team_colours.red >= 2 { mult += 10 };
if team_colours.green >= 5 && team_colours.red >= 5 { mult += 25 };
if team_colours.green >= 10 && team_colours.red >= 10 { mult += 50 };
mult * (team_colours.green + team_colours.red) as u64
if player_colours.green >= 2 && player_colours.red >= 2 { mult += 10 };
if player_colours.green >= 5 && player_colours.red >= 5 { mult += 25 };
if player_colours.green >= 10 && player_colours.red >= 10 { mult += 50 };
mult * (player_colours.green + player_colours.red) as u64
},
Spec::GBLI => modified + {
let mut mult: u64 = 10;
if team_colours.green >= 2 && team_colours.red >= 2 { mult += 10 };
if team_colours.green >= 5 && team_colours.red >= 5 { mult += 25 };
if team_colours.green >= 10 && team_colours.red >= 10 { mult += 50 };
mult * (team_colours.green + team_colours.red) as u64
if player_colours.green >= 2 && player_colours.red >= 2 { mult += 10 };
if player_colours.green >= 5 && player_colours.red >= 5 { mult += 25 };
if player_colours.green >= 10 && player_colours.red >= 10 { mult += 50 };
mult * (player_colours.green + player_colours.red) as u64
},
Spec::RBLI => modified + {
let mut mult: u64 = 10;
if team_colours.blue >= 2 && team_colours.red >= 2 { mult += 10 };
if team_colours.blue >= 5 && team_colours.red >= 5 { mult += 25 };
if team_colours.blue >= 10 && team_colours.red >= 10 { mult += 50 };
mult * (team_colours.blue + team_colours.red) as u64
if player_colours.blue >= 2 && player_colours.red >= 2 { mult += 10 };
if player_colours.blue >= 5 && player_colours.red >= 5 { mult += 25 };
if player_colours.blue >= 10 && player_colours.red >= 10 { mult += 50 };
mult * (player_colours.blue + player_colours.red) as u64
},
}
}

View File

@ -2,14 +2,14 @@ use net::Db;
// Db Commons
use failure::Error;
use game::{game_global_startup};
// use game::{game_global_startup};
pub fn startup(db: Db) -> Result<(), Error> {
let mut tx = db.transaction()?;
println!("running startup fns");
game_global_startup(&mut tx)?;
// game_global_startup(&mut tx)?;
match tx.commit() {
Ok(_) => {

View File

@ -15,7 +15,6 @@ use account::Account;
use rpc::{VboxAcceptParams, VboxDiscardParams, VboxCombineParams, VboxApplyParams, VboxReclaimParams, VboxUnequipParams};
use skill::{Skill};
use spec::{Spec};
use player::{Player};
use instance::{Instance, instance_get, instance_update};
use cryp::{Colours};
@ -397,16 +396,13 @@ fn get_combos() -> Vec<Combo> {
#[derive(Debug,Clone,Serialize,Deserialize)]
pub struct Vbox {
pub id: Uuid,
pub bits: u16,
pub free: Vec<Vec<Var>>,
pub bound: Vec<Var>,
pub instance: Uuid,
pub account: Uuid,
}
impl Vbox {
pub fn new(account_id: Uuid, instance_id: Uuid) -> Vbox {
pub fn new() -> Vbox {
let starting_items = vec![
Var::Attack,
Var::Attack,
@ -414,9 +410,6 @@ impl Vbox {
];
Vbox {
id: Uuid::new_v4(),
account: account_id,
instance: instance_id,
free: vec![vec![], vec![], vec![]],
bound: starting_items,
bits: 18,
@ -558,19 +551,19 @@ pub fn vbox_combine(params: VboxCombineParams, tx: &mut Transaction, account: &A
}
pub fn vbox_reclaim(params: VboxReclaimParams, tx: &mut Transaction, account: &Account) -> Result<Instance, Error> {
let mut instance = instance_get(tx, params.instance_id)?
let instance = instance_get(tx, params.instance_id)?
.vbox_reclaim(account.id, params.index)?;
return instance_update(tx, instance);
}
pub fn vbox_apply(params: VboxApplyParams, tx: &mut Transaction, account: &Account) -> Result<Instance, Error> {
let mut instance = instance_get(tx, params.instance_id)?
let instance = instance_get(tx, params.instance_id)?
.vbox_apply(account.id, params.index, params.cryp_id)?;
return instance_update(tx, instance);
}
pub fn vbox_unequip(params: VboxUnequipParams, tx: &mut Transaction, account: &Account) -> Result<Instance, Error> {
let mut instance = instance_get(tx, params.instance_id)?
let instance = instance_get(tx, params.instance_id)?
.vbox_unequip(account.id, params.target, params.cryp_id)?;
return instance_update(tx, instance);
}
@ -581,7 +574,7 @@ mod tests {
#[test]
fn combine_test() {
let mut vbox = Vbox::new(Uuid::new_v4(), Uuid::new_v4());
let mut vbox = Vbox::new();
vbox.bound = vec![Var::Attack, Var::Green, Var::Green];
vbox.combine(vec![1,2,0]).unwrap();
assert_eq!(vbox.bound[0], Var::Heal);
@ -601,7 +594,7 @@ mod tests {
#[test]
fn reclaim_test() {
let mut vbox = Vbox::new(Uuid::new_v4(), Uuid::new_v4());
let mut vbox = Vbox::new();
vbox.bound = vec![Var::Strike];
vbox.reclaim(0).unwrap();
assert_eq!(vbox.bits, 22);

53
server/src/warden.rs Normal file
View File

@ -0,0 +1,53 @@
// Db Commons
use postgres::transaction::Transaction;
use failure::Error;
use game::{games_need_upkeep, game_update, game_write, game_delete};
use instance::{instances_need_upkeep, instance_update};
use net::{Db};
fn fetch_games(mut tx: Transaction) -> Result<Transaction, Error> {
let games = games_need_upkeep(&mut tx)?;
for mut game in games {
let game = game.upkeep();
match game_update(&mut tx, &game) {
Ok(_) => (),
Err(e) => {
println!("{:?}", e);
game_delete(&mut tx, game.id)?;
}
}
}
Ok(tx)
}
fn fetch_instances(mut tx: Transaction) -> Result<Transaction, Error> {
let instances = instances_need_upkeep(&mut tx)?;
for mut instance in instances {
let (instance, new_games) = instance.upkeep();
println!("{:?} new games", new_games.len());
for game in new_games {
game_write(&mut tx, &game)?;
}
instance_update(&mut tx, instance)?;
}
Ok(tx)
}
pub fn warden(db: Db) -> Result<(), Error> {
println!("upkeep beginning");
fetch_games(db.transaction()?)?
.commit()?;
fetch_instances(db.transaction()?)?
.commit()?;
println!("upkeep done");
Ok(())
}

View File

@ -187,7 +187,7 @@ pub fn zone_join(params: ZoneJoinParams, tx: &mut Transaction, account: &Account
}
// persist
game_write(&game, tx)?;
game_write(tx, &game)?;
zone_update(&zone, tx)?;
return Ok(game);