diff --git a/client/src/scenes/item.list.js b/client/src/scenes/item.list.js index 1aafda61..6b23d259 100644 --- a/client/src/scenes/item.list.js +++ b/client/src/scenes/item.list.js @@ -160,7 +160,7 @@ class ItemList extends Phaser.Scene { .rectangle(WIDTH * 0.01, Y + HEIGHT * 0.775, ITEM_WIDTH * 1.25, ITEM_HEIGHT * 1.25, 0x222222) .setInteractive() .setOrigin(0) - .on('pointerdown', () => this.registry.get('ws').sendVboxDiscard(vbox.game)); + .on('pointerdown', () => this.registry.get('ws').sendVboxDiscard(vbox.instance)); this.add.text(reroll.getCenter().x, reroll.getCenter().y, 'Reroll', TEXT.HEADER) .setOrigin(0.5, 0.5); @@ -169,7 +169,7 @@ class ItemList extends Phaser.Scene { .setInteractive() .setOrigin(0) .on('pointerdown', () => { - ws.sendVboxCombine(vbox.game, this.combinerItems); + ws.sendVboxCombine(vbox.instance, this.combinerItems); this.combinerItems = [-1, -1, -1]; this.children.list.filter(obj => obj instanceof CombinerHitBox).forEach(cBox => cBox.deallocate()); }); @@ -201,7 +201,7 @@ class ItemList extends Phaser.Scene { itemBox .setInteractive() .on('pointerdown', () => { - ws.sendVboxAccept(vbox.game, i); + ws.sendVboxAccept(vbox.instance, i); }); this.add.existing(itemBox); }); @@ -277,8 +277,8 @@ class ItemList extends Phaser.Scene { return true; } // Allocate to cryp hitbox - if (hitBox instanceof DeleteHitBox) ws.sendVboxDrop(vbox.game, item.index); - else ws.sendVboxApply(vbox.game, hitBox.cryp.id, item.index); + if (hitBox instanceof DeleteHitBox) ws.sendVboxDrop(vbox.instance, item.index); + else ws.sendVboxApply(vbox.instance, hitBox.cryp.id, item.index); } // If the item hasn't been allocated deallocate the item // Scene will restart if there is vbox change diff --git a/client/src/scenes/menu.js b/client/src/scenes/menu.js index 77a1c53b..74dd42f8 100644 --- a/client/src/scenes/menu.js +++ b/client/src/scenes/menu.js @@ -38,7 +38,7 @@ class Menu extends Phaser.Scene { // When we load the menu request the latest items // Item list will restart when the data comes in - this.registry.get('ws').sendVboxState(NULL_UUID); + this.registry.get('ws').sendPlayerState(NULL_UUID); this.scene.manager.add('MenuCrypList', MenuCrypList, true); this.scene.manager.add('MenuNavigation', MenuNavigation, true); diff --git a/client/src/socket.js b/client/src/socket.js index 2f81629d..13b21d01 100644 --- a/client/src/socket.js +++ b/client/src/socket.js @@ -85,29 +85,29 @@ function createSocket(events) { send({ method: 'cryp_unspec', params: { id, spec } }); } - function sendVboxState(gameId) { - send({ method: 'vbox_state', params: { game_id: gameId } }); + function sendPlayerState(instanceId) { + send({ method: 'player_state', params: { instance_id: instanceId } }); } - function sendVboxAccept(gameId, i) { - send({ method: 'vbox_accept', params: { game_id: gameId, index: i } }); + function sendVboxAccept(instanceId, i) { + send({ method: 'player_vbox_accept', params: { instance_id: instanceId, index: i } }); } - function sendVboxApply(gameId, crypId, index) { - send({ method: 'vbox_apply', params: { game_id: gameId, cryp_id: crypId, index } }); + function sendVboxApply(instanceId, crypId, index) { + send({ method: 'player_vbox_apply', params: { instance_id: instanceId, cryp_id: crypId, index } }); } - function sendVboxDiscard(gameId) { - send({ method: 'vbox_discard', params: { game_id: gameId } }); + function sendVboxDiscard(instanceId) { + send({ method: 'player_vbox_discard', params: { instance_id: instanceId } }); } - function sendVboxCombine(gameId, indices) { - send({ method: 'vbox_combine', params: { game_id: gameId, indices } }); + function sendVboxCombine(instanceId, indices) { + send({ method: 'player_vbox_combine', params: { instance_id: instanceId, indices } }); } - function sendVboxDrop(gameId, index) { - send({ method: 'vbox_drop', params: { game_id: gameId, index } }); + function sendVboxDrop(instanceId, index) { + send({ method: 'player_vbox_drop', params: { instance_id: instanceId, index } }); } @@ -185,10 +185,9 @@ function createSocket(events) { events.setZone(zone); } - function vboxState(response) { - const [structName, vbox] = response; - console.log(vbox); - events.setVbox(vbox); + function playerState(response) { + const [structName, player] = response; + events.setVbox(player.vbox); } // ------------- @@ -210,7 +209,7 @@ function createSocket(events) { zone_create: res => console.log(res), zone_state: zoneState, zone_close: res => console.log(res), - vbox_state: vboxState, + player_state: playerState, }; function errHandler(error) { @@ -301,7 +300,7 @@ function createSocket(events) { sendZoneCreate, sendZoneJoin, sendZoneClose, - sendVboxState, + sendPlayerState, sendVboxAccept, sendVboxApply, sendVboxDrop, diff --git a/ops/migrations/20181020104420_games.js b/ops/migrations/20181020104420_games.js index 0fc18d17..ed19db27 100644 --- a/ops/migrations/20181020104420_games.js +++ b/ops/migrations/20181020104420_games.js @@ -1,35 +1,60 @@ +const NULL_UUID = '00000000-0000-0000-0000-000000000000'; + exports.up = async knex => { await knex.schema.createTable('games', table => { table.uuid('id').primary(); table.index('id'); table.timestamps(); + table.binary('data').notNullable(); + }); + + await knex.schema.createTable('instances', async table => { + table.uuid('id').primary(); + table.index('id'); + table.timestamps(); table.binary('data').notNullable(); - table.boolean('joinable') - .defaultTo(true) - .notNullable(); + table.boolean('open') + .defaultTo(true) + .notNullable(); }); + await knex.schema.raw( + // eslint-disable-next-line max-len + 'CREATE UNIQUE INDEX instances_open ON instances (open) WHERE open = true;' + ); + + await knex.schema.createTable('players', table => { table.uuid('id').primary(); table.index('id'); + table.binary('data').notNullable(); - // the game itself - table.uuid('game').notNullable() - table.foreign('game') - .references('id') - .inTable('games') - .onDelete('CASCADE'); - table.index('game'); + // the instance + table.uuid('instance').notNullable() + table.foreign('instance') + .references('id') + .inTable('instances') + .onDelete('CASCADE'); + table.index('instance'); // account in a game table.uuid('account').notNullable() table.foreign('account') - .references('id') - .inTable('accounts') - .onDelete('CASCADE'); + .references('id') + .inTable('accounts') + .onDelete('CASCADE'); table.index('account'); + table.unique(['account', 'instance']); + + }); + + // not really sure if this is a good idea + await knex('instances').insert({ + id: NULL_UUID, + data: 'INVALID', + open: false, }); }; diff --git a/ops/migrations/20190216123550_vbox.js b/ops/migrations/20190216123550_vbox.js deleted file mode 100644 index 4ed2fcae..00000000 --- a/ops/migrations/20190216123550_vbox.js +++ /dev/null @@ -1,36 +0,0 @@ -const NULL_UUID = '00000000-0000-0000-0000-000000000000'; - -exports.up = async knex => { - await knex.schema.createTable('vbox', table => { - table.timestamps(); - table.uuid('id').primary(); - table.uuid('account').notNullable() - table.uuid('game').notNullable() - table.binary('data').notNullable(); - - table.foreign('game') - .references('id') - .inTable('games') - .onDelete('CASCADE'); - - table.foreign('account') - .references('id') - .inTable('accounts') - .onDelete('CASCADE'); - - table.index('id'); - table.index('account'); - table.unique(['account', 'game']); - }); - - // not really sure if this is a good idea - await knex('games').insert({ - id: NULL_UUID, - data: 'INVALID', - joinable: false, - }); - - return true; -}; - -exports.down = async () => {}; \ No newline at end of file diff --git a/server/WORKLOG.md b/server/WORKLOG.md index 7922daf0..7510c68a 100644 --- a/server/WORKLOG.md +++ b/server/WORKLOG.md @@ -1,30 +1,3 @@ -# Principles -* Experience something -* Express something -* Prove something - -* 1: Fighting against human nature is a losing game -* 2: Aesthetics matter -* 3: Resonance is important -* 4: Make use of piggybacking -* 5: Don't confuse "interesting" with "fun" -* 6: Understand what emotion your game is trying to evoke -* 7: Allow the players the skill to make the game personal -* 8: The details are where the players fall in love with your game -* 9: Allow your players to have a sense of ownership -* 10: Leave room for the player to explore -* 11: If everyone likes your game, but no one loves it, it will fail -* 12: Don't design to prove you can do something -* 13: Make the fun part also the correct strategy to win -* 14: Don't be afraid to be blunt -* 15: Design the component for its intended audience -* 16: Be more afraid of boring your players than challenging them -* 17: You don't have to change much to change everything -* 18: Restrictions breed creativity -* 19: Your audience is good at recognizing problems and bad at solving them -* 20: All the lessons connect - - # Key Mechanics * 10d chaos maths, not rock paper scissors * phys is faster and chaotic @@ -33,28 +6,13 @@ * red_shield is restored, not gained * players can feel aggressive -# ask sam -* main screen layout - * ping icon - * -* combat screen layout - * health bars - * statuses -* icons - * skill type / damage type - * skills themselves - * passive nodes / notables - -* tell him about discord # WORK WORK - -broken skills -strangle -taunt - - ## NOW +cost system for items +design / implement specs +combo specs +round system for games ## SOON * clean up categories @@ -119,3 +77,29 @@ gem td style attr combinations slimey ghostly + +# Principles +* Experience something +* Express something +* Prove something + +* 1: Fighting against human nature is a losing game +* 2: Aesthetics matter +* 3: Resonance is important +* 4: Make use of piggybacking +* 5: Don't confuse "interesting" with "fun" +* 6: Understand what emotion your game is trying to evoke +* 7: Allow the players the skill to make the game personal +* 8: The details are where the players fall in love with your game +* 9: Allow your players to have a sense of ownership +* 10: Leave room for the player to explore +* 11: If everyone likes your game, but no one loves it, it will fail +* 12: Don't design to prove you can do something +* 13: Make the fun part also the correct strategy to win +* 14: Don't be afraid to be blunt +* 15: Design the component for its intended audience +* 16: Be more afraid of boring your players than challenging them +* 17: You don't have to change much to change everything +* 18: Restrictions breed creativity +* 19: Your audience is good at recognizing problems and bad at solving them +* 20: All the lessons connect diff --git a/server/src/game.rs b/server/src/game.rs index cc060432..8f4ca467 100644 --- a/server/src/game.rs +++ b/server/src/game.rs @@ -8,7 +8,7 @@ use failure::Error; use failure::err_msg; use account::Account; -use rpc::{GameStateParams, GameSkillParams, GamePveParams, GamePvpParams, GameJoinParams}; +use rpc::{GameStateParams, GameSkillParams, GamePveParams}; use cryp::{Cryp, cryp_get}; use skill::{Skill, Cast, ResolutionResult}; use zone::{node_finish}; @@ -648,26 +648,6 @@ pub fn game_get(tx: &mut Transaction, id: Uuid) -> Result { return Ok(game); } -pub fn players_write(account: &Account, game_id: Uuid, tx: &mut Transaction) -> Result<(), Error> { - // pve - let id = Uuid::new_v4(); - - let query = " - INSERT INTO players (id, game, account) - VALUES ($1, $2, $3) - RETURNING id, account; - "; - - let result = tx - .query(query, &[&id, &game_id, &account.id])?; - - let _returned = result.iter().next().expect("no row written"); - - println!("wrote player {:} joined game: {:}", account.name, game_id); - - return Ok(()); -} - pub fn game_update(game: &Game, tx: &mut Transaction) -> Result<(), Error> { let game_bytes = to_vec(&game)?; @@ -745,94 +725,6 @@ pub fn game_pve(params: GamePveParams, tx: &mut Transaction, account: &Account) Ok(game) } -pub fn game_pvp(params: GamePvpParams, tx: &mut Transaction, account: &Account) -> Result { - let cryps = params.cryp_ids - .iter() - .map(|id| cryp_get(tx, *id, account.id)) - .collect::, Error>>()?; - - // create the game - let mut game = Game::new(); - let game_id = game.id; - - game - .set_pve(false) - .set_team_num(2) - .set_team_size(cryps.len()) - .set_mode(GameMode::Pvp); - - // create the initiators team - let mut team = Team::new(account.id); - team.set_cryps(cryps); - - game.team_add(team)?; - - // persist - game_write(&game, tx)?; - players_write(account, game_id, tx)?; - - Ok(game) -} - -pub fn game_join(params: GameJoinParams, tx: &mut Transaction, account: &Account) -> Result { - let mut game = game_get(tx, params.game_id)?; - - // rejoining a game from the FE list - if game.already_joined(account.id) { - return Ok(game); - } - - // ok actually adding a new team - let game_id = game.id; - - let cryps = params.cryp_ids - .iter() - .map(|id| cryp_get(tx, *id, account.id)) - .collect::, Error>>()?; - - if cryps.len() != game.team_size { - return Err(format_err!("incorrect team size. ({:})", game.team_size)); - } - - let mut team = Team::new(account.id); - team.set_cryps(cryps); - game.team_add(team)?; - - if game.can_start() { - game.start(); - } - - game_update(&game, tx)?; - players_write(account, game_id, tx)?; - - Ok(game) -} - -pub fn game_joinable_list(tx: &mut Transaction, _account: &Account) -> Result, Error> { - let query = " - SELECT games.data - FROM games - WHERE joinable; - "; - - let result = tx - .query(query, &[])?; - - let games: Result, _> = result.iter().map(|row| { - let cryp_bytes: Vec = row.get(0); - from_slice::(&cryp_bytes) - }).collect(); - - // catch any errors - if games.is_err() { - return Err(err_msg("could not deserialize a game")); - } - - // now unwrap is safe - return Ok(games.unwrap()); -} - - #[cfg(test)] mod tests { use game::*; diff --git a/server/src/instance.rs b/server/src/instance.rs new file mode 100644 index 00000000..34dc61ca --- /dev/null +++ b/server/src/instance.rs @@ -0,0 +1,149 @@ +use uuid::Uuid; + +use serde_cbor::{from_slice, to_vec}; + +use postgres::transaction::Transaction; + +use failure::Error; +use failure::err_msg; + +use rpc::{InstanceJoinParams}; +use account::Account; +use player::{Player, player_create}; +use cryp::{Cryp, cryp_get}; + +#[derive(Debug,Clone,Copy,PartialEq,Serialize,Deserialize)] +enum InstancePhase { + Open, + Vbox, + Combat, + Finished, +} + +#[derive(Debug,Clone,Serialize,Deserialize)] +pub struct Instance { + id: Uuid, + players: Vec, + phase: InstancePhase, + open: bool, +} + +impl Instance { + fn new() -> Instance { + Instance { + id: Uuid::new_v4(), + players: vec![], + phase: InstancePhase::Open, + open: true, + } + } + + fn add_player(&mut self, player: &Player) -> &mut Instance { + self.players.push(player.id); + self + } +} + +pub fn instance_create(instance: Instance, tx: &mut Transaction) -> Result { + let instance_bytes = to_vec(&instance)?; + + let query = " + INSERT INTO instances (id, data) + VALUES ($1, $2) + RETURNING id; + "; + + let result = tx + .query(query, &[&instance.id, &instance_bytes])?; + + result.iter().next().ok_or(format_err!("no instances written"))?; + + return Ok(instance); +} + +pub fn instance_write(instance: Instance, tx: &mut Transaction) -> Result { + let instance_bytes = to_vec(&instance)?; + + let query = " + UPDATE instance + SET data = $1 + WHERE id = $2 + RETURNING id, data; + "; + + let result = tx + .query(query, &[&instance_bytes, &instance.id])?; + + result.iter().next().ok_or(err_msg("no instance row returned"))?; + + // println!("{:?} wrote instance", instance.id); + + return Ok(instance); +} + +pub fn instance_get(tx: &mut Transaction, instance_id: Uuid) -> Result { + let query = " + SELECT * + FROM instance + WHERE id = $1; + "; + + let result = tx + .query(query, &[&instance_id])?; + + let returned = match result.iter().next() { + Some(row) => row, + None => return Err(err_msg("instance not found")), + }; + + let instance_bytes: Vec = returned.get("data"); + let instance = from_slice::(&instance_bytes)?; + + return Ok(instance); +} + +pub fn instance_get_open(tx: &mut Transaction) -> Result { + let query = " + SELECT * + FROM instance + AND open = true; + "; + + let result = tx + .query(query, &[])?; + + let returned = match result.iter().next() { + Some(row) => row, + None => return Err(err_msg("instance not found")), + }; + + let instance_bytes: Vec = returned.get("data"); + let instance = from_slice::(&instance_bytes)?; + + return Ok(instance); +} + + +pub fn instance_join(params: InstanceJoinParams, tx: &mut Transaction, account: &Account) -> Result { + let mut instance = match instance_get_open(tx) { + Ok(i) => i, + Err(_) => instance_create(Instance::new(), tx)?, + }; + + let cryps = params.cryp_ids + .iter() + .map(|id| cryp_get(tx, *id, account.id)) + .collect::, Error>>()?; + + if cryps.len() != 3 { + return Err(format_err!("incorrect team size. ({:})", 3)); + } + + let player = Player::new(account.id, instance.id, cryps); + instance.add_player(&player); + + player_create(tx, &player, account)?; + instance_write(instance, tx)?; + + return Ok(player); +} diff --git a/server/src/main.rs b/server/src/main.rs index 570cfd98..1391afdb 100644 --- a/server/src/main.rs +++ b/server/src/main.rs @@ -26,7 +26,8 @@ mod spec; // mod passives; mod rpc; mod account; -// mod item; +mod instance; +mod player; mod zone; mod mob; diff --git a/server/src/player.rs b/server/src/player.rs new file mode 100644 index 00000000..1fb19389 --- /dev/null +++ b/server/src/player.rs @@ -0,0 +1,108 @@ +use uuid::Uuid; + +use serde_cbor::{from_slice, to_vec}; + +use postgres::transaction::Transaction; + +use failure::Error; +use failure::err_msg; + +use account::Account; +use instance::Instance; +use cryp::{Cryp}; +use vbox::{Vbox}; +use rpc::{PlayerStateParams}; + +#[derive(Debug,Clone,Serialize,Deserialize)] +pub struct Score { + wins: u8, + losses: u8, +} + +#[derive(Debug,Clone,Serialize,Deserialize)] +pub struct Player { + pub id: Uuid, + pub instance: Uuid, + pub account: Uuid, + // name: String, + pub vbox: Vbox, + pub score: Score, + pub cryps: Vec, +} + +impl Player { + pub fn new(account: Uuid, instance: Uuid, cryps: Vec) -> Player { + Player { + id: Uuid::new_v4(), + account, + instance, + vbox: Vbox::new(account, instance), + score: Score { wins: 0, losses: 0 }, + cryps, + } + } +} + +pub fn player_get(tx: &mut Transaction, account_id: Uuid, instance_id: Uuid) -> Result { + let query = " + SELECT * + FROM players + WHERE account = $1 + AND instance = $2; + "; + + let result = tx + .query(query, &[&account_id, &instance_id])?; + + let returned = match result.iter().next() { + Some(row) => row, + None => return Err(err_msg("player not found")), + }; + + // tells from_slice to cast into a cryp + let bytes: Vec = returned.get("data"); + let data = from_slice::(&bytes)?; + + return Ok(data); +} + +pub fn player_create(tx: &mut Transaction, player: &Player, account: &Account) -> Result<(), Error> { + let player_bytes = to_vec(&player)?; + + let query = " + INSERT INTO players (id, instance, account, data) + VALUES ($1, $2, $3, $4) + RETURNING id, account; + "; + + let result = tx + .query(query, &[&player.id, &player.instance, &account.id, &player_bytes])?; + + let _returned = result.iter().next().expect("no row written"); + + println!("wrote player {:} joined instance: {:}", account.name, player.instance); + + return Ok(()); +} + +pub fn player_update(tx: &mut Transaction, player: Player) -> Result { + let bytes = to_vec(&player)?; + + let query = " + UPDATE players + SET data = $1 + WHERE id = $2 + RETURNING id, data; + "; + + let result = tx + .query(query, &[&bytes, &player.id])?; + + result.iter().next().ok_or(format_err!("player {:?} could not be written", player))?; + + return Ok(player) +} + +pub fn player_state(params: PlayerStateParams, tx: &mut Transaction, account: &Account) -> Result { + player_get(tx, account.id, params.instance_id) +} diff --git a/server/src/rpc.rs b/server/src/rpc.rs index 22e4bc61..c1ebc729 100644 --- a/server/src/rpc.rs +++ b/server/src/rpc.rs @@ -15,13 +15,15 @@ use failure::Error; use failure::err_msg; use net::Db; -use cryp::{Cryp, cryp_spawn, cryp_learn, cryp_forget, cryp_unspec}; -use game::{Game, game_state, game_pve, game_pvp, game_join, game_joinable_list, game_skill}; +use cryp::{Cryp, cryp_spawn, cryp_learn}; +use game::{Game, game_state, game_pve, game_skill}; use account::{Account, account_create, account_login, account_from_token, account_cryps, account_zone}; use skill::{Skill}; use zone::{Zone, zone_create, zone_join, zone_close}; use spec::{Spec}; -use vbox::{Vbox, vbox_state, vbox_accept, vbox_apply, vbox_discard, vbox_combine, vbox_drop}; +use player::{player_state, player_create, Player}; +use instance::{instance_join}; +use vbox::{vbox_accept, vbox_apply, vbox_discard, vbox_combine, vbox_drop}; pub struct Rpc; @@ -61,29 +63,26 @@ impl Rpc { "account_demo" => Rpc::account_demo(data, &mut tx, client), // auth methods - "cryp_spawn" => Rpc::cryp_spawn(data, &mut tx, account.unwrap(), client), - "cryp_learn" => Rpc::cryp_learn(data, &mut tx, account.unwrap(), client), - "cryp_forget" => Rpc::cryp_forget(data, &mut tx, account.unwrap(), client), - "cryp_unspec" => Rpc::cryp_unspec(data, &mut tx, account.unwrap(), client), - "game_state" => Rpc::game_state(data, &mut tx, account.unwrap(), client), - "game_pve" => Rpc::game_pve(data, &mut tx, account.unwrap(), client), - "game_pvp" => Rpc::game_pvp(data, &mut tx, account.unwrap(), client), - "game_join" => Rpc::game_join(data, &mut tx, account.unwrap(), client), - "game_joinable_list" => Rpc::game_joinable_list(data, &mut tx, account.unwrap(), client), - "game_skill" => Rpc::game_skill(data, &mut tx, account.unwrap(), client), - // "game_target" => Rpc::game_target(data, &mut tx, account.unwrap(), client), - "zone_create" => Rpc::zone_create(data, &mut tx, account.unwrap(), client), - "zone_join" => Rpc::zone_join(data, &mut tx, account.unwrap(), client), - "zone_close" => Rpc::zone_close(data, &mut tx, account.unwrap(), client), "account_cryps" => Rpc::account_cryps(data, &mut tx, account.unwrap(), client), "account_zone" => Rpc::account_zone(data, &mut tx, account.unwrap(), client), - "vbox_state" => Rpc::vbox_state(data, &mut tx, account.unwrap(), client), - "vbox_accept" => Rpc::vbox_accept(data, &mut tx, account.unwrap(), client), - "vbox_apply" => Rpc::vbox_apply(data, &mut tx, account.unwrap(), client), - "vbox_drop" => Rpc::vbox_drop(data, &mut tx, account.unwrap(), client), - "vbox_combine" => Rpc::vbox_combine(data, &mut tx, account.unwrap(), client), - "vbox_discard" => Rpc::vbox_discard(data, &mut tx, account.unwrap(), client), + "cryp_spawn" => Rpc::cryp_spawn(data, &mut tx, account.unwrap(), client), + + "game_state" => Rpc::game_state(data, &mut tx, account.unwrap(), client), + "game_pve" => Rpc::game_pve(data, &mut tx, account.unwrap(), client), + "game_skill" => Rpc::game_skill(data, &mut tx, account.unwrap(), client), + + "zone_create" => Rpc::zone_create(data, &mut tx, account.unwrap(), client), + "zone_join" => Rpc::zone_join(data, &mut tx, account.unwrap(), client), + "zone_close" => Rpc::zone_close(data, &mut tx, account.unwrap(), client), + + "instance_join" => Rpc::instance_join(data, &mut tx, account.unwrap(), client), + "player_state" => Rpc::player_state(data, &mut tx, account.unwrap(), client), + "player_vbox_accept" => Rpc::player_vbox_accept(data, &mut tx, account.unwrap(), client), + "player_vbox_apply" => Rpc::player_vbox_apply(data, &mut tx, account.unwrap(), client), + "player_vbox_drop" => Rpc::player_vbox_drop(data, &mut tx, account.unwrap(), client), + "player_vbox_combine" => Rpc::player_vbox_combine(data, &mut tx, account.unwrap(), client), + "player_vbox_discard" => Rpc::player_vbox_discard(data, &mut tx, account.unwrap(), client), _ => Err(format_err!("unknown method - {:?}", v.method)), }; @@ -115,7 +114,6 @@ impl Rpc { return Ok(game_response); } - fn game_pve(data: Vec, tx: &mut Transaction, account: Account, client: &mut WebSocket) -> Result { let msg = from_slice::(&data).or(Err(err_msg("invalid params")))?; @@ -132,42 +130,6 @@ impl Rpc { return Ok(game_response); } - fn game_pvp(data: Vec, tx: &mut Transaction, account: Account, _client: &mut WebSocket) -> Result { - let msg = from_slice::(&data).or(Err(err_msg("invalid params")))?; - - let game_response = RpcResponse { - method: "game_state".to_string(), - params: RpcResult::GameState(game_pvp(msg.params, tx, &account)?) - }; - - return Ok(game_response); - } - - - fn game_join(data: Vec, tx: &mut Transaction, account: Account, _client: &mut WebSocket) -> Result { - let msg = from_slice::(&data).or(Err(err_msg("invalid params")))?; - - let game_response = RpcResponse { - method: "game_state".to_string(), - params: RpcResult::GameState(game_join(msg.params, tx, &account)?) - }; - - return Ok(game_response); - } - - fn game_joinable_list(_data: Vec, tx: &mut Transaction, account: Account, _client: &mut WebSocket) -> Result { - // let msg = from_slice::(&data).or(Err(err_msg("invalid params")))?; - - let game_list = RpcResponse { - method: "game_joinable_list".to_string(), - params: RpcResult::GameJoinableList(game_joinable_list(tx, &account)?) - }; - - return Ok(game_list); - } - - - fn game_skill(data: Vec, tx: &mut Transaction, account: Account, _client: &mut WebSocket) -> Result { let msg = from_slice::(&data).or(Err(err_msg("invalid params")))?; @@ -179,17 +141,6 @@ impl Rpc { return Ok(game_response); } - // fn game_target(data: Vec, tx: &mut Transaction, account: Account, _client: &mut WebSocket) -> Result { - // let msg = from_slice::(&data).or(Err(err_msg("invalid params")))?; - - // let game_response = RpcResponse { - // method: "game_state".to_string(), - // params: RpcResult::GameState(game_target(msg.params, tx, &account)?) - // }; - - // return Ok(game_response); - // } - fn cryp_spawn(data: Vec, tx: &mut Transaction, account: Account, client: &mut WebSocket) -> Result { let msg = from_slice::(&data).or(Err(err_msg("invalid params")))?; @@ -206,62 +157,17 @@ impl Rpc { Ok(cryp_list) } - fn cryp_learn(data: Vec, tx: &mut Transaction, account: Account, client: &mut WebSocket) -> Result { - let msg = from_slice::(&data).or(Err(err_msg("invalid params")))?; - - Rpc::send_msg(client, RpcResponse { - method: "cryp_learn".to_string(), - params: RpcResult::CrypLearn(cryp_learn(msg.params, tx, &account)?) - })?; - - let cryp_list = RpcResponse { - method: "account_cryps".to_string(), - params: RpcResult::CrypList(account_cryps(tx, &account)?) - }; - - Ok(cryp_list) - } - - fn cryp_forget(data: Vec, tx: &mut Transaction, account: Account, client: &mut WebSocket) -> Result { - let msg = from_slice::(&data).or(Err(err_msg("invalid params")))?; - - Rpc::send_msg(client, RpcResponse { - method: "cryp_forget".to_string(), - params: RpcResult::CrypForget(cryp_forget(msg.params, tx, &account)?) - })?; - - let cryp_list = RpcResponse { - method: "account_cryps".to_string(), - params: RpcResult::CrypList(account_cryps(tx, &account)?) - }; - - Ok(cryp_list) - } - - fn cryp_unspec(data: Vec, tx: &mut Transaction, account: Account, client: &mut WebSocket) -> Result { - let msg = from_slice::(&data).or(Err(err_msg("invalid params")))?; - - Rpc::send_msg(client, RpcResponse { - method: "cryp_unspec".to_string(), - params: RpcResult::CrypUnspec(cryp_unspec(msg.params, tx, &account)?) - })?; - - let cryp_list = RpcResponse { - method: "account_cryps".to_string(), - params: RpcResult::CrypList(account_cryps(tx, &account)?) - }; - - Ok(cryp_list) - } - fn account_create(data: Vec, tx: &mut Transaction, _client: &mut WebSocket) -> Result { - match from_slice::(&data) { - Ok(v) => Ok(RpcResponse { - method: v.method, - params: RpcResult::Account(account_create(v.params, tx)?) - }), - Err(_e) => Err(err_msg("invalid params")), - } + let msg = from_slice::(&data).or(Err(err_msg("invalid params")))?; + + let account = account_create(msg.params, tx)?; + let player = Player::new(account.id, Uuid::nil(), vec![]); + player_create(tx, &player, &account)?; + + Ok(RpcResponse { + method: "account_create".to_string(), + params: RpcResult::Account(account) + }) } fn account_login(data: Vec, tx: &mut Transaction, _client: &mut WebSocket) -> Result { @@ -355,57 +261,69 @@ impl Rpc { return Ok(response); } - fn vbox_state(data: Vec, tx: &mut Transaction, account: Account, _client: &mut WebSocket) -> Result { - let msg = from_slice::(&data).or(Err(err_msg("invalid params")))?; + fn instance_join(data: Vec, tx: &mut Transaction, account: Account, _client: &mut WebSocket) -> Result { + let msg = from_slice::(&data).or(Err(err_msg("invalid params")))?; let response = RpcResponse { - method: "vbox_state".to_string(), - params: RpcResult::VboxState(vbox_state(msg.params, tx, &account)?) + method: "player_state".to_string(), + params: RpcResult::PlayerState(instance_join(msg.params, tx, &account)?) }; return Ok(response); } - fn vbox_accept(data: Vec, tx: &mut Transaction, account: Account, _client: &mut WebSocket) -> Result { + + fn player_state(data: Vec, tx: &mut Transaction, account: Account, _client: &mut WebSocket) -> Result { + let msg = from_slice::(&data).or(Err(err_msg("invalid params")))?; + + let response = RpcResponse { + method: "player_state".to_string(), + params: RpcResult::PlayerState(player_state(msg.params, tx, &account)?) + }; + + return Ok(response); + } + + fn player_vbox_accept(data: Vec, tx: &mut Transaction, account: Account, _client: &mut WebSocket) -> Result { let msg = from_slice::(&data).or(Err(err_msg("invalid params")))?; let response = RpcResponse { - method: "vbox_state".to_string(), - params: RpcResult::VboxState(vbox_accept(msg.params, tx, &account)?) + method: "player_state".to_string(), + params: RpcResult::PlayerState(vbox_accept(msg.params, tx, &account)?) }; return Ok(response); } - fn vbox_discard(data: Vec, tx: &mut Transaction, account: Account, _client: &mut WebSocket) -> Result { + fn player_vbox_discard(data: Vec, tx: &mut Transaction, account: Account, _client: &mut WebSocket) -> Result { let msg = from_slice::(&data).or(Err(err_msg("invalid params")))?; let response = RpcResponse { - method: "vbox_state".to_string(), - params: RpcResult::VboxState(vbox_discard(msg.params, tx, &account)?) + method: "player_state".to_string(), + params: RpcResult::PlayerState(vbox_discard(msg.params, tx, &account)?) }; return Ok(response); } - fn vbox_combine(data: Vec, tx: &mut Transaction, account: Account, _client: &mut WebSocket) -> Result { + fn player_vbox_combine(data: Vec, tx: &mut Transaction, account: Account, _client: &mut WebSocket) -> Result { let msg = from_slice::(&data).or(Err(err_msg("invalid params")))?; let response = RpcResponse { - method: "vbox_state".to_string(), - params: RpcResult::VboxState(vbox_combine(msg.params, tx, &account)?) + method: "player_state".to_string(), + params: RpcResult::PlayerState(vbox_combine(msg.params, tx, &account)?) }; return Ok(response); } - fn vbox_apply(data: Vec, tx: &mut Transaction, account: Account, client: &mut WebSocket) -> Result { + fn player_vbox_apply(data: Vec, tx: &mut Transaction, account: Account, client: &mut WebSocket) -> Result { let msg = from_slice::(&data).or(Err(err_msg("invalid params")))?; let response = RpcResponse { - method: "vbox_state".to_string(), - params: RpcResult::VboxState(vbox_apply(msg.params, tx, &account)?) + method: "player_state".to_string(), + params: RpcResult::PlayerState(vbox_apply(msg.params, tx, &account)?) }; Rpc::send_msg(client, RpcResponse { @@ -416,16 +334,17 @@ impl Rpc { return Ok(response); } - fn vbox_drop(data: Vec, tx: &mut Transaction, account: Account, _client: &mut WebSocket) -> Result { + fn player_vbox_drop(data: Vec, tx: &mut Transaction, account: Account, _client: &mut WebSocket) -> Result { let msg = from_slice::(&data).or(Err(err_msg("invalid params")))?; let response = RpcResponse { - method: "vbox_state".to_string(), - params: RpcResult::VboxState(vbox_drop(msg.params, tx, &account)?) + method: "player_state".to_string(), + params: RpcResult::PlayerState(vbox_drop(msg.params, tx, &account)?) }; return Ok(response); } + } #[derive(Debug,Clone,Serialize,Deserialize)] @@ -447,7 +366,7 @@ pub enum RpcResult { ZoneState(Zone), ZoneClose(()), - VboxState(Vbox), + PlayerState(Player), } #[derive(Debug,Clone,Serialize,Deserialize)] @@ -525,48 +444,6 @@ pub struct GamePveParams { pub cryp_ids: Vec, } -#[derive(Debug,Clone,Serialize,Deserialize)] -struct GamePvpMsg { - method: String, - params: GamePvpParams, -} - -#[derive(Debug,Clone,Serialize,Deserialize)] -pub struct GamePvpParams { - pub cryp_ids: Vec, -} - -#[derive(Debug,Clone,Serialize,Deserialize)] -struct GameJoinMsg { - method: String, - params: GameJoinParams, -} - -#[derive(Debug,Clone,Serialize,Deserialize)] -pub struct GameJoinParams { - pub game_id: Uuid, - pub cryp_ids: Vec, -} - -#[derive(Debug,Clone,Serialize,Deserialize)] -struct GameJoinableListMsg { - method: String, - params: (), -} - -// #[derive(Debug,Clone,Serialize,Deserialize)] -// struct GameTargetMsg { -// method: String, -// params: GameTargetParams, -// } - -// #[derive(Debug,Clone,Serialize,Deserialize)] -// pub struct GameTargetParams { -// pub game_id: Uuid, -// pub cryp_id: Uuid, -// pub skill_id: Uuid, -// } - #[derive(Debug,Clone,Serialize,Deserialize)] struct GameSkillMsg { method: String, @@ -642,14 +519,25 @@ pub struct ZoneCloseParams { } #[derive(Debug,Clone,Serialize,Deserialize)] -struct VboxStateMsg { +struct InstanceJoinMsg { method: String, - params: VboxStateParams, + params: InstanceJoinParams, } #[derive(Debug,Clone,Serialize,Deserialize)] -pub struct VboxStateParams { - pub game_id: Uuid, +pub struct InstanceJoinParams { + pub cryp_ids: Vec, +} + +#[derive(Debug,Clone,Serialize,Deserialize)] +struct PlayerStateMsg { + method: String, + params: PlayerStateParams, +} + +#[derive(Debug,Clone,Serialize,Deserialize)] +pub struct PlayerStateParams { + pub instance_id: Uuid, } #[derive(Debug,Clone,Serialize,Deserialize)] @@ -660,7 +548,7 @@ struct VboxAcceptMsg { #[derive(Debug,Clone,Serialize,Deserialize)] pub struct VboxAcceptParams { - pub game_id: Uuid, + pub instance_id: Uuid, pub index: usize, } @@ -672,7 +560,7 @@ struct VboxDiscardMsg { #[derive(Debug,Clone,Serialize,Deserialize)] pub struct VboxDiscardParams { - pub game_id: Uuid, + pub instance_id: Uuid, } #[derive(Debug,Clone,Serialize,Deserialize)] @@ -683,7 +571,7 @@ struct VboxCombineMsg { #[derive(Debug,Clone,Serialize,Deserialize)] pub struct VboxCombineParams { - pub game_id: Uuid, + pub instance_id: Uuid, pub indices: Vec, } @@ -695,7 +583,7 @@ struct VboxApplyMsg { #[derive(Debug,Clone,Serialize,Deserialize)] pub struct VboxApplyParams { - pub game_id: Uuid, + pub instance_id: Uuid, pub cryp_id: Uuid, pub index: usize, } @@ -708,7 +596,7 @@ struct VboxDropMsg { #[derive(Debug,Clone,Serialize,Deserialize)] pub struct VboxDropParams { - pub game_id: Uuid, + pub instance_id: Uuid, pub index: usize, } diff --git a/server/src/vbox.rs b/server/src/vbox.rs index 9ce99389..05674889 100644 --- a/server/src/vbox.rs +++ b/server/src/vbox.rs @@ -6,16 +6,15 @@ use rand::prelude::*; use rand::{thread_rng}; use rand::distributions::{WeightedIndex}; -use serde_cbor::{from_slice, to_vec}; - use postgres::transaction::Transaction; use failure::Error; use failure::err_msg; use account::Account; -use rpc::{VboxStateParams, VboxAcceptParams, VboxDiscardParams, VboxCombineParams, VboxApplyParams, VboxDropParams}; +use rpc::{VboxAcceptParams, VboxDiscardParams, VboxCombineParams, VboxApplyParams, VboxDropParams}; use skill::{Skill}; +use player::{Player, player_get, player_update}; use cryp::{cryp_get, cryp_write}; #[derive(Debug,Clone,Copy,PartialEq,Serialize,Deserialize)] @@ -118,23 +117,23 @@ pub struct Vbox { pub balance: u16, pub free: Vec, pub bound: Vec, - pub game: Uuid, + pub instance: Uuid, pub account: Uuid, } impl Vbox { - pub fn new(account_id: Uuid, game_id: Uuid) -> Vbox { + pub fn new(account_id: Uuid, instance_id: Uuid) -> Vbox { Vbox { id: Uuid::new_v4(), account: account_id, - game: game_id, + instance: instance_id, free: vec![], bound: vec![], balance: 0, } } - pub fn fill(mut self: Vbox) -> Vbox { + pub fn fill(&mut self) -> &mut Vbox { let vars = vec![ (Var::Red, 1), (Var::Green, 1), @@ -277,107 +276,35 @@ impl Vbox { } } -pub fn vbox_create(vbox: Vbox, tx: &mut Transaction, account: &Account) -> Result { - let vbox_bytes = to_vec(&vbox)?; - - let query = " - INSERT INTO vbox (id, account, game, data) - VALUES ($1, $2, $3, $4) - RETURNING id; - "; - - let result = tx - .query(query, &[&vbox.id, &account.id, &vbox.game, &vbox_bytes])?; - - result.iter().next().ok_or(format_err!("no vbox written"))?; - - // println!("{:} wrote vbox", vbox.id); - - return Ok(vbox); +pub fn vbox_discard(params: VboxDiscardParams, tx: &mut Transaction, account: &Account) -> Result { + let mut player = player_get(tx, account.id, params.instance_id)?; + player.vbox.fill(); + return player_update(tx, player); } -pub fn vbox_write(vbox: Vbox, tx: &mut Transaction) -> Result { - let vbox_bytes = to_vec(&vbox)?; - - let query = " - UPDATE vbox - SET data = $1 - WHERE id = $2 - RETURNING id, account, data; - "; - - let result = tx - .query(query, &[&vbox_bytes, &vbox.id])?; - - result.iter().next().ok_or(err_msg("no vbox row returned"))?; - - // println!("{:?} wrote vbox", vbox.id); - - return Ok(vbox); +pub fn vbox_accept(params: VboxAcceptParams, tx: &mut Transaction, account: &Account) -> Result { + let mut player = player_get(tx, account.id, params.instance_id)?; + player.vbox.accept(params.index)?; + return player_update(tx, player); } - -pub fn vbox_get(tx: &mut Transaction, game_id: Uuid, account: &Account) -> Result { - let query = " - SELECT * - FROM vbox - WHERE account = $1 - AND game = $2; - "; - - let result = tx - .query(query, &[&account.id, &game_id])?; - - let returned = match result.iter().next() { - Some(row) => row, - None => return Err(err_msg("vbox not found")), - }; - - // tells from_slice to cast into a cryp - let vbox_bytes: Vec = returned.get("data"); - let vbox = from_slice::(&vbox_bytes)?; - - return Ok(vbox); +pub fn vbox_combine(params: VboxCombineParams, tx: &mut Transaction, account: &Account) -> Result { + let mut player = player_get(tx, account.id, params.instance_id)?; + player.vbox.combine(params.indices)?; + return player_update(tx, player); } -pub fn vbox_state(params: VboxStateParams, tx: &mut Transaction, account: &Account) -> Result { - match vbox_get(tx, params.game_id, account) { - Ok(v) => Ok(v), - Err(e) => { - println!("{:?}", e); - vbox_create(Vbox::new(account.id, params.game_id).fill(), tx, account) - } - } +pub fn vbox_drop(params: VboxDropParams, tx: &mut Transaction, account: &Account) -> Result { + let mut player = player_get(tx, account.id, params.instance_id)?; + player.vbox.drop(params.index)?; + return player_update(tx, player); } -pub fn vbox_discard(params: VboxDiscardParams, tx: &mut Transaction, account: &Account) -> Result { - let vbox = vbox_get(tx, params.game_id, account)?; - return vbox_write(vbox.fill(), tx); -} - -pub fn vbox_accept(params: VboxAcceptParams, tx: &mut Transaction, account: &Account) -> Result { - let mut vbox = vbox_get(tx, params.game_id, account)?; - vbox.accept(params.index)?; - return vbox_write(vbox, tx); -} - -pub fn vbox_combine(params: VboxCombineParams, tx: &mut Transaction, account: &Account) -> Result { - let mut vbox = vbox_get(tx, params.game_id, account)?; - vbox.combine(params.indices)?; - return vbox_write(vbox, tx); -} - -pub fn vbox_drop(params: VboxDropParams, tx: &mut Transaction, account: &Account) -> Result { - let mut vbox = vbox_get(tx, params.game_id, account)?; - vbox.drop(params.index)?; - return vbox_write(vbox, tx); -} - -pub fn vbox_apply(params: VboxApplyParams, tx: &mut Transaction, account: &Account) -> Result { - let mut vbox = vbox_get(tx, params.game_id, account)?; +pub fn vbox_apply(params: VboxApplyParams, tx: &mut Transaction, account: &Account) -> Result { + let mut player = player_get(tx, account.id, params.instance_id)?; let mut cryp = cryp_get(tx, params.cryp_id, account.id)?; - let var = vbox.bound.remove(params.index); + let var = player.vbox.bound.remove(params.index); // done here because i teach them a tonne of skills for tests let max_skills = 4; @@ -388,7 +315,7 @@ pub fn vbox_apply(params: VboxApplyParams, tx: &mut Transaction, account: &Accou let skill = var.skill()?; cryp = cryp.learn(skill); cryp_write(cryp, tx)?; - return vbox_write(vbox, tx); + return player_update(tx, player); }