Ship idle users to the homeless shelter after a couple of hours

This commit is contained in:
Condorra 2024-03-05 22:37:33 +11:00
parent 19cef2d9c4
commit 5c230f2667
12 changed files with 909 additions and 6 deletions

View File

@ -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<Vec<User>> {
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 {

View File

@ -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",

View File

@ -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),

View File

@ -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;

View File

@ -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<Option<time::Duration>> {
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<dyn Iterator<Item = StaticTask>> {
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(),
)
}

View File

@ -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<StaticThingTypeGroup<StaticTask>> {
thing_type: "ResetSpawns",
things: || spawn::reset_tasks(),
},
StaticThingTypeGroup::<StaticTask> {
thing_type: "IdleparkCharacters",
things: || idlepark::idlepark_tasks(),
},
]
}

View File

@ -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<Room> {
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()
})
}

View File

@ -983,12 +983,21 @@
code: melbs_latrobest_140
name: La Trobe St - 140 block
short: <yellow>==<reset>
secondary_zones:
- zone: northern_radfields
short: <yellow>ME<reset>
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

View File

@ -0,0 +1,10 @@
use super::{Room, SimpleRoom};
use serde_yaml::from_str as from_yaml_str;
pub fn room_list() -> Vec<Room> {
from_yaml_str::<Vec<SimpleRoom<()>>>(include_str!("northern_radfields.yaml"))
.unwrap()
.into_iter()
.map(|r| r.into())
.collect()
}

View File

@ -0,0 +1,20 @@
- zone: northern_radfields
secondary_zones:
- zone: melbs
short: <yellow>NR<reset>
grid_coords:
x: 11
y: -6
z: 0
caption: Exit to Northern Radfields
code: northrad_t6
name: Northern Radfield Road Gatehouse
short: <yellow><lt>||<reset>
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: <red>DANGER - FALLOUT - Ionising Radiation Hazard. Access to the radfields by permit only<reset>"
exits:
- direction: south
target: !Custom room/melbs_latrobest_140

753
docs/NorthernRadfields.svg Normal file
View File

