Updated models + migration infra
+ Model migration is handled in the DB modules + It involves writing an up and a down case + Both load and interact with the JSON directly + Done so it can be decoupled from modelsmain
parent
a655146c81
commit
12218d0b62
|
@ -456,6 +456,7 @@ version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"byteorder",
|
"byteorder",
|
||||||
"geoffrey_models",
|
"geoffrey_models",
|
||||||
|
"json",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"log",
|
"log",
|
||||||
"serde 1.0.130",
|
"serde 1.0.130",
|
||||||
|
@ -707,6 +708,12 @@ dependencies = [
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "json"
|
||||||
|
version = "0.12.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "078e285eafdfb6c4b434e0d31e8cfcb5115b651496faca5749b88fafd4f23bfd"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lazy_static"
|
name = "lazy_static"
|
||||||
version = "1.4.0"
|
version = "1.4.0"
|
||||||
|
|
|
@ -33,7 +33,7 @@ impl Command for AddLocation {
|
||||||
req.name.as_str(),
|
req.name.as_str(),
|
||||||
req.position,
|
req.position,
|
||||||
user.id.unwrap(),
|
user.id.unwrap(),
|
||||||
req.tunnel.clone(),
|
req.portal.clone(),
|
||||||
req.loc_type.into(),
|
req.loc_type.into(),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -54,22 +54,28 @@ impl BotCommand for AddLocationCommand {
|
||||||
.create_option(|option| {
|
.create_option(|option| {
|
||||||
option
|
option
|
||||||
.name("x")
|
.name("x")
|
||||||
.description("X coordinate of the shop")
|
.description("X coordinate of the location")
|
||||||
.kind(ApplicationCommandOptionType::Integer)
|
.kind(ApplicationCommandOptionType::Integer)
|
||||||
|
.max_int_value(i32::MAX)
|
||||||
|
.min_int_value(i32::MIN)
|
||||||
.required(true)
|
.required(true)
|
||||||
})
|
})
|
||||||
.create_option(|option| {
|
.create_option(|option| {
|
||||||
option
|
option
|
||||||
.name("y")
|
.name("y")
|
||||||
.description("Y coordinate of the shop")
|
.description("Y coordinate of the location")
|
||||||
.kind(ApplicationCommandOptionType::Integer)
|
.kind(ApplicationCommandOptionType::Integer)
|
||||||
|
.max_int_value(i32::MAX)
|
||||||
|
.min_int_value(i32::MIN)
|
||||||
.required(true)
|
.required(true)
|
||||||
})
|
})
|
||||||
.create_option(|option| {
|
.create_option(|option| {
|
||||||
option
|
option
|
||||||
.name("z")
|
.name("z")
|
||||||
.description("Z coordinate of the shop")
|
.description("Z coordinate of the location")
|
||||||
.kind(ApplicationCommandOptionType::Integer)
|
.kind(ApplicationCommandOptionType::Integer)
|
||||||
|
.max_int_value(i32::MAX)
|
||||||
|
.min_int_value(i32::MIN)
|
||||||
.required(true)
|
.required(true)
|
||||||
})
|
})
|
||||||
.create_option(|option| {
|
.create_option(|option| {
|
||||||
|
@ -82,20 +88,6 @@ impl BotCommand for AddLocationCommand {
|
||||||
.add_string_choice(Dimension::TheEnd, Dimension::TheEnd)
|
.add_string_choice(Dimension::TheEnd, Dimension::TheEnd)
|
||||||
.required(false)
|
.required(false)
|
||||||
})
|
})
|
||||||
.create_option(|option| {
|
|
||||||
option
|
|
||||||
.name("portal_x")
|
|
||||||
.description("X Coordinate of the portal in the nether")
|
|
||||||
.kind(ApplicationCommandOptionType::Integer)
|
|
||||||
.required(false)
|
|
||||||
})
|
|
||||||
.create_option(|option| {
|
|
||||||
option
|
|
||||||
.name("portal_z")
|
|
||||||
.description("Z Coordinate of the portal in the nether")
|
|
||||||
.kind(ApplicationCommandOptionType::Integer)
|
|
||||||
.required(false)
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
|
@ -109,11 +101,11 @@ impl BotCommand for AddLocationCommand {
|
||||||
let name = option_to_string(options.get(0), "name")?;
|
let name = option_to_string(options.get(0), "name")?;
|
||||||
let loc_type = option_to_loc_type(options.get(1), "loc_type")?;
|
let loc_type = option_to_loc_type(options.get(1), "loc_type")?;
|
||||||
let x = option_to_i64(options.get(2), "x")?;
|
let x = option_to_i64(options.get(2), "x")?;
|
||||||
let _y = option_to_i64(options.get(3), "x")?;
|
let y = option_to_i64(options.get(3), "y")?;
|
||||||
let z = option_to_i64(options.get(4), "x")?;
|
let z = option_to_i64(options.get(4), "z")?;
|
||||||
let dim = option_to_dim(options.get(5), "dimension").unwrap_or(Dimension::Overworld);
|
let dim = option_to_dim(options.get(5), "dimension").unwrap_or(Dimension::Overworld);
|
||||||
|
|
||||||
let position = Position::new(x as i32, z as i32, dim);
|
let position = Position::new(x as i32, y as i32, z as i32, dim);
|
||||||
|
|
||||||
Ok(Self::ApiParams::new(name, position, loc_type, None))
|
Ok(Self::ApiParams::new(name, position, loc_type, None))
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,7 @@ geoffrey_models = { path = "../geoffrey_models" }
|
||||||
byteorder = "1.4.2"
|
byteorder = "1.4.2"
|
||||||
log = "0.4.14"
|
log = "0.4.14"
|
||||||
simple_logger = "1.13.0"
|
simple_logger = "1.13.0"
|
||||||
|
json = "0.12.4"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
lazy_static = "1.4.0"
|
lazy_static = "1.4.0"
|
||||||
|
|
|
@ -2,16 +2,26 @@ use crate::error::{GeoffreyDBError, Result};
|
||||||
use geoffrey_models::GeoffreyDatabaseModel;
|
use geoffrey_models::GeoffreyDatabaseModel;
|
||||||
use std::convert::TryInto;
|
use std::convert::TryInto;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
use geoffrey_models::models::db_metadata::DBMetadata;
|
||||||
|
use crate::migration::do_migration;
|
||||||
|
|
||||||
|
const DB_VERSION: u64 = 2;
|
||||||
|
const DB_METADATA_ID: u64 = 1;
|
||||||
|
|
||||||
pub struct Database {
|
pub struct Database {
|
||||||
db: sled::Db,
|
pub(crate) db: sled::Db,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Database {
|
impl Database {
|
||||||
pub fn new(db_path: &Path) -> Result<Self> {
|
pub fn new(db_path: &Path) -> Result<Self> {
|
||||||
let db = sled::open(db_path)?;
|
let db = sled::open(db_path)?;
|
||||||
|
let db = Self { db };
|
||||||
|
|
||||||
Ok(Self { db })
|
do_migration(&db, DB_VERSION)?;
|
||||||
|
|
||||||
|
log::info!("Geoffrey Database V{}", db.version()?);
|
||||||
|
|
||||||
|
Ok(db)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_tree<T>(&self) -> Result<sled::Tree>
|
fn get_tree<T>(&self) -> Result<sled::Tree>
|
||||||
|
@ -106,6 +116,20 @@ impl Database {
|
||||||
{
|
{
|
||||||
Ok(self.db.open_tree(T::tree()).map(|tree| tree.iter())?)
|
Ok(self.db.open_tree(T::tree()).map(|tree| tree.iter())?)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn version(&self) -> Result<u64> {
|
||||||
|
Ok(self.get::<DBMetadata>(DB_METADATA_ID)?.version)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn set_version(&mut self, version: u64) -> Result<()> {
|
||||||
|
let mut md = self.get::<DBMetadata>(0)?;
|
||||||
|
|
||||||
|
md.version = version;
|
||||||
|
|
||||||
|
self.insert(md)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
@ -182,7 +206,7 @@ mod tests {
|
||||||
let player = DB.insert::<Player>(player.clone()).unwrap();
|
let player = DB.insert::<Player>(player.clone()).unwrap();
|
||||||
let loc = LocationDb::new(
|
let loc = LocationDb::new(
|
||||||
"Test Shop",
|
"Test Shop",
|
||||||
Position::new(0, 0, Dimension::Overworld),
|
Position::new(0, 0, 0, Dimension::Overworld),
|
||||||
player.id.unwrap(),
|
player.id.unwrap(),
|
||||||
None,
|
None,
|
||||||
LocationDataDb::Shop(Shop {
|
LocationDataDb::Shop(Shop {
|
||||||
|
|
|
@ -3,3 +3,4 @@
|
||||||
pub mod database;
|
pub mod database;
|
||||||
pub mod error;
|
pub mod error;
|
||||||
pub mod helper;
|
pub mod helper;
|
||||||
|
pub(crate) mod migration;
|
||||||
|
|
|
@ -0,0 +1,98 @@
|
||||||
|
use crate::migration::Migration;
|
||||||
|
use crate::database::Database;
|
||||||
|
use geoffrey_models::models::locations::LocationDb;
|
||||||
|
use geoffrey_models::GeoffreyDatabaseModel;
|
||||||
|
use json::JsonValue;
|
||||||
|
|
||||||
|
pub(crate) struct PosAndNetherMigration {}
|
||||||
|
|
||||||
|
impl Migration for PosAndNetherMigration {
|
||||||
|
fn up(db: &Database) -> crate::error::Result<()> {
|
||||||
|
let loc_tree = db.db.open_tree(LocationDb::tree())?;
|
||||||
|
|
||||||
|
for entry in loc_tree.iter() {
|
||||||
|
let (id, loc_ivec) = entry?;
|
||||||
|
let mut loc = json::parse(std::str::from_utf8(&loc_ivec).unwrap()).unwrap();
|
||||||
|
|
||||||
|
let z = loc["position"]["y"].clone();
|
||||||
|
|
||||||
|
loc["position"]["y"] = 65.into();
|
||||||
|
loc["position"]["z"] = z;
|
||||||
|
|
||||||
|
loc["tunnel"] = JsonValue::Null;
|
||||||
|
|
||||||
|
println!("{}", loc.dump());
|
||||||
|
|
||||||
|
loc_tree.insert(id, loc.to_string().as_bytes())?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn down(db: &Database) -> crate::error::Result<()> {
|
||||||
|
let loc_tree = db.db.open_tree(LocationDb::tree())?;
|
||||||
|
|
||||||
|
for entry in loc_tree.iter() {
|
||||||
|
let (id, loc_ivec) = entry?;
|
||||||
|
let mut loc = json::parse(std::str::from_utf8(&loc_ivec).unwrap()).unwrap();
|
||||||
|
|
||||||
|
loc["position"]["y"] = loc["position"]["z"].clone();
|
||||||
|
loc["position"]["z"].clear();
|
||||||
|
|
||||||
|
// Clear out the tunnel entry, there is not a great way to convert
|
||||||
|
loc["tunnel"] = JsonValue::Null;
|
||||||
|
|
||||||
|
loc_tree.insert(id, loc.to_string().as_bytes())?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fn version() -> u64 {
|
||||||
|
2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use crate::database::Database;
|
||||||
|
use std::path::Path;
|
||||||
|
use geoffrey_models::models::locations::LocationDb;
|
||||||
|
use geoffrey_models::GeoffreyDatabaseModel;
|
||||||
|
use sled::IVec;
|
||||||
|
use crate::migration::migration_2::PosAndNetherMigration;
|
||||||
|
use crate::migration::Migration;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_migration_2() {
|
||||||
|
let db = Database::new(Path::new("../migration_2_db/")).unwrap();
|
||||||
|
|
||||||
|
let loc_tree = db.db.open_tree(LocationDb::tree()).unwrap();
|
||||||
|
|
||||||
|
let old_loc_format = json::parse(r#"{
|
||||||
|
"id": 55,
|
||||||
|
"name": "Test",
|
||||||
|
"position": {
|
||||||
|
"x": 55,
|
||||||
|
"y": 55,
|
||||||
|
"dimension": "Overworld"
|
||||||
|
},
|
||||||
|
"loc_data": "Base"
|
||||||
|
}"#).unwrap();
|
||||||
|
|
||||||
|
loc_tree.insert(IVec::from(vec![55]), old_loc_format.to_string().as_bytes()).unwrap();
|
||||||
|
|
||||||
|
PosAndNetherMigration::up(&db).unwrap();
|
||||||
|
|
||||||
|
let new_loc = loc_tree.get(IVec::from(vec![55])).unwrap().unwrap();
|
||||||
|
let new_loc = json::parse(std::str::from_utf8(&new_loc).unwrap()).unwrap();
|
||||||
|
|
||||||
|
assert_eq!(new_loc["position"]["y"], 65);
|
||||||
|
assert_eq!(new_loc["position"]["z"], 55);
|
||||||
|
|
||||||
|
drop(db);
|
||||||
|
|
||||||
|
std::fs::remove_dir_all("../migration_2_db").unwrap();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,53 @@
|
||||||
|
use crate::database::Database;
|
||||||
|
use crate::error::Result;
|
||||||
|
use crate::migration::migration_2::PosAndNetherMigration;
|
||||||
|
use geoffrey_models::models::db_metadata::DBMetadata;
|
||||||
|
|
||||||
|
mod migration_2;
|
||||||
|
|
||||||
|
trait Migration {
|
||||||
|
fn up(db: &Database) -> Result<()>;
|
||||||
|
fn down(db: &Database) -> Result<()>;
|
||||||
|
fn version() -> u64;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn upgrade(db: &Database, current_version: u64, target_version: u64) -> Result<()> {
|
||||||
|
for ver in current_version+1..=target_version {
|
||||||
|
match ver {
|
||||||
|
2 => PosAndNetherMigration::up(db)?,
|
||||||
|
_ => ()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn downgrade(db: &Database, current_version: u64, target_version: u64) -> Result<()> {
|
||||||
|
for ver in (target_version..current_version).rev() {
|
||||||
|
match ver {
|
||||||
|
2 => PosAndNetherMigration::up(db)?,
|
||||||
|
_ => ()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn do_migration(db: &Database, target_version: u64) -> Result<()> {
|
||||||
|
let current_version = db.version().unwrap_or(0);
|
||||||
|
|
||||||
|
if target_version > current_version {
|
||||||
|
upgrade(db, current_version, target_version)?;
|
||||||
|
}
|
||||||
|
else if target_version < current_version {
|
||||||
|
downgrade(db, current_version, target_version)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
let metadata = DBMetadata {
|
||||||
|
version: target_version,
|
||||||
|
};
|
||||||
|
|
||||||
|
db.insert(metadata)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
|
@ -5,7 +5,6 @@ use std::fmt::Debug;
|
||||||
|
|
||||||
pub mod models;
|
pub mod models;
|
||||||
|
|
||||||
const DB_VERSION: u64 = 1;
|
|
||||||
|
|
||||||
pub trait GeoffreyDatabaseModel: Serialize + DeserializeOwned + Debug {
|
pub trait GeoffreyDatabaseModel: Serialize + DeserializeOwned + Debug {
|
||||||
fn id(&self) -> Option<u64>;
|
fn id(&self) -> Option<u64>;
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use crate::GeoffreyDatabaseModel;
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug, Clone, Hash, Eq, PartialEq)]
|
||||||
|
pub struct DBMetadata {
|
||||||
|
pub version: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GeoffreyDatabaseModel for DBMetadata {
|
||||||
|
fn id(&self) -> Option<u64> {
|
||||||
|
Some(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_id(&mut self, _id: u64) {}
|
||||||
|
|
||||||
|
fn tree() -> String {
|
||||||
|
"DBMetadata".to_string()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@ use crate::models::locations::market::{Market, MarketDb};
|
||||||
use crate::models::locations::shop::Shop;
|
use crate::models::locations::shop::Shop;
|
||||||
use crate::models::locations::town::{Town, TownDb};
|
use crate::models::locations::town::{Town, TownDb};
|
||||||
use crate::models::player::Player;
|
use crate::models::player::Player;
|
||||||
use crate::models::{Position, Tunnel};
|
use crate::models::{Position, Portal};
|
||||||
use crate::GeoffreyDatabaseModel;
|
use crate::GeoffreyDatabaseModel;
|
||||||
use std::fmt::{Display, Formatter};
|
use std::fmt::{Display, Formatter};
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
@ -111,7 +111,7 @@ pub struct LocationDb {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub position: Position,
|
pub position: Position,
|
||||||
owners: HashSet<u64>,
|
owners: HashSet<u64>,
|
||||||
pub tunnel: Option<Tunnel>,
|
pub tunnel: Option<Portal>,
|
||||||
pub loc_data: LocationDataDb,
|
pub loc_data: LocationDataDb,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -120,7 +120,7 @@ impl LocationDb {
|
||||||
name: &str,
|
name: &str,
|
||||||
position: Position,
|
position: Position,
|
||||||
owner: u64,
|
owner: u64,
|
||||||
tunnel: Option<Tunnel>,
|
tunnel: Option<Portal>,
|
||||||
loc_type: LocationDataDb,
|
loc_type: LocationDataDb,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let mut owners = HashSet::new();
|
let mut owners = HashSet::new();
|
||||||
|
@ -173,7 +173,7 @@ pub struct Location {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub position: Position,
|
pub position: Position,
|
||||||
pub owners: Vec<Player>,
|
pub owners: Vec<Player>,
|
||||||
pub tunnel: Option<Tunnel>,
|
pub tunnel: Option<Portal>,
|
||||||
pub loc_data: LocationData,
|
pub loc_data: LocationData,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -204,14 +204,14 @@ mod tests {
|
||||||
fn test_location_check_unique() {
|
fn test_location_check_unique() {
|
||||||
let l1 = LocationDb::new(
|
let l1 = LocationDb::new(
|
||||||
"Test",
|
"Test",
|
||||||
Position::new(0, 0, Dimension::Overworld),
|
Position::new(0, 0, 0, Dimension::Overworld),
|
||||||
0u64,
|
0u64,
|
||||||
None,
|
None,
|
||||||
LocationDataDb::Base,
|
LocationDataDb::Base,
|
||||||
);
|
);
|
||||||
let l2 = LocationDb::new(
|
let l2 = LocationDb::new(
|
||||||
"NotTest",
|
"NotTest",
|
||||||
Position::new(0, 0, Dimension::Overworld),
|
Position::new(0, 0, 0, Dimension::Overworld),
|
||||||
0u64,
|
0u64,
|
||||||
None,
|
None,
|
||||||
LocationDataDb::Base,
|
LocationDataDb::Base,
|
||||||
|
@ -221,14 +221,14 @@ mod tests {
|
||||||
|
|
||||||
let l1 = LocationDb::new(
|
let l1 = LocationDb::new(
|
||||||
"Test",
|
"Test",
|
||||||
Position::new(0, 0, Dimension::Overworld),
|
Position::new(0, 0, 0, Dimension::Overworld),
|
||||||
0u64,
|
0u64,
|
||||||
None,
|
None,
|
||||||
LocationDataDb::Base,
|
LocationDataDb::Base,
|
||||||
);
|
);
|
||||||
let l2 = LocationDb::new(
|
let l2 = LocationDb::new(
|
||||||
"teSt",
|
"teSt",
|
||||||
Position::new(0, 0, Dimension::Overworld),
|
Position::new(0, 0, 0,Dimension::Overworld),
|
||||||
0u64,
|
0u64,
|
||||||
None,
|
None,
|
||||||
LocationDataDb::Base,
|
LocationDataDb::Base,
|
||||||
|
|
|
@ -9,6 +9,7 @@ pub mod parameters;
|
||||||
pub mod player;
|
pub mod player;
|
||||||
pub mod response;
|
pub mod response;
|
||||||
pub mod token;
|
pub mod token;
|
||||||
|
pub mod db_metadata;
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug, Copy, Clone)]
|
#[derive(Serialize, Deserialize, Debug, Copy, Clone)]
|
||||||
pub enum Dimension {
|
pub enum Dimension {
|
||||||
|
@ -73,25 +74,54 @@ impl Display for Direction {
|
||||||
pub struct Position {
|
pub struct Position {
|
||||||
pub x: i32,
|
pub x: i32,
|
||||||
pub y: i32,
|
pub y: i32,
|
||||||
|
pub z: i32,
|
||||||
pub dimension: Dimension,
|
pub dimension: Dimension,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Position {
|
impl Position {
|
||||||
pub fn new(x: i32, y: i32, dimension: Dimension) -> Self {
|
pub fn new(x: i32, y: i32, z: i32, dimension: Dimension) -> Self {
|
||||||
Self { x, y, dimension }
|
Self { x, y, z, dimension }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for Position {
|
impl Display for Position {
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
write!(f, "{} @ (x={}, z={}) ", self.dimension, self.x, self.y)
|
write!(f, "(x={}, y={}, z={}) in {} ", self.x, self.y, self.z, self.dimension)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||||
pub struct Tunnel {
|
pub struct Portal {
|
||||||
direction: Direction,
|
x: i32,
|
||||||
number: i32,
|
z: i32
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Portal {
|
||||||
|
pub fn new(x: i32, z: i32) -> Self {
|
||||||
|
Self {
|
||||||
|
x,
|
||||||
|
z
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn direction(&self) -> Direction {
|
||||||
|
if self.x.abs() > self.z.abs() {
|
||||||
|
if self.x < 0 {
|
||||||
|
Direction::West
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Direction::East
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if self.z < 0 {
|
||||||
|
Direction::North
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Direction::South
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Ord, PartialOrd, Eq, Hash)]
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Ord, PartialOrd, Eq, Hash)]
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use crate::models::locations::LocationType;
|
use crate::models::locations::LocationType;
|
||||||
use crate::models::parameters::CommandRequest;
|
use crate::models::parameters::CommandRequest;
|
||||||
use crate::models::player::UserID;
|
use crate::models::player::UserID;
|
||||||
use crate::models::{Position, Tunnel};
|
use crate::models::{Position, Portal};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||||
|
@ -11,7 +11,7 @@ pub struct AddLocationParams {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub position: Position,
|
pub position: Position,
|
||||||
pub loc_type: LocationType,
|
pub loc_type: LocationType,
|
||||||
pub tunnel: Option<Tunnel>,
|
pub portal: Option<Portal>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AddLocationParams {
|
impl AddLocationParams {
|
||||||
|
@ -19,7 +19,7 @@ impl AddLocationParams {
|
||||||
name: String,
|
name: String,
|
||||||
position: Position,
|
position: Position,
|
||||||
loc_type: LocationType,
|
loc_type: LocationType,
|
||||||
tunnel: Option<Tunnel>,
|
portal: Option<Portal>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
token: Default::default(),
|
token: Default::default(),
|
||||||
|
@ -27,7 +27,7 @@ impl AddLocationParams {
|
||||||
name,
|
name,
|
||||||
position,
|
position,
|
||||||
loc_type,
|
loc_type,
|
||||||
tunnel,
|
portal,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
use crate::models::item::ItemListing;
|
use crate::models::item::ItemListing;
|
||||||
use crate::models::{Position, Tunnel};
|
use crate::models::{Position, Portal};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, Serialize, Clone)]
|
#[derive(Debug, Deserialize, Serialize, Clone)]
|
||||||
pub struct SellingListing {
|
pub struct SellingListing {
|
||||||
pub shop_name: String,
|
pub shop_name: String,
|
||||||
pub shop_loc: Position,
|
pub shop_loc: Position,
|
||||||
pub portal: Option<Tunnel>,
|
pub portal: Option<Portal>,
|
||||||
pub listing: ItemListing,
|
pub listing: ItemListing,
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue