From 5c230f266748ce7f1e22cbd8dbaf279715e4c933 Mon Sep 17 00:00:00 2001 From: Condorra Date: Tue, 5 Mar 2024 22:37:33 +1100 Subject: [PATCH] Ship idle users to the homeless shelter after a couple of hours --- blastmud_game/src/db.rs | 33 +- blastmud_game/src/models/task.rs | 2 + blastmud_game/src/regular_tasks.rs | 3 +- blastmud_game/src/services.rs | 1 + blastmud_game/src/services/idlepark.rs | 68 ++ blastmud_game/src/static_content.rs | 6 +- blastmud_game/src/static_content/room.rs | 7 + .../src/static_content/room/melbs.yaml | 9 + .../static_content/room/northern_radfields.rs | 10 + .../room/northern_radfields.yaml | 20 + docs/NorthernRadfields.svg | 753 ++++++++++++++++++ schema/schema.sql | 3 +- 12 files changed, 909 insertions(+), 6 deletions(-) create mode 100644 blastmud_game/src/services/idlepark.rs create mode 100644 blastmud_game/src/static_content/room/northern_radfields.rs create mode 100644 blastmud_game/src/static_content/room/northern_radfields.yaml create mode 100644 docs/NorthernRadfields.svg diff --git a/blastmud_game/src/db.rs b/blastmud_game/src/db.rs index fc132d38..b23765b2 100644 --- a/blastmud_game/src/db.rs +++ b/blastmud_game/src/db.rs @@ -114,7 +114,7 @@ impl DBPool { let mut conn = self.get_conn().await?; let tx = conn.transaction().await?; tx.execute( - "UPDATE users SET current_session = NULL, \ + "UPDATE users SET current_session = NULL, idle_park_time = NOW() + INTERVAL '2 hours', \ current_listener = NULL WHERE current_listener = $1", &[&listener], ) @@ -153,7 +153,7 @@ impl DBPool { let mut conn = self.get_conn().await?; let tx = conn.transaction().await?; tx.execute( - "UPDATE users SET current_session = NULL, \ + "UPDATE users SET current_session = NULL, idle_park_time = NOW() + INTERVAL '2 hours', \ current_listener = NULL WHERE current_session = $1", &[&session.session], ) @@ -600,7 +600,10 @@ impl DBTrans { .await?; self.pg_trans()? .execute( - "UPDATE users SET current_session = $1, current_listener = $2 WHERE username = $3", + "UPDATE users SET current_session = $1, \ + current_listener = $2, \ + idle_park_time = NULL \ + WHERE username = $3", &[ &session.session as &(dyn ToSql + Sync), &session.listener, @@ -2004,6 +2007,30 @@ impl DBTrans { .get("found")) } + pub async fn find_users_to_idlepark(&self) -> DResult> { + Ok(self + .pg_trans()? + .query( + "SELECT details FROM users WHERE idle_park_time < NOW() \ + LIMIT 100", + &[], + ) + .await? + .into_iter() + .filter_map(|r| serde_json::from_value(r.get("details")).ok()) + .collect()) + } + + pub async fn mark_idleparked(&self, username: &str) -> DResult<()> { + self.pg_trans()? + .execute( + "UPDATE users SET idle_park_time = NULL WHERE username = $1", + &[&&username.to_lowercase()], + ) + .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 { diff --git a/blastmud_game/src/models/task.rs b/blastmud_game/src/models/task.rs index c503d1f0..73a1a2e3 100644 --- a/blastmud_game/src/models/task.rs +++ b/blastmud_game/src/models/task.rs @@ -61,6 +61,7 @@ pub enum TaskDetails { }, TickUrges, ResetSpawns, + IdlePark, ResetHanoi, HospitalERSeePatient { item: String, @@ -103,6 +104,7 @@ impl TaskDetails { TickUrges => "TickUrges", ResetSpawns => "ResetSpawns", ResetHanoi => "ResetHanoi", + IdlePark => "IdlePark", HospitalERSeePatient { .. } => "HospitalERSeePatient", ExpireBuff { .. } => "ExpireBuff", DischargeLight { .. } => "DischargeLight", diff --git a/blastmud_game/src/regular_tasks.rs b/blastmud_game/src/regular_tasks.rs index f4f34b8e..83938833 100644 --- a/blastmud_game/src/regular_tasks.rs +++ b/blastmud_game/src/regular_tasks.rs @@ -9,7 +9,7 @@ use crate::{ listener::{ListenerMap, ListenerSend}, message_handler::user_commands::{delete, drop, hire, open, rent}, models::task::Task, - services::{charging, combat, effect, sharing, spawn, tempbuff, urges}, + services::{charging, combat, effect, idlepark, sharing, spawn, tempbuff, urges}, static_content::{ npc::{self, computer_museum_npcs}, possession_type::lights, @@ -67,6 +67,7 @@ fn task_handler_registry( ("TickUrges", urges::TICK_URGES_HANDLER), ("ResetSpawns", spawn::RESET_SPAWNS_HANDLER), ("ResetHanoi", computer_museum_npcs::RESET_GAME_HANDLER), + ("IdlePark", idlepark::IDLEPARK_HANDLER), ("HospitalERSeePatient", general_hospital::SEE_PATIENT_TASK), ("ExpireBuff", tempbuff::EXPIRE_BUFF_TASK), ("DischargeLight", lights::DISCHARGE_TASK), diff --git a/blastmud_game/src/services.rs b/blastmud_game/src/services.rs index 9ff18a05..41836d93 100644 --- a/blastmud_game/src/services.rs +++ b/blastmud_game/src/services.rs @@ -22,6 +22,7 @@ pub mod combat; pub mod comms; pub mod display; pub mod effect; +pub mod idlepark; pub mod room_effects; pub mod sharing; pub mod skills; diff --git a/blastmud_game/src/services/idlepark.rs b/blastmud_game/src/services/idlepark.rs new file mode 100644 index 00000000..9f70ca49 --- /dev/null +++ b/blastmud_game/src/services/idlepark.rs @@ -0,0 +1,68 @@ +use async_trait::async_trait; +use chrono::Utc; +use log::info; + +use crate::{ + models::{ + item::ItemFlag, + task::{Task, TaskDetails, TaskMeta, TaskRecurrence}, + }, + regular_tasks::{TaskHandler, TaskRunContext}, + static_content::StaticTask, + DResult, +}; +use std::time; + +use super::comms::broadcast_to_room; + +pub struct IdleparkTaskHandler; +#[async_trait] +impl TaskHandler for IdleparkTaskHandler { + async fn do_task(&self, ctx: &mut TaskRunContext) -> DResult> { + for user in ctx.trans.find_users_to_idlepark().await? { + if let Some(player_item) = ctx + .trans + .find_item_by_type_code("player", &user.username.to_lowercase()) + .await? + { + if let Some((loc_type, loc_code)) = player_item.location.split_once("/") { + if let Some(loc) = ctx.trans.find_item_by_type_code(loc_type, loc_code).await? { + if !loc.flags.contains(&ItemFlag::PrivatePlace) { + let mut player_item = (*player_item).clone(); + info!("Broadcasting to {}.\n", &player_item.location); + broadcast_to_room(&ctx.trans, &player_item.location, None, + &format!( + "A sweeping robot whirs as it passes by, sweeping up the slumbering {} and carrying {} off to the homeless shelter.\n", + &player_item.display_for_sentence(1, false), + &player_item.pronouns.object)).await?; + player_item.location = "room/melbs_homelessshelter".to_owned(); + ctx.trans.save_item_model(&player_item).await?; + } + } + } + } + ctx.trans.mark_idleparked(&user.username).await?; + } + Ok(Some(time::Duration::from_secs(120))) + } +} +pub static IDLEPARK_HANDLER: &'static (dyn TaskHandler + Sync + Send) = &IdleparkTaskHandler; + +pub fn idlepark_tasks() -> Box> { + Box::new( + vec![StaticTask { + task_code: "IdlePark".to_owned(), + initial_task: Box::new(|| Task { + meta: TaskMeta { + task_code: "IdlePark".to_owned(), + is_static: true, + recurrence: Some(TaskRecurrence::FixedDuration { seconds: 120 }), + next_scheduled: Utc::now() + chrono::Duration::seconds(120), + ..Default::default() + }, + details: TaskDetails::IdlePark, + }), + }] + .into_iter(), + ) +} diff --git a/blastmud_game/src/static_content.rs b/blastmud_game/src/static_content.rs index 2a9951a8..d4ac8aba 100644 --- a/blastmud_game/src/static_content.rs +++ b/blastmud_game/src/static_content.rs @@ -1,7 +1,7 @@ use crate::{ db::DBPool, models::{item::Item, task::Task}, - services::{spawn, urges}, + services::{idlepark, spawn, urges}, DResult, }; use log::info; @@ -76,6 +76,10 @@ fn static_task_registry() -> Vec> { thing_type: "ResetSpawns", things: || spawn::reset_tasks(), }, + StaticThingTypeGroup:: { + thing_type: "IdleparkCharacters", + things: || idlepark::idlepark_tasks(), + }, ] } diff --git a/blastmud_game/src/static_content/room.rs b/blastmud_game/src/static_content/room.rs index 9147f97a..7715d558 100644 --- a/blastmud_game/src/static_content/room.rs +++ b/blastmud_game/src/static_content/room.rs @@ -29,6 +29,7 @@ pub mod computer_museum; pub mod general_hospital; pub mod melbs; pub mod melbs_sewers; +pub mod northern_radfields; mod repro_xv; mod special; @@ -87,6 +88,11 @@ pub fn zone_details() -> &'static BTreeMap<&'static str, Zone> { display: "King's Office", outdoors: false, }, + Zone { + code: "northern_radfields", + display: "Northern Radfields", + outdoors: false, + }, ] .into_iter() .map(|x| (x.code, x)) @@ -677,6 +683,7 @@ pub fn room_list() -> &'static Vec { rooms.append(&mut computer_museum::room_list()); rooms.append(&mut general_hospital::room_list()); rooms.append(&mut melbs_sewers::room_list()); + rooms.append(&mut northern_radfields::room_list()); rooms.into_iter().collect() }) } diff --git a/blastmud_game/src/static_content/room/melbs.yaml b/blastmud_game/src/static_content/room/melbs.yaml index 01398426..3bc6537c 100644 --- a/blastmud_game/src/static_content/room/melbs.yaml +++ b/blastmud_game/src/static_content/room/melbs.yaml @@ -983,12 +983,21 @@ code: melbs_latrobest_140 name: La Trobe St - 140 block short: == + secondary_zones: + - zone: northern_radfields + short: ME + grid_coords: + x: 6 + y: 21 + z: 0 grid_coords: x: 11 y: -5 z: 0 description: A moderately wide road that is now overgrown and completely covered in weeds exits: + - direction: north + target: !Custom room/northrad_t6 - direction: west - direction: east should_caption: false diff --git a/blastmud_game/src/static_content/room/northern_radfields.rs b/blastmud_game/src/static_content/room/northern_radfields.rs new file mode 100644 index 00000000..0ee5470a --- /dev/null +++ b/blastmud_game/src/static_content/room/northern_radfields.rs @@ -0,0 +1,10 @@ +use super::{Room, SimpleRoom}; +use serde_yaml::from_str as from_yaml_str; + +pub fn room_list() -> Vec { + from_yaml_str::>>(include_str!("northern_radfields.yaml")) + .unwrap() + .into_iter() + .map(|r| r.into()) + .collect() +} diff --git a/blastmud_game/src/static_content/room/northern_radfields.yaml b/blastmud_game/src/static_content/room/northern_radfields.yaml new file mode 100644 index 00000000..da3ec1c2 --- /dev/null +++ b/blastmud_game/src/static_content/room/northern_radfields.yaml @@ -0,0 +1,20 @@ +- zone: northern_radfields + secondary_zones: + - zone: melbs + short: NR + grid_coords: + x: 11 + y: -6 + z: 0 + caption: Exit to Northern Radfields + code: northrad_t6 + name: Northern Radfield Road Gatehouse + short: || + grid_coords: + x: 6 + y: 20 + z: 0 + description: "The start of a deteriorating asphalt road that leads north through a barren dusty environment. The road is blocked by a barrier arm. The arm is attached to a box with a window in it, occupied by a guard in a fluorescent yellow high-visibility vest. The side of the box is painted with a symbol featuring three black wedges arranged circularly around a central black circle, on a yellow background. Beneath it is the text: DANGER - FALLOUT - Ionising Radiation Hazard. Access to the radfields by permit only" + exits: + - direction: south + target: !Custom room/melbs_latrobest_140 diff --git a/docs/NorthernRadfields.svg b/docs/NorthernRadfields.svg new file mode 100644 index 00000000..aff3fde3 --- /dev/null +++ b/docs/NorthernRadfields.svg @@ -0,0 +1,753 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Ronald's house + + Desert + + Oasis + + Road + (19)S + (01)A + (02)B + (03)C + (04)D + (05)E + (06)F + (07)G + (08)H + (09)I + (10)J + (11)K + (12)L + (13)M + (14)N + (15)O + (16)P + (17)Q + (18)R + (20)T + 9 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 10 + + diff --git a/schema/schema.sql b/schema/schema.sql index a59648c5..c9e9eaf6 100644 --- a/schema/schema.sql +++ b/schema/schema.sql @@ -39,7 +39,8 @@ CREATE TABLE users ( username TEXT NOT NULL PRIMARY KEY, current_session UUID REFERENCES sessions(session), current_listener UUID REFERENCES listeners(listener), - details JSONB NOT NULL + details JSONB NOT NULL, + idle_park_time TIMESTAMPTZ ); CREATE INDEX user_by_listener ON users(current_listener); CREATE INDEX user_by_session ON users(current_session);