2022-12-27 20:16:35 +11:00
|
|
|
use crate::DResult;
|
|
|
|
use crate::db::DBPool;
|
2023-01-07 23:06:02 +11:00
|
|
|
use crate::models::{item::Item, task::Task};
|
2022-12-27 20:16:35 +11:00
|
|
|
use std::collections::{BTreeSet, BTreeMap};
|
2022-12-27 23:35:27 +11:00
|
|
|
use log::info;
|
2022-12-27 20:16:35 +11:00
|
|
|
|
2022-12-29 00:37:14 +11:00
|
|
|
pub mod room;
|
2022-12-29 23:16:52 +11:00
|
|
|
pub mod npc;
|
2023-01-22 01:16:00 +11:00
|
|
|
pub mod possession_type;
|
2023-01-22 22:43:44 +11:00
|
|
|
pub mod species;
|
2023-01-01 00:09:25 +11:00
|
|
|
mod fixed_item;
|
2022-12-27 20:16:35 +11:00
|
|
|
|
|
|
|
pub struct StaticItem {
|
|
|
|
pub item_code: &'static str,
|
2022-12-27 23:35:27 +11:00
|
|
|
pub initial_item: Box<dyn Fn() -> Item>
|
2022-12-27 20:16:35 +11:00
|
|
|
}
|
|
|
|
|
2023-01-07 23:06:02 +11:00
|
|
|
pub struct StaticTask {
|
|
|
|
pub task_code: String,
|
|
|
|
pub initial_task: Box<dyn Fn() -> Task>
|
2022-12-27 20:16:35 +11:00
|
|
|
}
|
|
|
|
|
2023-01-07 23:06:02 +11:00
|
|
|
struct StaticThingTypeGroup<Thing> {
|
|
|
|
thing_type: &'static str,
|
|
|
|
things: fn () -> Box<dyn Iterator<Item = Thing>>
|
|
|
|
}
|
|
|
|
|
|
|
|
fn static_item_registry() -> Vec<StaticThingTypeGroup<StaticItem>> {
|
2022-12-27 20:16:35 +11:00
|
|
|
vec!(
|
|
|
|
// Must have no duplicates.
|
2023-01-07 23:06:02 +11:00
|
|
|
StaticThingTypeGroup::<StaticItem> {
|
|
|
|
thing_type: "npc",
|
|
|
|
things: || npc::npc_static_items()
|
2022-12-27 20:16:35 +11:00
|
|
|
},
|
2023-01-07 23:06:02 +11:00
|
|
|
StaticThingTypeGroup::<StaticItem> {
|
|
|
|
thing_type: "room",
|
|
|
|
things: || room::room_static_items()
|
2022-12-27 20:16:35 +11:00
|
|
|
},
|
2023-01-07 23:06:02 +11:00
|
|
|
StaticThingTypeGroup::<StaticItem> {
|
|
|
|
thing_type: "fixed_item",
|
|
|
|
things: || fixed_item::static_items()
|
|
|
|
},
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn static_task_registry() -> Vec<StaticThingTypeGroup<StaticTask>> {
|
|
|
|
vec!(
|
|
|
|
// Must have no duplicates.
|
|
|
|
StaticThingTypeGroup::<StaticTask> {
|
|
|
|
thing_type: "NPCSay",
|
|
|
|
things: || npc::npc_say_tasks()
|
2023-01-01 00:09:25 +11:00
|
|
|
},
|
2023-01-27 00:36:49 +11:00
|
|
|
StaticThingTypeGroup::<StaticTask> {
|
|
|
|
thing_type: "NPCWander",
|
|
|
|
things: || npc::npc_wander_tasks()
|
|
|
|
},
|
|
|
|
StaticThingTypeGroup::<StaticTask> {
|
|
|
|
thing_type: "NPCAggro",
|
|
|
|
things: || npc::npc_aggro_tasks()
|
|
|
|
},
|
2022-12-27 20:16:35 +11:00
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
async fn refresh_static_items(pool: &DBPool) -> DResult<()> {
|
2022-12-27 23:35:27 +11:00
|
|
|
let registry = static_item_registry();
|
2022-12-27 20:16:35 +11:00
|
|
|
|
|
|
|
let expected_type: BTreeSet<String> =
|
2023-01-07 23:06:02 +11:00
|
|
|
registry.iter().map(|x| x.thing_type.to_owned()).collect();
|
2022-12-27 20:16:35 +11:00
|
|
|
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() {
|
2023-01-07 23:06:02 +11:00
|
|
|
info!("Checking static_content of item_type {}", type_group.thing_type);
|
2022-12-27 20:16:35 +11:00
|
|
|
let tx = pool.start_transaction().await?;
|
2023-01-07 23:06:02 +11:00
|
|
|
let existing_items = tx.find_static_items_by_type(type_group.thing_type).await?;
|
2022-12-27 20:16:35 +11:00
|
|
|
let expected_items: BTreeMap<String, StaticItem> =
|
2023-01-07 23:06:02 +11:00
|
|
|
(type_group.things)().map(|x| (x.item_code.to_owned(), x)).collect();
|
2022-12-27 20:16:35 +11:00
|
|
|
let expected_set: BTreeSet<String> = expected_items.keys().map(|x|x.to_owned()).collect();
|
|
|
|
for unwanted_item in existing_items.difference(&expected_set) {
|
2023-01-02 15:39:55 +11:00
|
|
|
info!("Deleting item {:?}", unwanted_item);
|
2023-01-07 23:06:02 +11:00
|
|
|
tx.delete_static_items_by_code(type_group.thing_type, unwanted_item).await?;
|
2022-12-27 20:16:35 +11:00
|
|
|
}
|
|
|
|
for new_item_code in expected_set.difference(&existing_items) {
|
2023-01-02 15:39:55 +11:00
|
|
|
info!("Creating item {:?}", new_item_code);
|
2022-12-27 20:16:35 +11:00
|
|
|
tx.create_item(&(expected_items.get(new_item_code)
|
|
|
|
.unwrap().initial_item)()).await?;
|
|
|
|
}
|
2022-12-29 23:16:52 +11:00
|
|
|
for existing_item_code in expected_set.intersection(&existing_items) {
|
|
|
|
tx.limited_update_static_item(
|
|
|
|
&(expected_items.get(existing_item_code)
|
|
|
|
.unwrap().initial_item)()).await?;
|
|
|
|
}
|
2022-12-27 23:35:27 +11:00
|
|
|
tx.commit().await?;
|
2023-01-07 23:06:02 +11:00
|
|
|
info!("Committed any changes for static_content of item_type {}", type_group.thing_type);
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
async fn refresh_static_tasks(pool: &DBPool) -> DResult<()> {
|
|
|
|
let registry = static_task_registry();
|
|
|
|
|
|
|
|
let expected_type: BTreeSet<String> =
|
|
|
|
registry.iter().map(|x| x.thing_type.to_owned()).collect();
|
|
|
|
let cur_types: Box<BTreeSet<String>> = pool.find_static_task_types().await?;
|
|
|
|
for task_type in cur_types.difference(&expected_type) {
|
|
|
|
pool.delete_static_tasks_by_type(task_type).await?;
|
|
|
|
}
|
|
|
|
|
|
|
|
for type_group in registry.iter() {
|
|
|
|
info!("Checking static_content of task_type {}", type_group.thing_type);
|
|
|
|
let tx = pool.start_transaction().await?;
|
|
|
|
let existing_tasks = tx.find_static_tasks_by_type(type_group.thing_type).await?;
|
|
|
|
let expected_tasks: BTreeMap<String, StaticTask> =
|
|
|
|
(type_group.things)().map(|x| (x.task_code.to_owned(), x)).collect();
|
|
|
|
let expected_set: BTreeSet<String> = expected_tasks.keys().map(|x|x.to_owned()).collect();
|
|
|
|
for unwanted_task in existing_tasks.difference(&expected_set) {
|
|
|
|
info!("Deleting task {:?}", unwanted_task);
|
|
|
|
tx.delete_static_tasks_by_code(type_group.thing_type, unwanted_task).await?;
|
|
|
|
}
|
|
|
|
for new_task_code in expected_set.difference(&existing_tasks) {
|
|
|
|
info!("Creating task {:?}", new_task_code);
|
|
|
|
tx.upsert_task(&(expected_tasks.get(new_task_code)
|
|
|
|
.unwrap().initial_task)()).await?;
|
|
|
|
}
|
|
|
|
for existing_task_code in expected_set.intersection(&existing_tasks) {
|
|
|
|
tx.limited_update_static_task(
|
|
|
|
&(expected_tasks.get(existing_task_code)
|
|
|
|
.unwrap().initial_task)()).await?;
|
|
|
|
}
|
|
|
|
tx.commit().await?;
|
|
|
|
info!("Committed any changes for static_content of task_type {}", type_group.thing_type);
|
2022-12-27 20:16:35 +11:00
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
pub async fn refresh_static_content(pool: &DBPool) -> DResult<()> {
|
|
|
|
refresh_static_items(pool).await?;
|
2023-01-07 23:06:02 +11:00
|
|
|
refresh_static_tasks(pool).await?;
|
2022-12-27 20:16:35 +11:00
|
|
|
Ok(())
|
|
|
|
}
|
2022-12-27 23:35:27 +11:00
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod test {
|
2022-12-28 20:00:55 +11:00
|
|
|
use itertools::Itertools;
|
2022-12-27 23:35:27 +11:00
|
|
|
use super::*;
|
|
|
|
|
|
|
|
#[test]
|
2023-01-07 23:06:02 +11:00
|
|
|
fn no_duplicate_static_items() {
|
2023-01-04 23:05:06 +11:00
|
|
|
let mut registry = static_item_registry();
|
2023-01-07 23:06:02 +11:00
|
|
|
registry.sort_unstable_by(|x, y| x.thing_type.cmp(y.thing_type));
|
2022-12-27 23:35:27 +11:00
|
|
|
|
|
|
|
let duplicates: Vec<&'static str> =
|
|
|
|
registry.iter()
|
2023-01-07 23:06:02 +11:00
|
|
|
.group_by(|x| x.thing_type).into_iter()
|
2022-12-27 23:35:27 +11:00
|
|
|
.filter_map(|(k, v)| if v.count() <= 1 { None } else { Some(k) })
|
|
|
|
.collect();
|
|
|
|
if duplicates.len() > 0 {
|
|
|
|
panic!("static_item_registry has duplicate item_types: {:}", duplicates.join(", "));
|
|
|
|
}
|
|
|
|
|
|
|
|
for type_group in registry.iter() {
|
2023-01-07 23:06:02 +11:00
|
|
|
let iterator : Box<dyn Iterator<Item = StaticItem>> = (type_group.things)();
|
2022-12-27 23:35:27 +11:00
|
|
|
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 {
|
|
|
|
panic!("static_item_registry has duplicate item_codes for {}: {:}",
|
2023-01-07 23:06:02 +11:00
|
|
|
type_group.thing_type,
|
|
|
|
duplicates.join(", "));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn no_duplicate_static_tasks() {
|
|
|
|
let mut registry = static_task_registry();
|
|
|
|
registry.sort_unstable_by(|x, y| x.thing_type.cmp(y.thing_type));
|
|
|
|
|
|
|
|
let duplicates: Vec<&'static str> =
|
|
|
|
registry.iter()
|
|
|
|
.group_by(|x| x.thing_type).into_iter()
|
|
|
|
.filter_map(|(k, v)| if v.count() <= 1 { None } else { Some(k) })
|
|
|
|
.collect();
|
|
|
|
if duplicates.len() > 0 {
|
|
|
|
panic!("static_task_registry has duplicate task_types: {:}", duplicates.join(", "));
|
|
|
|
}
|
|
|
|
|
|
|
|
for type_group in registry.iter() {
|
|
|
|
let iterator : Box<dyn Iterator<Item = StaticTask>> = (type_group.things)();
|
2023-01-08 00:18:56 +11:00
|
|
|
let duplicates: Vec<String> = iterator
|
|
|
|
.group_by(|x| x.task_code.clone())
|
2023-01-07 23:06:02 +11:00
|
|
|
.into_iter()
|
|
|
|
.filter_map(|(k, v)| if v.count() <= 1 { None } else { Some(k) })
|
|
|
|
.collect();
|
|
|
|
if duplicates.len() > 0 {
|
|
|
|
panic!("static_task_registry has duplicate task_codes for {}: {:}",
|
|
|
|
type_group.thing_type,
|
2022-12-27 23:35:27 +11:00
|
|
|
duplicates.join(", "));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|