---
tags: TGUI, UI
title: Reworking preferences (Mothblocks)
---
# Reworking preferences (Mothblocks)
[toc]
## Maintainer Design Flows
:::warning
This section describes design flows that are meant to be upheld in the PR process. **PRs that go against this section are subject to closing.** Please do not edit this section unless you are a maintainer. Comments via sidebar are welcomed.
:::
## Intro
This page will include information about reworking the preferences menu into a tgui version with better UI/UX.
### Why do we want this?
* Preferences is not tgui at the moment
* This makes any attempt to add any functionality to it require a ton of really awful work.
* The preferences menu is currently a mis-match of different settings that are character and non character specific
* The preferences menu is not intuitive to new users
### Goals
* Create an interface that is easy to append onto, both in terms of UI and in terms of backend code.
* Most new settings should not require you to touch UI at all. UI code should only be necessary to write if you are creating a preference with a unique selection method.
* UI design should have scalable solution: Room for new buttons should be ample and as many use-cases should be kept in mind as possible
* Provide intuitive explanations of otherwise unknown in game concepts
* In the antag selection menu, you will get a brief description of the antag.
* In the job selection menu, you will get a brief description of the job.
* Provide visual representations of visual content
* Choosing your hairstyle will show the hairstyle alongside it, rather than just a name.
### Non-goals
* Stray too far from feature parity. Some uniqueness will come, but should be at the cost of better UI or UX.
### Future improvements
* Character exporting and importing
* Would just be JSON outputs, and would be entirely client-side to avoid any possibility of rogue inputs.
## Character Setup Menu
### Shared properties
### Character Customization
This is the page on which you can customize the looks, quirks, and other minor details of your character.
#### Main Screen

#### Species Select

#### Mothblocks notes
- Some species don't have skin, such as moths. In this case the buttons should be greyed out to prevent confusion.
### Role Preferences
This is the page on which you can pick this characters preferences antag roles.

### Job Preferences
This is the page on which you can pick this characters job preferences

Colors of the circles here are temporary. They will most likely be:
Off - Gray with diagonal black line through it
Low - Red
Medium - Orange
High - Green
### Hotkeys

## Non-Maintainer Design Flows
:::info
This section describes various design flows that are not yet incorporated into the maintainer-approved design. **Working towards these flows does not guarantee merge, nor does going against these flows guarantee close. Please resort to `###` and below for heading tags, and preferably `Title (Author)` for easy reference. Titles can be set with YAML metadata. Ping Cobby on Discord if you need assistance embedding/generating your note.**
:::
---
### Job Screen? Maybe? (maxymax13)
#### Job Select

Job Select Troubles
* Where exactly should prisoners go?
* Should snowflake jobs (Clown, Mine & Assistant) be shown in their de jure place in the chain of command (under hop), or reflect their de facto role ingame (gods of eternal chaos bound neither above or under anyone)?
* How do we handle displaying departments with exceedingly high amounts of jobs (Supplyvice)?
* Are 4 tiny icons really a good way of showing the seccie department choice? Maybe a dropdown shown near the icon? Either way we need to make that choice not be buried on a completely separate tab from jobs.
* What's the best way of displaying the low/med/high status of a job? I think maybe colored glowing icon outlines with a much higher width than the regular outlines?
* Do we have to make it clearer that the QM is not a head, or is him being under the HoP and not being command blue enough?
* the all jobs taken behaviour button should be more prominent
#### Assistant/Overflow On

Assistant/Overflow On Troubles
* we need a more elegant way of handling the randlom overflow job station trait
#### Job Info

Job Info Troubles
* I think something like the "bare minimum" line on job infoboxes on the wiki would be good, but at the same time, wouldn't that just encourage people to play shittily by implying it's ok to just do 3 things as a semi important job and then just walk away?
* Talking about wiki, a button linking to the job's wiki page would be great.
### preferences backend idea spitballing/"let's make this overly extensible for fun and profit" (silicons)
Some proposals for making the system extremely extensible.
Possibly far more extensible than it realistically needs to be for just one server.
#### UI, global vs character specific options
I'm way too unartistic to do a drawup but:

