Merge branch 'sql'

This commit is contained in:
ntr
2018-09-13 17:20:17 +10:00
24 changed files with 222 additions and 37 deletions
+57
View File
@@ -0,0 +1,57 @@
// use uuid::Uuid;
use rand::prelude::*;
use cryp::Cryp;
// impl Attribute {
// pub fn as_str(&self) -> &'static str {
// match self {
// Dmg => "dmg",
// Def => "def",
// }
// }
// }
#[derive(Debug)]
pub struct Battle {
a: Cryp,
b: Cryp,
}
impl Battle {
pub fn new(a: &Cryp, b: &Cryp) -> Battle {
return Battle {
a: a.clone(),
b: b.clone(),
};
}
pub fn cryps(&self) -> Vec<&Cryp> {
vec![&self.a, &self.b]
}
pub fn next(&mut self) -> &mut Battle {
let a_turn = self.a.turn();
let b_turn = self.b.turn();
self.a.assign_dmg(&self.b, &a_turn, &b_turn);
self.b.assign_dmg(&self.a, &b_turn, &a_turn);
self
}
pub fn finished(&self) -> bool {
self.cryps().iter().any(|c| c.is_ko())
}
pub fn winner(&self) -> Option<&Cryp> {
if self.cryps().iter().all(|c| c.is_ko()) {
return None
}
match self.cryps().iter().find(|c| !c.is_ko()) {
Some(w) => Some(w),
None => panic!("no winner found {:?}", self),
}
}
}
+113
View File
@@ -0,0 +1,113 @@
use rand::prelude::*;
use cryp::Cryp;
use battle::Battle;
use skill::Skill;
struct Encounter {
mob: Cryp,
success: bool,
player: Cryp,
}
pub fn battle(a: &Cryp, b: &Cryp) -> Battle {
let mut battle = Battle::new(a, b);
loop {
battle.next();
if battle.finished() {
break battle
}
}
}
fn pve(plr: Cryp) -> Encounter {
let mut rng = thread_rng();
let mob_lvl: u8 = rng.gen_range(1, plr.lvl);
let mob = Cryp::new()
.named("bamboo basher".to_string())
.level(mob_lvl)
.create();
let outcome = battle(&plr, &mob);
let success = match outcome.winner() {
Some(c) => c.id == plr.id,
None => false,
};
return Encounter {
mob: mob,
success,
player: plr,
};
}
pub fn levelling(mut c: Cryp) -> Cryp {
loop {
let enc = pve(c);
c = enc.player;
if !enc.success {
println!("{:?} has been KO'd", c.name);
break c;
}
println!("{:?} rekt {:?}", c.name, enc.mob.name);
c = c.add_xp();
println!("{:?} now has {:?} xp and is lvl {:?}", c.name, c.xp, c.lvl);
// LEVEL CAP
if c.lvl == 12 {
break c;
}
continue;
}
}
pub fn test_battle() {
let mut a = Cryp::new()
.named("pronounced \"creeep\"".to_string())
.level(8)
.learn(Skill::Stoney)
.create();
let b = Cryp::new()
.named("lemongrass tea".to_string())
.level(8)
.create();
let outcome = battle(&a, &b);
match outcome.winner() {
Some(w) => println!("{:?} is the winner with {:?} hp remaining", w.name, w.hp),
None => println!("{:?} was a draw", outcome),
};
return
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn pve_test() {
let player = Cryp::new()
.named("ca phe sua da".to_string())
.level(2)
.create();
levelling(player);
return;
}
#[test]
fn battle_test() {
test_battle();
return;
}
}
+209
View File
@@ -0,0 +1,209 @@
use uuid::Uuid;
use rand::prelude::*;
use serde_cbor::*;
use std::fs::File;
use std::io::prelude::*;
use rpc::{GenerateParams};
use skill::{Skill};
#[derive(Debug,Clone,Copy,PartialEq,Serialize,Deserialize)]
pub enum StatKind {
Dmg,
Def,
Hp,
Stam,
}
#[derive(Debug,Clone)]
pub struct Roll {
pub base: u64,
pub result: u64,
pub kind: StatKind,
}
#[derive(Debug,Clone,Serialize,Deserialize)]
pub struct Stat {
pub value: u64,
pub kind: StatKind,
}
impl Stat {
fn set(&mut self, v: u64) -> &Stat {
self.value = v;
self
}
fn roll(&self, c: &Cryp) -> Roll {
let mut rng = thread_rng();
let base: u64 = rng.gen();
let mut roll = Roll { kind: self.kind, base, result: base };
println!("{:?}", self.kind);
println!("{:064b} <- base roll", base);
// apply skills
roll = c.skills.iter().fold(roll, |roll, s| s.apply(roll));
// finally combine with stat
println!("{:064b} <- finalised", roll.result);
roll.result = roll.result & self.value;
println!("{:064b} & <- attribute roll", self.value);
println!("{:064b} = {:?}", roll.result, roll.result);
println!("");
return roll;
}
fn reduce(&mut self, dmg: u64) -> &mut Stat {
self.value = self.value.saturating_sub(dmg);
self
}
}
pub struct Turn {
pub dmg: Roll,
pub def: Roll,
}
#[derive(Debug,Clone,Serialize,Deserialize)]
pub struct Cryp {
pub id: Uuid,
// todo
// make attributes hold this value
pub dmg: Stat,
pub def: Stat,
pub stam: Stat,
pub hp: Stat,
pub xp: u64,
pub lvl: u8,
pub skills: Vec<Skill>,
pub name: String,
}
fn check_lvl(lvl: u8) -> u8 {
if lvl > 64 { return 64; }
return lvl;
}
impl Cryp {
pub fn new() -> Cryp {
let id = Uuid::new_v4();
return Cryp {
id,
dmg: Stat { value: 0, kind: StatKind::Dmg },
def: Stat { value: 0, kind: StatKind::Def },
stam: Stat { value: 0, kind: StatKind::Stam },
hp: Stat { value: 0, kind: StatKind::Hp },
lvl: 0,
xp: 0,
skills: vec![],
name: String::new()
};
}
pub fn named(mut self, name: String) -> Cryp {
self.name = name.clone();
self
}
pub fn level(mut self, lvl: u8) -> Cryp {
self.lvl = check_lvl(lvl);
self
}
pub fn learn(mut self, s: Skill) -> Cryp {
self.skills.push(s);
self
}
pub fn add_xp(mut self) -> Cryp {
self.xp = self.xp.saturating_add(1);
if self.xp.is_power_of_two() {
return self.level_up();
}
self
}
pub fn level_up(mut self) -> Cryp {
self.lvl = self.lvl.saturating_add(1);
self.create()
}
pub fn turn(&self) -> Turn {
// println!("{:?}'s turn:", c.name);
let dmg = self.dmg.roll(self);
let def = self.def.roll(self);
return Turn { dmg, def }
}
pub fn create(mut self) -> Cryp {
let mut rng = thread_rng();
let max = match self.lvl == 64 {
true => u64::max_value(),
false => 2_u64.pow(self.lvl.into()),
};
self.xp = max;
self.dmg.set(rng.gen_range(1, max));
self.def.set(rng.gen_range(1, max));
self.stam.set(rng.gen_range(1, max));
self.hp.set(self.stam.value);
self
}
pub fn assign_dmg(&mut self, opp: &Cryp, plr_t: &Turn, opp_t: &Turn) -> &mut Cryp {
let final_dmg = opp_t.dmg.result.saturating_sub(plr_t.def.result);
let blocked = opp_t.dmg.result.saturating_sub(final_dmg);
self.hp.reduce(final_dmg);
println!("{:?} deals {:?} dmg to {:?} ({:?} blocked / {:?} hp remaining)"
,opp.name
,final_dmg
,self.name
,blocked
,self.hp.value);
self
}
pub fn is_ko(&self) -> bool {
self.hp.value == 0
}
}
pub fn generate(params: GenerateParams) -> Vec<u8> {
let level_two = Cryp::new()
.named("hatchling".to_string())
.level(params.level)
.learn(Skill::Stoney)
.create();
to_vec(&level_two)
.expect("couldn't serialize cryp")
}
#[cfg(test)]
mod tests {
use cryp::*;
use skill::*;
#[test]
fn create_cryp_test() {
let max_level = Cryp::new()
.named("hatchling".to_string())
.level(64)
.learn(Skill::Stoney)
.create();
assert_eq!(max_level.lvl, 64);
return;
}
}
+29
View File
@@ -0,0 +1,29 @@
extern crate rand;
extern crate uuid;
extern crate ws;
extern crate env_logger;
// #[macro_use]
// extern crate dotenv;
extern crate r2d2;
extern crate r2d2_sqlite;
extern crate rusqlite;
extern crate serde;
extern crate serde_cbor;
#[macro_use]
extern crate serde_derive;
mod cryp;
mod battle;
mod net;
mod combat;
mod skill;
mod rpc;
mod user;
use net::{start};
fn main() {
start()
}
+55
View File
@@ -0,0 +1,55 @@
use ws::{listen, Handler, Sender, Result, Message, Handshake, CloseCode, Error};
use serde_cbor::{to_vec};
use r2d2::{Pool};
use r2d2::{PooledConnection};
use r2d2_sqlite::{SqliteConnectionManager};
pub type Db = PooledConnection<SqliteConnectionManager>;
use cryp::{generate};
use rpc::{Rpc,RpcMessage};
struct Server {
out: Sender,
rpc: Rpc,
db: Pool<SqliteConnectionManager>,
}
impl Handler for Server {
fn on_open(&mut self, _: Handshake) -> Result<()> {
println!("somebody joined");
Ok(())
}
fn on_message(&mut self, msg: Message) -> Result<()> {
let db = self.db.get().expect("unable to get db connection");
let reply = self.rpc.receive(msg, db);
println!("{:?}", reply);
self.out.send(reply.unwrap())
}
fn on_close(&mut self, code: CloseCode, reason: &str) {
match code {
CloseCode::Normal => println!("The client is done with the connection."),
CloseCode::Away => println!("The client is leaving the site."),
CloseCode::Abnormal => println!(
"Closing handshake failed! Unable to obtain closing status from client."),
_ => println!("The client encountered an error: {}", reason),
}
}
fn on_error(&mut self, err: Error) {
println!("The server encountered an error: {:?}", err);
}
}
pub fn start() {
let manager = SqliteConnectionManager::file("/var/cryps/cryps.db");
let pool = Pool::builder()
.build(manager)
.expect("Failed to create pool.");
listen("127.0.0.1:40000", |out| { Server { out, rpc: Rpc {}, db: pool.clone() } }).unwrap();
}
+90
View File
@@ -0,0 +1,90 @@
use std::result::Result as StdResult;
use ws::{Message};
use serde_cbor::{from_slice};
use serde_cbor::error::Error as CborError;
use net::Db;
use cryp::generate;
use user::{create};
pub struct Rpc;
impl Rpc {
pub fn receive(&self, msg: Message, db: Db) -> StdResult<Vec<u8>, RpcError> {
// consume the ws data into bytes
let data = msg.into_data();
// cast the msg to this type to receive method name
match from_slice::<RpcMessage>(&data) {
Ok(v) => {
// now we have the method name
// match on that to determine what fn to call
match v.method.as_ref() {
"cryp_generate" => {
match from_slice::<GenerateMsg>(&data) {
Ok(v) => Ok(generate(v.params)),
Err(_) => Err(RpcError::Parse),
}
},
"account_create" => {
match from_slice::<AccountCreateMsg>(&data) {
Ok(v) => Ok(create(v.params, db)),
Err(_) => Err(RpcError::Parse),
}
},
_ => Err(RpcError::UnknownMethod),
}
},
Err(_) => Err(RpcError::Parse),
}
}
}
#[derive(Debug,Clone,Serialize,Deserialize)]
pub struct RpcMessage {
method: String,
}
#[derive(Debug,Clone,Serialize,Deserialize)]
pub enum RpcError {
Parse,
UnknownMethod,
}
#[derive(Debug,Clone,Serialize,Deserialize)]
struct GenerateMsg {
method: String,
params: GenerateParams,
}
#[derive(Debug,Clone,Serialize,Deserialize)]
pub struct GenerateParams {
pub level: u8,
}
#[derive(Debug,Clone,Serialize,Deserialize)]
struct AccountCreateMsg {
method: String,
params: AccountCreateParams,
}
#[derive(Debug,Clone,Serialize,Deserialize)]
pub struct AccountCreateParams {
pub name: String,
}
// #[cfg(test)]
// mod tests {
// use super::*;
// use serde_cbor::to_vec;
// #[test]
// fn rpc_parse() {
// let rpc = Rpc {};
// let msg = GenerateMsg { method: "cryp_generate".to_string(), params: GenerateParams { level: 64 } };
// let v = to_vec(&msg).unwrap();
// let received = rpc.receive(Message::Binary(v));
// }
// }
+41
View File
@@ -0,0 +1,41 @@
use cryp::{StatKind, Roll};
#[derive(Debug,Clone,Copy,PartialEq,Serialize,Deserialize)]
pub enum Skill {
Stoney,
Evasive,
}
impl Skill {
pub fn apply(&self, mut roll: Roll) -> Roll {
match self {
Skill::Stoney => stoney(self, roll),
Skill::Evasive => evasive(self, roll),
_ => panic!("missing skill"),
}
}
}
fn stoney(s: &Skill, mut roll: Roll) -> Roll {
let effect = 0b11110000;
match roll.kind {
StatKind::Def => {
println!("{:064b} | <- {:?}", effect, s);
roll.result = roll.result | effect;
roll
},
_ => roll,
}
}
fn evasive(s: &Skill, mut roll: Roll) -> Roll {
match roll.kind {
StatKind::Def => {
if roll.result.is_power_of_two() {
roll.result = u64::max_value()
}
roll
},
_ => roll,
}
}
+29
View File
@@ -0,0 +1,29 @@
use serde_cbor::to_vec;
use uuid::Uuid;
use net::Db;
use rpc::{AccountCreateParams};
struct User {
name: String,
id: Uuid,
}
pub fn create(params: AccountCreateParams, db: Db) -> Vec<u8> {
let uuid = Uuid::new_v4();
let user = User {
id: uuid,
name: params.name,
};
let entry = db.execute("INSERT INTO users (id, name)
VALUES (?1, ?2)",
&[&user.id.to_string(), &user.name]).unwrap();
println!("{:?}", entry);
match to_vec(&true) {
Ok(v) => v,
Err(e) => panic!("couldn't serialize cryp"),
}
}