Changed how Locations are handled

+ Each location type is now a struct containing LocationData and location specific data.
+ Each type has its own place its own tree
+ Both were done in order to allow clear deserialization
main
Joey Hines 2021-03-13 14:42:37 -06:00
parent 0bcb28bc47
commit 2bf1b8ab1c
No known key found for this signature in database
GPG Key ID: 80F567B5C968F91B
13 changed files with 367 additions and 75 deletions

View File

@ -20,15 +20,20 @@ impl Database {
Ok(self.db.open_tree::<String>(T::tree())?) Ok(self.db.open_tree::<String>(T::tree())?)
} }
pub fn insert<'a, T>(&self, mut model: T) -> Result<T> where T: GeoffreyDatabaseModel { pub fn insert<T>(&self, mut model: T) -> Result<T> where T: GeoffreyDatabaseModel {
let id = match model.id() {
Some(id) => id,
None => {
let id = self.db.generate_id()?; let id = self.db.generate_id()?;
model.set_id(id);
id
}
};
let tree = self.get_tree::<T>()?; let tree = self.get_tree::<T>()?;
let data = serde_json::to_vec(&model).unwrap();
let id_bytes = u64_to_bytes(id); let id_bytes = u64_to_bytes(id);
tree.insert(id_bytes, data)?; tree.insert(id_bytes, model.to_bytes()?)?;
model.set_id(id);
Ok(model) Ok(model)
} }
@ -39,7 +44,7 @@ impl Database {
let id_bytes = u64_to_bytes(id); let id_bytes = u64_to_bytes(id);
if let Some(bytes) = tree.get(id_bytes)? { if let Some(bytes) = tree.get(id_bytes)? {
Ok(Some(T::try_from_bytes(&bytes).unwrap())) Ok(Some(T::try_from_bytes(&bytes)?))
} }
else { else {
Ok(None) Ok(None)
@ -54,6 +59,8 @@ mod tests {
use std::path::Path; use std::path::Path;
use geoffrey_models::models::player::{Player, UserID}; use geoffrey_models::models::player::{Player, UserID};
use lazy_static::lazy_static; use lazy_static::lazy_static;
use geoffrey_models::models::shop::Shop;
use geoffrey_models::models::{Location, Position};
lazy_static! { lazy_static! {
@ -87,5 +94,20 @@ mod tests {
assert_eq!(p3.unwrap().name, player.name); assert_eq!(p3.unwrap().name, player.name);
cleanup(); cleanup();
} }
#[test]
fn test_shop() {
let player = Player::new("CoolZero123", UserID::DiscordUUID(0));
let player= DB.insert::<Player>(player.clone()).unwrap();
let shop = Shop::new("cool shop123", Position::default(), player.id.unwrap(), None);
let shop2 = DB.insert::<Shop>(shop.clone()).unwrap();
assert_eq!(shop.name(), shop2.name());
let shop3 = DB.get::<Shop>(shop2.id.unwrap()).unwrap().unwrap();
assert_eq!(shop3.id, shop2.id);
cleanup();
}
} }

View File

@ -1,3 +1,4 @@
#![allow(dead_code)]
use byteorder::{WriteBytesExt, BigEndian}; use byteorder::{WriteBytesExt, BigEndian};
pub mod database; pub mod database;

View File

@ -1,5 +1,4 @@
#[allow(dead_code)] #![allow(dead_code)]
use serde::{Serialize}; use serde::{Serialize};
use serde::de::DeserializeOwned; use serde::de::DeserializeOwned;
@ -10,8 +9,20 @@ pub trait GeoffreyDatabaseModel: Serialize + DeserializeOwned {
fn set_id(&mut self, id: u64); fn set_id(&mut self, id: u64);
fn tree() -> String; fn tree() -> String;
fn try_from_bytes(v: &[u8]) -> Result<Self, serde_json::Error> { fn to_json_string(&self) -> Result<String, serde_json::Error> {
Ok(serde_json::from_slice::<Self>(v)?) serde_json::to_string(self)
}
fn try_from_str(s: &str) -> Result<Self, serde_json::Error> {
serde_json::from_str(s)
}
fn to_bytes(&self) -> Result<Vec<u8>, serde_json::Error> {
serde_json::to_vec(self)
}
fn try_from_bytes(b: &[u8]) -> Result<Self, serde_json::Error> {
serde_json::from_slice(b)
} }
} }

View File

@ -0,0 +1,40 @@
use serde::{Serialize, Deserialize};
use crate::models::{LocationData, Location, Position, Tunnel};
use crate::GeoffreyDatabaseModel;
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Attraction {
pub id: Option<u64>,
pub location_data: LocationData
}
impl GeoffreyDatabaseModel for Attraction {
fn id(&self) -> Option<u64> {
self.id
}
fn set_id(&mut self, id: u64) {
self.id = Some(id)
}
fn tree() -> String {
"attraction".to_string()
}
}
impl Location for Attraction {
fn new(name: &str, position: Position, owner: u64, tunnel: Option<Tunnel>) -> Self {
Self {
id: None,
location_data: LocationData::new(name, position, owner, tunnel)
}
}
fn mut_location_data(&mut self) -> &mut LocationData {
&mut self.location_data
}
fn location_data(&self) -> &LocationData {
&self.location_data
}
}

View File

@ -0,0 +1,40 @@
use serde::{Serialize, Deserialize};
use crate::models::{LocationData, Location, Position, Tunnel};
use crate::GeoffreyDatabaseModel;
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Base {
pub id: Option<u64>,
pub location_data: LocationData
}
impl GeoffreyDatabaseModel for Base {
fn id(&self) -> Option<u64> {
self.id
}
fn set_id(&mut self, id: u64) {
self.id = Some(id)
}
fn tree() -> String {
"base".to_string()
}
}
impl Location for Base {
fn new(name: &str, position: Position, owner: u64, tunnel: Option<Tunnel>) -> Self {
Self {
id: None,
location_data: LocationData::new(name, position, owner, tunnel)
}
}
fn mut_location_data(&mut self) -> &mut LocationData {
&mut self.location_data
}
fn location_data(&self) -> &LocationData {
&self.location_data
}
}

View File

@ -1,8 +1,44 @@
use serde::{Deserialize, Serialize}; use serde::{Serialize, Deserialize};
use crate::models::{LocationData, Location, Position, Tunnel};
use crate::models::item::Item; use crate::models::item::Item;
use crate::GeoffreyDatabaseModel;
use std::collections::HashSet;
#[derive(Serialize, Deserialize, Debug, Clone)] #[derive(Serialize, Deserialize, Debug, Clone)]
pub struct FarmData { pub struct Farm {
pub items_produced: Vec<Item> pub id: Option<u64>,
pub location_data: LocationData,
pub items_produced: HashSet<Item>
} }
impl GeoffreyDatabaseModel for Farm {
fn id(&self) -> Option<u64> {
self.id
}
fn set_id(&mut self, id: u64) {
self.id = Some(id)
}
fn tree() -> String {
"farm".to_string()
}
}
impl Location for Farm {
fn new(name: &str, position: Position, owner: u64, tunnel: Option<Tunnel>) -> Self {
Self {
id: None,
location_data: LocationData::new(name, position, owner, tunnel),
items_produced: HashSet::new(),
}
}
fn mut_location_data(&mut self) -> &mut LocationData {
&mut self.location_data
}
fn location_data(&self) -> &LocationData {
&self.location_data
}
}

View File

@ -1,6 +1,6 @@
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Debug, Clone)] #[derive(Serialize, Deserialize, Debug, Clone, Hash, Eq, PartialEq)]
pub struct Item { pub struct Item {
pub name: String, pub name: String,
} }

