Start to implement a static item (rooms etc...) system.
This commit is contained in:
parent
672eb1ee75
commit
c4f9577645
16
Cargo.lock
generated
16
Cargo.lock
generated
@ -112,6 +112,7 @@ dependencies = [
|
||||
"deadpool",
|
||||
"deadpool-postgres",
|
||||
"futures",
|
||||
"itertools",
|
||||
"log",
|
||||
"nix",
|
||||
"nom",
|
||||
@ -392,6 +393,12 @@ dependencies = [
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "either"
|
||||
version = "1.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797"
|
||||
|
||||
[[package]]
|
||||
name = "enum-ordinalize"
|
||||
version = "3.1.12"
|
||||
@ -751,6 +758,15 @@ dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.10.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473"
|
||||
dependencies = [
|
||||
"either",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.4"
|
||||
|
@ -32,3 +32,4 @@ ouroboros = "0.15.5"
|
||||
chrono = { version = "0.4.23", features = ["serde"] }
|
||||
bcrypt = "0.13.0"
|
||||
validator = "0.16.0"
|
||||
itertools = "0.10.5"
|
||||
|
@ -10,6 +10,7 @@ use crate::message_handler::ListenerSession;
|
||||
use crate::DResult;
|
||||
use crate::models::{session::Session, user::User, item::Item};
|
||||
use tokio_postgres::types::ToSql;
|
||||
use std::collections::BTreeSet;
|
||||
|
||||
use serde_json;
|
||||
use futures::FutureExt;
|
||||
@ -132,6 +133,24 @@ impl DBPool {
|
||||
conn.execute("DELETE FROM sendqueue WHERE item=$1", &[&item.item]).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn find_static_item_types(self: &Self) -> DResult<Box<BTreeSet<String>>> {
|
||||
Ok(Box::new(
|
||||
self
|
||||
.get_conn().await?
|
||||
.query("SELECT DISTINCT details->>'item_type' AS item_type \
|
||||
FROM items WHERE details->>'is_static' = 'true'", &[]).await?
|
||||
.iter()
|
||||
.map(|r| r.get("item_type"))
|
||||
.collect()))
|
||||
}
|
||||
|
||||
pub async fn delete_static_items_by_type(self: &Self, item_type: &str) -> DResult<()> {
|
||||
self.get_conn().await?.query(
|
||||
"DELETE FROM items WHERE details->>'is_static' = 'true' AND details->>'item_type' = {}",
|
||||
&[&item_type]).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn get_conn(self: &DBPool) ->
|
||||
DResult<Object> {
|
||||
@ -243,6 +262,29 @@ impl DBTrans {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn find_static_items_by_type(self: &Self, item_type: &str) ->
|
||||
DResult<Box<BTreeSet<String>>> {
|
||||
Ok(Box::new(
|
||||
self.pg_trans()?
|
||||
.query("SELECT DISTINCT details->>'item_code' AS item_code FROM items WHERE \
|
||||
details->>'is_static' = 'true' AND \
|
||||
details->>'item_type' = $1", &[&item_type])
|
||||
.await?
|
||||
.into_iter()
|
||||
.map(|v| v.get("item_code"))
|
||||
.collect()))
|
||||
}
|
||||
|
||||
pub async fn delete_static_items_by_code(self: &Self, item_type: &str,
|
||||
item_code: &str) -> DResult<()> {
|
||||
self.pg_trans()?.query(
|
||||
"DELETE FROM items WHERE details->>'is_static' = 'true' AND \
|
||||
details->>'item_type' = {} AND \
|
||||
details->>'item_code' = {}",
|
||||
&[&item_type, &item_code]).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn commit(mut self: Self) -> DResult<()> {
|
||||
let trans_opt = self.with_trans_mut(|t| std::mem::replace(t, None));
|
||||
if let Some(trans) = trans_opt {
|
||||
|
@ -13,6 +13,7 @@ mod version_cutover;
|
||||
mod av;
|
||||
mod regular_tasks;
|
||||
mod models;
|
||||
mod static_content;
|
||||
|
||||
pub type DResult<T> = Result<T, Box<dyn Error + Send + Sync>>;
|
||||
|
||||
@ -53,6 +54,8 @@ async fn main() -> DResult<()> {
|
||||
}
|
||||
).await?;
|
||||
|
||||
static_content::refresh_static_content(&pool).await?;
|
||||
|
||||
version_cutover::replace_old_gameserver(&config.pidfile)?;
|
||||
regular_tasks::start_regular_tasks(&pool, listener_map)?;
|
||||
|
||||
|
87
blastmud_game/src/static_content.rs
Normal file
87
blastmud_game/src/static_content.rs
Normal file
@ -0,0 +1,87 @@
|
||||
use crate::DResult;
|
||||
use crate::db::DBPool;
|
||||
use crate::models::item::Item;
|
||||
use log::error;
|
||||
use itertools::Itertools;
|
||||
use std::collections::{BTreeSet, BTreeMap};
|
||||
|
||||
mod room;
|
||||
|
||||
pub struct StaticItem {
|
||||
pub item_code: &'static str,
|
||||
pub initial_item: fn () -> Item
|
||||
}
|
||||
|
||||
struct StaticItemTypeGroup {
|
||||
item_type: &'static str,
|
||||
items: fn () -> Box<dyn Iterator<Item = StaticItem>>
|
||||
}
|
||||
|
||||
fn static_item_registry() -> Vec<StaticItemTypeGroup> {
|
||||
vec!(
|
||||
// Must have no duplicates.
|
||||
StaticItemTypeGroup {
|
||||
item_type: "npc",
|
||||
items: || Box::new(vec!().into_iter())
|
||||
},
|
||||
StaticItemTypeGroup {
|
||||
item_type: "room",
|
||||
items: || room::static_items()
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
async fn refresh_static_items(pool: &DBPool) -> DResult<()> {
|
||||
let mut registry = static_item_registry();
|
||||
registry.sort_unstable_by(|x, y| x.item_type.cmp(y.item_type));
|
||||
|
||||
let duplicates: Vec<&'static str> =
|
||||
registry.iter()
|
||||
.group_by(|x| x.item_type).into_iter()
|
||||
.filter_map(|(k, v)| if v.count() <= 1 { None } else { Some(k) })
|
||||
.collect();
|
||||
if duplicates.len() > 0 {
|
||||
error!("static_item_registry has duplicate item_types: {:}", duplicates.join(", "));
|
||||
Err("Duplicate item_types in static_item_registry")?;
|
||||
}
|
||||
let expected_type: BTreeSet<String> =
|
||||
registry.iter().map(|x| x.item_type.to_owned()).collect();
|
||||
let cur_types: Box<BTreeSet<String>> = pool.find_static_item_types().await?;
|
||||
for item_type in cur_types.difference(&expected_type) {
|
||||
pool.delete_static_items_by_type(item_type).await?;
|
||||
}
|
||||
|
||||
for type_group in registry.iter() {
|
||||
let iterator : Box<dyn Iterator<Item = StaticItem>> = (type_group.items)();
|
||||
let duplicates: Vec<&'static str> = iterator
|
||||
.group_by(|x| x.item_code)
|
||||
.into_iter()
|
||||
.filter_map(|(k, v)| if v.count() <= 1 { None } else { Some(k) })
|
||||
.collect();
|
||||
if duplicates.len() > 0 {
|
||||
error!("static_item_registry has duplicate item_codes for {}: {:}",
|
||||
type_group.item_type,
|
||||
duplicates.join(", "));
|
||||
Err("Duplicate item_types in static_item_registry")?;
|
||||
}
|
||||
let tx = pool.start_transaction().await?;
|
||||
let existing_items = tx.find_static_items_by_type(type_group.item_type).await?;
|
||||
let expected_items: BTreeMap<String, StaticItem> =
|
||||
(type_group.items)().map(|x| (x.item_code.to_owned(), x)).collect();
|
||||
let expected_set: BTreeSet<String> = expected_items.keys().map(|x|x.to_owned()).collect();
|
||||
for unwanted_item in existing_items.difference(&expected_set) {
|
||||
tx.delete_static_items_by_code(type_group.item_type, unwanted_item).await?;
|
||||
}
|
||||
for new_item_code in expected_set.difference(&existing_items) {
|
||||
tx.create_item(&(expected_items.get(new_item_code)
|
||||
.unwrap().initial_item)()).await?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn refresh_static_content(pool: &DBPool) -> DResult<()> {
|
||||
refresh_static_items(pool).await?;
|
||||
Ok(())
|
||||
}
|
5
blastmud_game/src/static_content/room.rs
Normal file
5
blastmud_game/src/static_content/room.rs
Normal file
@ -0,0 +1,5 @@
|
||||
use super::StaticItem;
|
||||
|
||||
pub fn static_items() -> Box<dyn Iterator<Item = StaticItem>> {
|
||||
Box::new(vec!().into_iter())
|
||||
}
|
@ -21,7 +21,7 @@ CREATE TABLE items (
|
||||
item_id BIGSERIAL NOT NULL PRIMARY KEY,
|
||||
details JSONB NOT NULL
|
||||
);
|
||||
CREATE UNIQUE INDEX item_index ON items ((details->>'item_code'), (details->>'item_type'));
|
||||
CREATE UNIQUE INDEX item_index ON items ((details->>'item_type'), (details->>'item_code'));
|
||||
CREATE INDEX item_by_loc ON items ((details->>'location'));
|
||||
CREATE INDEX item_by_static ON items ((cast(details->>'is_static' as boolean)));
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user