Character slots go on the left, click on a slot to load. Buttons on the top for save/load/reset/copy/etc
Categories go on the top. There's a UI divider in the middle to separate character preferences from global preferences.
The content is rendered below using ui_data from a category datum
#### Backend, savefiles, etc
Inspired by how bay handles their however-complicated system: Preference categories are their own (globally cached) datums that
- read data from someone's savefile to render the content
- react to topic/ui acts to write to their preferences savefile
- Perform sanitization and generally *handle* data related to themselves
For example you'd have /datum/preferences_category/occupations, which reads and writes to the job slots of a character's savefile, and it handles ui_data and ui_act for a tgui template that's then rendered in the content section. Kinda like how modular computers work.
You'd also have stuff like "set default" procs for initializing new savefiles per category.
Data storage can either be like now, with "raw" variables set on the /datum/preferences, or something like /datum/preferences/list/savedata where the entire list is then written to savefile, either for global prefs or character prefs
The entire system would direct the savefile.cd to /global for all global prefs, and then /character# for char specific saves.
procs:
/save_character(savefile/S, preferences/P)
/save_global(savefile/S, preferences/P)
/load_character(savefile/S, preferences/P)
/load_global(savefile/S, preferences/P)
/sanitize_character(preferences/P)
/sanitize_global(preferences/)
^ above are separate procs for chars/global so if anyone ever wants to do "default global but can be made into a character override by an user" stuff, it'll be far easier
sanitization is done with every save/load
/copy_to(human/H, preferences/P)
^ loads a character to a human mob, per usual. reads directly from prefs.
/get_ui_data(action, params, client/C, preferences/P)
/on_ui_act(action, params, client/C, preferences/P)
^ primarily how they actually function for ui and operation purposes. reads/writes to prefs, not savefile. savefile "flush" only done on user request
for the actual save/load operations, maybe something like how Polaris/some baycode codebases does it, where a subsystem is used (NO_FIRE, queue by |='ing a datum and addtimer 0 unique to fire immediately on the next tick). sure, people should be smart and not do stupid things like save to disk 5 times at the same time, but this'll safety-net for when someone fucks up
*This would also allow for some crazy stuff like json import/export if savefile saving/loading/sanitization was standardized as procs, rather than direct savefile accesses. And y'know, sanitization was literally perfect :)*
#### Migrations
Savefile wise, I'm really not sure how efficient this would be but
Savefile versions would be saved globally on the savefile, as well as on each character
When migrating, first all global categories are called upon to do their savefile migrations. Each category would have a proc named, say, `handle_migrations(savefile/S, old_version, new_version, list/errors)`.
After that, you have say, the following system
```
#define SAVEFILE_VERSION_MIN 5
#define SAVEFILE_VERSION_MAX 20
#define SAVEFILE_VERSION_FULL_UPDATE_REQUIRED 15
```
To save on the processing requirement of, y'know, having to read every character slot to check for updates every time someone connects, or being *entirely* lazy and only checking on load, you could have a system where the global version is checked
If below min, just like now, the entire file is tossed out, set to default, and set to max.
If it's below max, one of two things happen:
- If it's not below full update required, global prefs are migrated, and whatever slot they choose is migrated. If they load another slot, it's checked and migrated. Loading a slot always checks for migrations.
- For when coders do breaking changes that really should be updated **now**, at the cost of a performance hit when someone with such a save connects, having version below full update required will cause the system to iterate through 1 through MAX_CHARACTERS slots and update **everything**, before loading their chosen slot again.
- Savefile migration failures are +='d to `errors`. Whenever it's not empty, its contents are logged and output to the user, so coders can put in feedback for when something fails instead of a silent failure.
#### Why all of this mess?
- Categories vs just one datum can potentially make code cleaner/more concise/easier to edit.
- Extensibility to this degree imo is going to be helpful for future changes, but even more valuable for potential downstreams trying to add more things.
and y'know I'm assuming this is already a taken project but if anyone wants me to code anything for this I'm around.