View File

@ -1,6 +1,44 @@
use serde::{Deserialize, Serialize}; use serde::{Serialize, Deserialize};
use crate::models::{LocationData, Location, Position, Tunnel};
use crate::GeoffreyDatabaseModel;
use std::collections::HashSet;
#[derive(Serialize, Deserialize, Debug, Clone)] #[derive(Serialize, Deserialize, Debug, Clone)]
pub struct MarketData { pub struct Market {
pub shops: Vec<u64>, pub id: Option<u64>,
pub location_data: LocationData,
pub shops: HashSet<u64>
} }
impl GeoffreyDatabaseModel for Market {
fn id(&self) -> Option<u64> {
self.id
}
fn set_id(&mut self, id: u64) {
self.id = Some(id)
}
fn tree() -> String {
"farm".to_string()
}
}
impl Location for Market {
fn new(name: &str, position: Position, owner: u64, tunnel: Option<Tunnel>) -> Self {
Self {
id: None,
location_data: LocationData::new(name, position, owner, tunnel),
shops: HashSet::new()
}
}
fn mut_location_data(&mut self) -> &mut LocationData {
&mut self.location_data
}
fn location_data(&self) -> &LocationData {
&self.location_data
}
}

View File

@ -1,10 +1,6 @@
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::models::player::Player; use serde::de::DeserializeOwned;
use crate::models::shop::ShopData; use std::collections::HashSet;
use crate::models::town::TownData;
use crate::models::market::MarketData;
use crate::models::farm::FarmData;
use crate::GeoffreyDatabaseModel;
pub mod player; pub mod player;
pub mod shop; pub mod shop;
@ -13,17 +9,9 @@ pub mod town;
pub mod farm; pub mod farm;
pub mod market; pub mod market;
pub mod token; pub mod token;
mod meta; pub mod meta;
mod base;
#[derive(Serialize, Deserialize, Debug, Clone)] pub mod attraction;
pub enum LocationData {
Base,
Shop(ShopData),
Town(TownData),
Market(MarketData),
Attraction,
PublicFarm(FarmData),
}
#[derive(Serialize, Deserialize, Debug, Copy, Clone)] #[derive(Serialize, Deserialize, Debug, Copy, Clone)]
pub enum Dimension { pub enum Dimension {
@ -50,7 +38,17 @@ pub enum Direction {
pub struct Position { pub struct Position {
pub x: i64, pub x: i64,
pub y: i64, pub y: i64,
dimension: Dimension, pub dimension: Dimension,
}
impl Position {
pub fn new(x: i64, y: i64, dimension: Dimension) -> Self {
Self {
x,
y,
dimension
}
}
} }
#[derive(Serialize, Deserialize, Debug, Clone)] #[derive(Serialize, Deserialize, Debug, Clone)]
@ -59,53 +57,68 @@ pub struct Tunnel {
number: i64 number: i64
} }
#[derive(Serialize, Deserialize, Debug, Clone)] #[derive(Serialize, Deserialize, Debug, Clone, Default)]
pub struct Location { pub struct LocationData {
id: Option<u64>,
name: String, name: String,
position: Position, position: Position,
owners: Vec<Player>, owners: HashSet<u64>,
tunnel: Option<Tunnel>, tunnel: Option<Tunnel>,
loc_data: LocationData,
} }
impl Location { impl LocationData {
pub fn new (name: &str, position: Position, owners: Vec<Player>, tunnel: Option<Tunnel>, loc_data: LocationData) -> Self { pub fn new (name: &str, position: Position, owner: u64, tunnel: Option<Tunnel>) -> Self {
Location { let mut owners = HashSet::new();
id: None, owners.insert(owner);
Self {
name: name.to_string(), name: name.to_string(),
position, position,
owners, owners,
tunnel, tunnel,
loc_data,
} }
} }
} }
impl GeoffreyDatabaseModel for Location { pub trait Location: Serialize + DeserializeOwned + Clone {
fn id(&self) -> Option<u64> { fn new (name: &str, position: Position, owner: u64, tunnel: Option<Tunnel>) -> Self;
self.id fn mut_location_data(&mut self) -> &mut LocationData;
fn location_data(&self) -> &LocationData;
fn name(&self) -> String {
self.location_data().name.clone()
} }
fn set_id(&mut self, id: u64) { fn owners(&self) -> Vec<u64> {
self.id = Some(id); self.location_data().owners.iter().cloned().collect()
} }
fn tree() -> String { fn position(&self) -> Position {
"location".to_string() self.location_data().position.clone()
} }
}
fn tunnel(&self) -> Option<Tunnel> {
#[cfg(test)] self.location_data().tunnel.clone()
mod tests { }
use crate::models::{Location, Position, Dimension, LocationData};
use crate::models::player::{Player, UserID}; fn add_owner(&mut self, owner: u64) {
self.mut_location_data().owners.insert(owner);
#[test] }
fn test_new_base() {
let player = Player::new("CoolZero123", UserID::DiscordUUID(0)); fn remove_owner(&mut self, owner: u64) {
Location::new("test", Position {x: 0, y: 0, dimension: Dimension::Overworld}, vec![player], None, LocationData::Base); self.mut_location_data().owners.remove(&owner);
}
fn set_position(&mut self, position: Position) {
self.mut_location_data().position = position;
}
fn set_tunnel(&mut self, tunnel: Tunnel) {
self.mut_location_data().tunnel = Some(tunnel);
}
fn set_name(&mut self, name: &str) {
self.mut_location_data().name = name.to_string();
} }
} }

View File

@ -1,13 +1,13 @@
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::GeoffreyDatabaseModel; use crate::GeoffreyDatabaseModel;
#[derive(Serialize, Deserialize, Debug, Clone)] #[derive(Serialize, Deserialize, Debug, Clone, Hash, PartialEq, Eq)]
pub enum UserID { pub enum UserID {
DiscordUUID(u64), DiscordUUID(u64),
MinecraftUUID(String), MinecraftUUID(String),
} }
#[derive(Serialize, Deserialize, Debug, Clone)] #[derive(Serialize, Deserialize, Debug, Clone, Hash, PartialEq, Eq)]
pub struct Player { pub struct Player {
pub id: Option<u64>, pub id: Option<u64>,
pub name: String, pub name: String,

View File

@ -2,8 +2,11 @@ use serde::{Deserialize, Serialize};
use chrono::{DateTime, Utc}; use chrono::{DateTime, Utc};
use crate::models::item::Item; use crate::models::item::Item;
use std::collections::HashSet;
use crate::models::{LocationData, Location, Tunnel, Position};
use crate::GeoffreyDatabaseModel;
#[derive(Serialize, Deserialize, Debug, Clone)] #[derive(Serialize, Deserialize, Debug, Clone, Hash, Eq, PartialEq)]
pub struct ItemListing { pub struct ItemListing {
pub item: Item, pub item: Item,
pub price: u64, pub price: u64,
@ -22,8 +25,58 @@ impl ItemListing {
} }
} }
#[derive(Default, Serialize, Deserialize, Debug, Clone)] #[derive(Serialize, Deserialize, Debug, Clone)]
pub struct ShopData { pub struct Shop {
pub item_listings: Vec<ItemListing> pub id: Option<u64>,
pub item_listings: HashSet<ItemListing>,
pub location_data: LocationData
}
impl Location for Shop {
fn new(name: &str, position: Position, owner: u64, tunnel: Option<Tunnel>) -> Self {
Self {
id: None,
item_listings: Default::default(),
location_data: LocationData::new(name, position, owner, tunnel)
}
}
fn mut_location_data(&mut self) -> &mut LocationData {
&mut self.location_data
}
fn location_data(&self) -> &LocationData {
&self.location_data
}
}
impl GeoffreyDatabaseModel for Shop {
fn id(&self) -> Option<u64> {
self.id
}
fn set_id(&mut self, id: u64) {
self.id = Some(id);
}
fn tree() -> String {
"shop".to_string()
}
}
#[cfg(test)]
mod tests {
use crate::models::{Position, Dimension, LocationData, Location};
use crate::models::player::{Player, UserID};
use crate::models::shop::Shop;
fn create_shop() -> Shop {
let player = Player::new("CoolZero123", UserID::DiscordUUID(0));
let shop = Shop::new("Cool Shop 123", Position::default(), player, None);
}
#[test]
fn test_new_shop() {
}
} }

View File

@ -71,7 +71,7 @@ mod tests {
#[test] #[test]
fn test_token() { fn test_token() {
let mut token = Token::new(0); let mut token = Token::new();
token.set_permission(Permissions::ModelGet); token.set_permission(Permissions::ModelGet);
assert_eq!(token.permission, 0x1u64); assert_eq!(token.permission, 0x1u64);

View File

@ -1,7 +1,45 @@
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::models::{LocationData, Location, Position, Tunnel};
use crate::models::player::Player;
use crate::GeoffreyDatabaseModel;
use std::collections::HashSet;
#[derive(Default, Serialize, Deserialize, Debug, Clone)] #[derive(Serialize, Deserialize, Debug, Clone)]
pub struct TownData { pub struct Town {
pub resident: Vec<u64> pub id: Option<u64>,
pub location_data: LocationData,
pub residents: HashSet<Player>
}
impl GeoffreyDatabaseModel for Town {
fn id(&self) -> Option<u64> {
self.id
}
fn set_id(&mut self, id: u64) {
self.id = Some(id)
}
fn tree() -> String {
"town".to_string()
}
}
impl Location for Town {
fn new(name: &str, position: Position, owner: u64, tunnel: Option<Tunnel>) -> Self {
Self {
id: None,
location_data: LocationData::new(name, position, owner, tunnel),
residents: HashSet::new(),
}
}
fn mut_location_data(&mut self) -> &mut LocationData {
&mut self.location_data
}
fn location_data(&self) -> &LocationData {
&self.location_data
}
} }