@ -0,0 +1,753 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="210mm"
height="297mm"
viewBox="0 0 210 297"
version="1.1"
id="svg5"
sodipodi:docname="NorthernRadfields.svg"
inkscape:version="1.2.2 (b0a8486541, 2022-12-01)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview7"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:document-units="mm"
showgrid="false"
inkscape:zoom="1.6819304"
inkscape:cx="370.40771"
inkscape:cy="373.08321"
inkscape:window-width="1073"
inkscape:window-height="1033"
inkscape:window-x="589"
inkscape:window-y="18"
inkscape:window-maximized="1"
inkscape:current-layer="layer1" />
<defs
id="defs2" />
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1">
<rect
style="opacity:0.996;fill:#ffff00;fill-opacity:1;stroke:none;stroke-width:2.065;stroke-opacity:1"
id="rect337"
width="23.933922"
height="28.862682"
x="88.883881"
y="76.762024" />
<g
inkscape:label="GridCartesian:X10:Y10"
transform="translate(78.3129, 101.201)"
id="g1892">
<g
inkscape:label="MajorXGridlines"
id="g1868">
<path
style="fill:none;stroke:#000000;stroke-width:0.5027083333333333"
d="M 5 0 L 5 50"
inkscape:label="MajorXDiv1"
id="path1850" />
<path
style="fill:none;stroke:#000000;stroke-width:0.5027083333333333"
d="M 10 0 L 10 50"
inkscape:label="MajorXDiv2"
id="path1852" />
<path
style="fill:none;stroke:#000000;stroke-width:0.5027083333333333"
d="M 15 0 L 15 50"
inkscape:label="MajorXDiv3"
id="path1854" />
<path
style="fill:none;stroke:#000000;stroke-width:0.5027083333333333"
d="M 20 0 L 20 50"
inkscape:label="MajorXDiv4"
id="path1856" />
<path
style="fill:none;stroke:#000000;stroke-width:0.5027083333333333"
d="M 25 0 L 25 50"
inkscape:label="MajorXDiv5"
id="path1858" />
<path
style="fill:none;stroke:#000000;stroke-width:0.5027083333333333"
d="M 30 0 L 30 50"
inkscape:label="MajorXDiv6"
id="path1860" />
<path
style="fill:none;stroke:#000000;stroke-width:0.5027083333333333"
d="M 35 0 L 35 50"
inkscape:label="MajorXDiv7"
id="path1862" />
<path
style="fill:none;stroke:#000000;stroke-width:0.5027083333333333"
d="M 40 0 L 40 50"
inkscape:label="MajorXDiv8"
id="path1864" />
<path
style="fill:none;stroke:#000000;stroke-width:0.5027083333333333"
d="M 45 0 L 45 50"
inkscape:label="MajorXDiv9"
id="path1866" />
</g>
<g
inkscape:label="MajorYGridlines"
id="g1888">
<path
style="fill:none;stroke:#000000;stroke-width:0.5027083333333333"
d="M 0 5 L 50 5"
inkscape:label="MajorYDiv1"
id="path1870" />
<path
style="fill:none;stroke:#000000;stroke-width:0.5027083333333333"
d="M 0 10 L 50 10"
inkscape:label="MajorYDiv2"
id="path1872" />
<path
style="fill:none;stroke:#000000;stroke-width:0.5027083333333333"
d="M 0 15 L 50 15"
inkscape:label="MajorYDiv3"
id="path1874" />
<path
style="fill:none;stroke:#000000;stroke-width:0.5027083333333333"
d="M 0 20 L 50 20"
inkscape:label="MajorYDiv4"
id="path1876" />
<path
style="fill:none;stroke:#000000;stroke-width:0.5027083333333333"
d="M 0 25 L 50 25"
inkscape:label="MajorYDiv5"
id="path1878" />
<path
style="fill:none;stroke:#000000;stroke-width:0.5027083333333333"
d="M 0 30 L 50 30"
inkscape:label="MajorYDiv6"
id="path1880" />
<path
style="fill:none;stroke:#000000;stroke-width:0.5027083333333333"
d="M 0 35 L 50 35"
inkscape:label="MajorYDiv7"
id="path1882" />
<path
style="fill:none;stroke:#000000;stroke-width:0.5027083333333333"
d="M 0 40 L 50 40"
inkscape:label="MajorYDiv8"
id="path1884" />
<path
style="fill:none;stroke:#000000;stroke-width:0.5027083333333333"
d="M 0 45 L 50 45"
inkscape:label="MajorYDiv9"
id="path1886" />
</g>
<rect
x="0"
y="0"
width="50.0"
height="50.0"
style="fill:none;stroke:#000000;stroke-width:0.26458333333333334"
inkscape:label="Border"
id="rect1890" />
</g>
<rect
style="opacity:0.996;fill:#999999;fill-opacity:1;stroke:none;stroke-width:2.065;stroke-opacity:1"
id="rect2026"
width="4.9159884"
height="9.9846125"
x="103.44835"
y="141.35667" />
<g
inkscape:label="GridCartesian:X10:Y10"
transform="translate(78.374383,51.360644)"
id="g7926">
<g
inkscape:label="MajorXGridlines"
id="g7902">
<path
style="fill:none;stroke:#000000;stroke-width:0.502708"
d="M 5,0 V 50"
inkscape:label="MajorXDiv1"
id="path7884" />
<path
style="fill:none;stroke:#000000;stroke-width:0.502708"
d="M 10,0 V 50"
inkscape:label="MajorXDiv2"
id="path7886" />
<path
style="fill:none;stroke:#000000;stroke-width:0.502708"
d="M 15,0 V 50"
inkscape:label="MajorXDiv3"
id="path7888" />
<path
style="fill:none;stroke:#000000;stroke-width:0.502708"
d="M 20,0 V 50"
inkscape:label="MajorXDiv4"
id="path7890" />
<path
style="fill:none;stroke:#000000;stroke-width:0.502708"
d="M 25,0 V 50"
inkscape:label="MajorXDiv5"
id="path7892" />
<path
style="fill:none;stroke:#000000;stroke-width:0.502708"
d="M 30,0 V 50"
inkscape:label="MajorXDiv6"
id="path7894" />
<path
style="fill:none;stroke:#000000;stroke-width:0.502708"
d="M 35,0 V 50"
inkscape:label="MajorXDiv7"
id="path7896" />
<path
style="fill:none;stroke:#000000;stroke-width:0.502708"
d="M 40,0 V 50"
inkscape:label="MajorXDiv8"
id="path7898" />
<path
style="fill:none;stroke:#000000;stroke-width:0.502708"
d="M 45,0 V 50"
inkscape:label="MajorXDiv9"
id="path7900" />
</g>
<g
inkscape:label="MajorYGridlines"
id="g7922">
<path
style="fill:none;stroke:#000000;stroke-width:0.502708"
d="M 0,5 H 50"
inkscape:label="MajorYDiv1"
id="path7904" />
<path
style="fill:none;stroke:#000000;stroke-width:0.502708"
d="M 0,10 H 50"
inkscape:label="MajorYDiv2"
id="path7906" />
<path
style="fill:none;stroke:#000000;stroke-width:0.502708"
d="M 0,15 H 50"
inkscape:label="MajorYDiv3"
id="path7908" />
<path
style="fill:none;stroke:#000000;stroke-width:0.502708"
d="M 0,20 H 50"
inkscape:label="MajorYDiv4"
id="path7910" />
<path
style="fill:none;stroke:#000000;stroke-width:0.502708"
d="M 0,25 H 50"
inkscape:label="MajorYDiv5"
id="path7912" />
<path
style="fill:none;stroke:#000000;stroke-width:0.502708"
d="M 0,30 H 50"
inkscape:label="MajorYDiv6"
id="path7914" />
<path
style="fill:none;stroke:#000000;stroke-width:0.502708"
d="M 0,35 H 50"
inkscape:label="MajorYDiv7"
id="path7916" />
<path
style="fill:none;stroke:#000000;stroke-width:0.502708"
d="M 0,40 H 50"
inkscape:label="MajorYDiv8"
id="path7918" />
<path
style="fill:none;stroke:#000000;stroke-width:0.502708"
d="M 0,45 H 50"
inkscape:label="MajorYDiv9"
id="path7920" />
</g>
<rect
x="0"
y="0"
width="50"
height="50"
style="fill:none;stroke:#000000;stroke-width:0.264583"
inkscape:label="Border"
id="rect7924" />
</g>
<rect
style="opacity:0.996;fill:#999999;fill-opacity:1;stroke:none;stroke-width:2.065;stroke-opacity:1"
id="rect7928"
width="4.9159884"
height="9.9846125"
x="103.36028"
y="131.1398" />
<rect
style="opacity:0.996;fill:#999999;fill-opacity:1;stroke:none;stroke-width:2.065;stroke-opacity:1"
id="rect7930"
width="4.9159884"
height="9.9846125"
x="98.336182"
y="121.11232" />
<rect
style="opacity:0.996;fill:#4220bd;fill-opacity:1;stroke:none;stroke-width:2.065;stroke-opacity:1"
id="rect7932"
width="4.9159884"
height="5.0030127"
x="98.232796"
y="116.12067" />
<rect
style="opacity:0.996;fill:#999999;fill-opacity:1;stroke:none;stroke-width:2.065;stroke-opacity:1"
id="rect335"
width="4.9159884"
height="9.9846125"
x="98.173988"
y="106.11881" />
<rect
style="opacity:0.996;fill:#008000;fill-opacity:1;stroke:none;stroke-width:2.065;stroke-opacity:1"
id="rect339"
width="4.9159884"
height="5.0030127"
x="98.578827"
y="91.50824" />
<rect
style="opacity:0.996;fill:#800000;fill-opacity:1;stroke:none;stroke-width:2.065;stroke-opacity:1"
id="rect341"
width="4.9159884"
height="5.0030127"
x="93.501251"
y="81.265602" />
<rect
style="opacity:0.996;fill:#800000;fill-opacity:1;stroke:none;stroke-width:2.065;stroke-opacity:1"
id="rect343"
width="4.9159884"
height="5.0030127"
x="137.34044"
y="77.756187" />
<text
xml:space="preserve"
style="font-size:7.05556px;line-height:125%;font-family:'Linux Libertine O';-inkscape-font-specification:'Linux Libertine O';letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;fill:#000000;stroke:#000000;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="143.7274"
y="82.352852"
id="text399"><tspan
sodipodi:role="line"
id="tspan397"
style="stroke-width:0.264583px;fill:#000000"
x="143.7274"
y="82.352852">Ronald's house</tspan></text>
<rect
style="opacity:0.996;fill:#ffff00;fill-opacity:1;stroke:none;stroke-width:2.065;stroke-opacity:1"
id="rect451"
width="4.9159884"
height="5.0030127"
x="137.46651"
y="84.68708" />
<text
xml:space="preserve"
style="font-size:7.05556px;line-height:125%;font-family:'Linux Libertine O';-inkscape-font-specification:'Linux Libertine O';letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;fill:#000000;stroke:#000000;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="143.25378"
y="89.211967"
id="text455"><tspan
sodipodi:role="line"
id="tspan453"
style="fill:#000000;stroke-width:0.264583px"
x="143.25378"
y="89.211967">Desert</tspan></text>
<rect
style="opacity:0.996;fill:#008000;fill-opacity:1;stroke:none;stroke-width:2.065;stroke-opacity:1"
id="rect457"
width="4.9159884"
height="5.0030127"
x="137.40149"
y="91.927803" />
<text
xml:space="preserve"
style="font-size:7.05556px;line-height:125%;font-family:'Linux Libertine O';-inkscape-font-specification:'Linux Libertine O';letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;fill:#000000;stroke:#000000;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="143.21344"
y="96.509109"
id="text461"><tspan
sodipodi:role="line"
id="tspan459"
style="fill:#000000;stroke-width:0.264583px"
x="143.21344"
y="96.509109">Oasis</tspan></text>
<rect
style="opacity:0.996;fill:#808080;fill-opacity:1;stroke:none;stroke-width:2.065;stroke-opacity:1"
id="rect463"
width="4.9159884"
height="5.0030127"
x="137.27751"
y="98.927811" />
<text
xml:space="preserve"
style="font-size:7.05556px;line-height:125%;font-family:'Linux Libertine O';-inkscape-font-specification:'Linux Libertine O';letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;fill:#000000;stroke:#000000;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="143.53284"
y="103.50477"
id="text467"><tspan
sodipodi:role="line"
id="tspan465"
style="fill:#000000;stroke-width:0.264583px"
x="143.53284"
y="103.50477">Road</tspan></text>
<text
xml:space="preserve"
style="font-size:5.12831px;line-height:125%;font-family:'Linux Libertine O';-inkscape-font-specification:'Linux Libertine O';letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;fill:#000000;stroke:#000000;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="70.512794"
y="138.14319"
id="text539"
transform="scale(0.94984468,1.0528037)"><tspan
sodipodi:role="line"
id="tspan537"
style="fill:#000000;stroke-width:0.264583px"
x="70.512794"
y="138.14319">(19)S</tspan></text>
<text
xml:space="preserve"
style="font-size:5.12831px;line-height:125%;font-family:'Linux Libertine O';-inkscape-font-specification:'Linux Libertine O';letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;fill:#000000;stroke:#000000;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="70.512794"
y="52.536247"
id="text543"
transform="scale(0.94984468,1.0528037)"><tspan
sodipodi:role="line"
id="tspan541"
style="fill:#000000;stroke-width:0.264583px"
x="70.512794"
y="52.536247">(01)A</tspan></text>
<text
xml:space="preserve"
style="font-size:5.12831px;line-height:125%;font-family:'Linux Libertine O';-inkscape-font-specification:'Linux Libertine O';letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;fill:#000000;stroke:#000000;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="70.512794"
y="57.292187"
id="text547"
transform="scale(0.94984468,1.0528037)"><tspan
sodipodi:role="line"
id="tspan545"
style="fill:#000000;stroke-width:0.264583px"
x="70.512794"
y="57.292187">(02)B</tspan></text>
<text
xml:space="preserve"
style="font-size:5.12831px;line-height:125%;font-family:'Linux Libertine O';-inkscape-font-specification:'Linux Libertine O';letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;fill:#000000;stroke:#000000;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="70.512794"
y="62.04813"
id="text551"
transform="scale(0.94984468,1.0528037)"><tspan
sodipodi:role="line"
id="tspan549"
style="fill:#000000;stroke-width:0.264583px"
x="70.512794"
y="62.04813">(03)C</tspan></text>
<text
xml:space="preserve"
style="font-size:5.12831px;line-height:125%;font-family:'Linux Libertine O';-inkscape-font-specification:'Linux Libertine O';letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;fill:#000000;stroke:#000000;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="70.512794"
y="66.804062"
id="text555"
transform="scale(0.94984468,1.0528037)"><tspan
sodipodi:role="line"
id="tspan553"
style="fill:#000000;stroke-width:0.264583px"
x="70.512794"
y="66.804062">(04)D</tspan></text>
<text
xml:space="preserve"
style="font-size:5.12831px;line-height:125%;font-family:'Linux Libertine O';-inkscape-font-specification:'Linux Libertine O';letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;fill:#000000;stroke:#000000;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="70.512794"
y="71.560005"
id="text559"
transform="scale(0.94984468,1.0528037)"><tspan
sodipodi:role="line"
id="tspan557"
style="fill:#000000;stroke-width:0.264583px"
x="70.512794"
y="71.560005">(05)E</tspan></text>
<text
xml:space="preserve"
style="font-size:5.12831px;line-height:125%;font-family:'Linux Libertine O';-inkscape-font-specification:'Linux Libertine O';letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;fill:#000000;stroke:#000000;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="70.512794"
y="76.315948"
id="text563"
transform="scale(0.94984468,1.0528037)"><tspan
sodipodi:role="line"
id="tspan561"
style="fill:#000000;stroke-width:0.264583px"
x="70.512794"
y="76.315948">(06)F</tspan></text>
<text
xml:space="preserve"
style="font-size:5.12831px;line-height:125%;font-family:'Linux Libertine O';-inkscape-font-specification:'Linux Libertine O';letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;fill:#000000;stroke:#000000;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="70.512794"
y="81.071884"
id="text567"
transform="scale(0.94984468,1.0528037)"><tspan
sodipodi:role="line"
id="tspan565"
style="fill:#000000;stroke-width:0.264583px"
x="70.512794"
y="81.071884">(07)G</tspan></text>
<text
xml:space="preserve"
style="font-size:5.12831px;line-height:125%;font-family:'Linux Libertine O';-inkscape-font-specification:'Linux Libertine O';letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;fill:#000000;stroke:#000000;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="70.512794"
y="85.827827"
id="text571"
transform="scale(0.94984468,1.0528037)"><tspan
sodipodi:role="line"
id="tspan569"
style="fill:#000000;stroke-width:0.264583px"
x="70.512794"
y="85.827827">(08)H</tspan></text>
<text
xml:space="preserve"
style="font-size:5.12831px;line-height:125%;font-family:'Linux Libertine O';-inkscape-font-specification:'Linux Libertine O';letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;fill:#000000;stroke:#000000;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="70.512794"
y="90.583771"
id="text575"
transform="scale(0.94984468,1.0528037)"><tspan
sodipodi:role="line"
id="tspan573"
style="fill:#000000;stroke-width:0.264583px"
x="70.512794"
y="90.583771">(09)I</tspan></text>
<text
xml:space="preserve"
style="font-size:5.12831px;line-height:125%;font-family:'Linux Libertine O';-inkscape-font-specification:'Linux Libertine O';letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;fill:#000000;stroke:#000000;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="70.512794"
y="95.339706"
id="text579"
transform="scale(0.94984468,1.0528037)"><tspan
sodipodi:role="line"
id="tspan577"
style="fill:#000000;stroke-width:0.264583px"
x="70.512794"
y="95.339706">(10)J</tspan></text>
<text
xml:space="preserve"
style="font-size:5.12831px;line-height:125%;font-family:'Linux Libertine O';-inkscape-font-specification:'Linux Libertine O';letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;fill:#000000;stroke:#000000;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="70.512794"
y="100.09565"
id="text583"
transform="scale(0.94984468,1.0528037)"><tspan
sodipodi:role="line"
id="tspan581"
style="fill:#000000;stroke-width:0.264583px"
x="70.512794"
y="100.09565">(11)K</tspan></text>
<text
xml:space="preserve"
style="font-size:5.12831px;line-height:125%;font-family:'Linux Libertine O';-inkscape-font-specification:'Linux Libertine O';letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;fill:#000000;stroke:#000000;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="70.512794"
y="104.85159"
id="text587"
transform="scale(0.94984468,1.0528037)"><tspan
sodipodi:role="line"
id="tspan585"
style="fill:#000000;stroke-width:0.264583px"
x="70.512794"
y="104.85159">(12)L</tspan></text>
<text
xml:space="preserve"
style="font-size:5.12831px;line-height:125%;font-family:'Linux Libertine O';-inkscape-font-specification:'Linux Libertine O';letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;fill:#000000;stroke:#000000;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="70.512794"
y="109.60753"
id="text591"
transform="scale(0.94984468,1.0528037)"><tspan
sodipodi:role="line"
id="tspan589"
style="fill:#000000;stroke-width:0.264583px"
x="70.512794"
y="109.60753">(13)M</tspan></text>
<text
xml:space="preserve"
style="font-size:5.12831px;line-height:125%;font-family:'Linux Libertine O';-inkscape-font-specification:'Linux Libertine O';letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;fill:#000000;stroke:#000000;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="70.512794"
y="114.36347"
id="text595"
transform="scale(0.94984468,1.0528037)"><tspan
sodipodi:role="line"
id="tspan593"
style="fill:#000000;stroke-width:0.264583px"
x="70.512794"
y="114.36347">(14)N</tspan></text>
<text
xml:space="preserve"
style="font-size:5.12831px;line-height:125%;font-family:'Linux Libertine O';-inkscape-font-specification:'Linux Libertine O';letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;fill:#000000;stroke:#000000;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="70.512794"
y="119.11942"
id="text599"
transform="scale(0.94984468,1.0528037)"><tspan
sodipodi:role="line"
id="tspan597"
style="fill:#000000;stroke-width:0.264583px"
x="70.512794"
y="119.11942">(15)O</tspan></text>
<text
xml:space="preserve"
style="font-size:5.12831px;line-height:125%;font-family:'Linux Libertine O';-inkscape-font-specification:'Linux Libertine O';letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;fill:#000000;stroke:#000000;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="70.512794"
y="123.87535"
id="text603"
transform="scale(0.94984468,1.0528037)"><tspan
sodipodi:role="line"
id="tspan601"
style="fill:#000000;stroke-width:0.264583px"
x="70.512794"
y="123.87535">(16)P</tspan></text>
<text
xml:space="preserve"
style="font-size:5.12831px;line-height:125%;font-family:'Linux Libertine O';-inkscape-font-specification:'Linux Libertine O';letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;fill:#000000;stroke:#000000;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="70.512794"
y="128.6313"
id="text607"
transform="scale(0.94984468,1.0528037)"><tspan
sodipodi:role="line"
id="tspan605"
style="fill:#000000;stroke-width:0.264583px"
x="70.512794"
y="128.6313">(17)Q</tspan></text>
<text
xml:space="preserve"
style="font-size:5.12831px;line-height:125%;font-family:'Linux Libertine O';-inkscape-font-specification:'Linux Libertine O';letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;fill:#000000;stroke:#000000;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="70.512794"
y="133.38724"
id="text611"
transform="scale(0.94984468,1.0528037)"><tspan
sodipodi:role="line"
id="tspan609"
style="fill:#000000;stroke-width:0.264583px"
x="70.512794"
y="133.38724">(18)R</tspan></text>
<text
xml:space="preserve"
style="font-size:5.12831px;line-height:125%;font-family:'Linux Libertine O';-inkscape-font-specification:'Linux Libertine O';letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;fill:#000000;stroke:#000000;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="70.244728"
y="142.89912"
id="text615"
transform="scale(0.94984468,1.0528037)"><tspan
sodipodi:role="line"
id="tspan613"
style="fill:#000000;stroke-width:0.264583px"
x="70.244728"
y="142.89912">(20)T</tspan></text>
<text
xml:space="preserve"
style="font-size:5.12831px;line-height:125%;font-family:'Linux Libertine O';-inkscape-font-specification:'Linux Libertine O';letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;fill:#000000;stroke:#000000;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="126.06919"
y="47.331234"
id="text619"
transform="scale(0.94984468,1.0528037)"><tspan
sodipodi:role="line"
id="tspan617"
style="fill:#000000;stroke-width:0.264583px"
x="126.06919"
y="47.331234">9</tspan></text>
<text
xml:space="preserve"
style="font-size:5.12831px;line-height:125%;font-family:'Linux Libertine O';-inkscape-font-specification:'Linux Libertine O';letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;fill:#000000;stroke:#000000;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="83.517471"
y="47.331234"
id="text623"
transform="scale(0.94984468,1.0528037)"><tspan
sodipodi:role="line"
id="tspan621"
style="fill:#000000;stroke-width:0.264583px"
x="83.517471"
y="47.331234">1</tspan></text>
<text
xml:space="preserve"
style="font-size:5.12831px;line-height:125%;font-family:'Linux Libertine O';-inkscape-font-specification:'Linux Libertine O';letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;fill:#000000;stroke:#000000;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="88.836433"
y="47.331234"
id="text627"
transform="scale(0.94984468,1.0528037)"><tspan
sodipodi:role="line"
id="tspan625"
style="fill:#000000;stroke-width:0.264583px"
x="88.836433"
y="47.331234">2</tspan></text>
<text
xml:space="preserve"
style="font-size:5.12831px;line-height:125%;font-family:'Linux Libertine O';-inkscape-font-specification:'Linux Libertine O';letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;fill:#000000;stroke:#000000;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="94.155403"
y="47.331234"
id="text631"
transform="scale(0.94984468,1.0528037)"><tspan
sodipodi:role="line"
id="tspan629"
style="fill:#000000;stroke-width:0.264583px"
x="94.155403"
y="47.331234">3</tspan></text>
<text
xml:space="preserve"
style="font-size:5.12831px;line-height:125%;font-family:'Linux Libertine O';-inkscape-font-specification:'Linux Libertine O';letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;fill:#000000;stroke:#000000;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="99.474365"
y="47.331234"
id="text635"
transform="scale(0.94984468,1.0528037)"><tspan
sodipodi:role="line"
id="tspan633"
style="fill:#000000;stroke-width:0.264583px"
x="99.474365"
y="47.331234">4</tspan></text>
<text
xml:space="preserve"
style="font-size:5.12831px;line-height:125%;font-family:'Linux Libertine O';-inkscape-font-specification:'Linux Libertine O';letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;fill:#000000;stroke:#000000;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="104.79333"
y="47.331234"
id="text639"
transform="scale(0.94984468,1.0528037)"><tspan
sodipodi:role="line"
id="tspan637"
style="fill:#000000;stroke-width:0.264583px"
x="104.79333"
y="47.331234">5</tspan></text>
<text
xml:space="preserve"
style="font-size:5.12831px;line-height:125%;font-family:'Linux Libertine O';-inkscape-font-specification:'Linux Libertine O';letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;fill:#000000;stroke:#000000;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="110.1123"
y="47.331234"
id="text643"
transform="scale(0.94984468,1.0528037)"><tspan
sodipodi:role="line"
id="tspan641"
style="fill:#000000;stroke-width:0.264583px"
x="110.1123"
y="47.331234">6</tspan></text>
<text
xml:space="preserve"
style="font-size:5.12831px;line-height:125%;font-family:'Linux Libertine O';-inkscape-font-specification:'Linux Libertine O';letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;fill:#000000;stroke:#000000;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="115.43126"
y="47.331234"
id="text647"
transform="scale(0.94984468,1.0528037)"><tspan
sodipodi:role="line"
id="tspan645"
style="fill:#000000;stroke-width:0.264583px"
x="115.43126"
y="47.331234">7</tspan></text>
<text
xml:space="preserve"
style="font-size:5.12831px;line-height:125%;font-family:'Linux Libertine O';-inkscape-font-specification:'Linux Libertine O';letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;fill:#000000;stroke:#000000;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="120.75022"
y="47.331234"
id="text651"
transform="scale(0.94984468,1.0528037)"><tspan
sodipodi:role="line"
id="tspan649"
style="fill:#000000;stroke-width:0.264583px"
x="120.75022"
y="47.331234">8</tspan></text>
<text
xml:space="preserve"
style="font-size:5.12831px;line-height:125%;font-family:'Linux Libertine O';-inkscape-font-specification:'Linux Libertine O';letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;fill:#000000;stroke:#000000;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="131.38815"
y="47.469975"
id="text655"
transform="scale(0.94984468,1.0528037)"><tspan
sodipodi:role="line"
id="tspan653"
style="fill:#000000;stroke-width:0.264583px"
x="131.38815"
y="47.469975">10</tspan></text>
</g>
</svg>

After

Width:  |  Height:  |  Size: 32 KiB

View File

@ -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);