diff --git a/.github/workflows/ci_suite.yml b/.github/workflows/ci_suite.yml
index d29a4c2d96e..46492e19abe 100644
--- a/.github/workflows/ci_suite.yml
+++ b/.github/workflows/ci_suite.yml
@@ -30,7 +30,7 @@ jobs:
run_linters:
name: Run Linters
needs: start_gate
- runs-on: ubuntu-22.04
+ runs-on: ubuntu-24.04
timeout-minutes: 10
steps:
@@ -75,6 +75,7 @@ jobs:
bash tools/ci/install_node.sh
bash tools/ci/install/install_spaceman_dmm.sh dreamchecker
bash tools/ci/install_ripgrep.sh
+ sudo apt install -y python3-pip
tools/bootstrap/python -c ''
- name: Give Linters A Go
id: linter-setup
@@ -140,19 +141,25 @@ jobs:
options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3
steps:
- uses: actions/checkout@v4
+ - name: Restore Flyway
+ uses: actions/cache@v4
+ with:
+ path: ~/flyway
+ key: ${{ runner.os }}-flyway-${{ hashFiles('dependencies.sh') }}
- name: Restore BYOND cache
uses: actions/cache@v4
with:
path: ~/BYOND
key: ${{ runner.os }}-byond-${{ hashFiles('dependencies.sh') }}
+ - name: Install flyway
+ run: |
+ bash tools/ci/install/install_flyway.sh
- name: Setup database
run: |
sudo systemctl start mysql
- mysql -u root -proot -e 'CREATE DATABASE ss13_ci;'
- mysql -u root -proot ss13_ci < SQL/database_schema_prefixed.sql
- mysql -u root -proot ss13_ci < SQL/unified_schema.sql
- # mysql -u root -proot -e 'CREATE DATABASE tg_ci_prefixed;'
- # mysql -u root -proot tg_ci_prefixed < SQL/tgstation_schema_prefixed.sql
+ mysql -u root -proot -e 'CREATE DATABASE ss13;'
+ source dependencies.sh
+ ~/flyway/flyway-$FLYWAY_VERSION/flyway -user=root -password=root -url=jdbc:mariadb://localhost:3306/ss13 -locations="filesystem:sql/migrations" migrate
- name: Install rust-g
run: |
bash tools/ci/install/install_rust_g.sh
diff --git a/.vscode/extensions.json b/.vscode/extensions.json
index 87869168fcf..44df201905e 100644
--- a/.vscode/extensions.json
+++ b/.vscode/extensions.json
@@ -8,6 +8,7 @@
"donkie.vscode-tgstation-test-adapter",
"anturk.dmi-editor",
"aaron-bond.better-comments",
- "ss13.opendream"
+ "ss13.opendream",
+ "tamasfe.even-better-toml"
]
}
diff --git a/README.md b/README.md
index b0228569fea..a957b846c10 100644
--- a/README.md
+++ b/README.md
@@ -42,8 +42,12 @@ On **May 9, 2022** we have changed the way to compile the codebase.
## SQL Setup
The SQL backend for the library and stats tracking requires a MariaDB server.
-Your server details go in /config/legacy/dbconfig.txt, and the SQL schema is in /SQL/tgstation_schema.sql.
-More detailed setup instructions arecoming soon, for now ask in our Discord.
+Your server details go in /config/legacy/dbconfig.txt.
+
+Flyway is used for setup and migration. Run the migrations in `sql/migrations` against your database, and everything should just work.
+We do not use table prefixes.
+
+More detailed setup instructions are coming soon, for now ask in our Discord.
todo: update this section
@@ -62,6 +66,7 @@ These are also the folders you are likely going to encounter while managing the
- /players: player data, like saves and characters get dumped in here
- /tmp: server scratch space
- /assets - for asset generation
+ - /config - used as scratch space for config
You only need to make the top level folders (e.g. config, data) static folders in TGS4.
diff --git a/SQL/database_schema.sql b/SQL/database_schema.sql
deleted file mode 100644
index f1b50df6fd4..00000000000
--- a/SQL/database_schema.sql
+++ /dev/null
@@ -1,439 +0,0 @@
-/**
- * make sure to bump schema version and mark changes in database_changelog.md!
- *
- * default prefix is rp_
- * find replace case sensitive %_PREFIX_%
- * PRESERVE ANY vr_'s! We need to replace those tables and features at some point, that's how we konw.
- **/
-
--- core --
-
---
--- Table structure for table `schema_revision`
---
-CREATE TABLE IF NOT EXISTS `%_PREFIX_%schema_revision` (
- `major` TINYINT(3) unsigned NOT NULL,
- `minor` TINYINT(3) unsigned NOT NULL,
- `date` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
- PRIMARY KEY (`major`, `minor`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
-
--- persistence --
-
--- SSpersistence modules/bulk_entity
-CREATE TABLE IF NOT EXISTS `%_PREFIX_%persistence_bulk_entity` (
- `id` INT(24) NOT NULL AUTO_INCREMENT,
- `generation` INT(11) NOT NULL,
- `persistence_key` VARCHAR(64) NOT NULL,
- `level_id` VARCHAR(64) NOT NULL,
- `data` MEDIUMTEXT,
- `round_id` INT(11) NOT NULL,
- PRIMARY KEY (`id`),
- INDEX(`level_id`, `generation`, `persistence_key`),
- INDEX(`level_id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
-
--- SSpersistence modules/level_objects
-CREATE TABLE IF NOT EXISTS `%_PREFIX_%persistence_static_level_objects` (
- `generation` INT(11) NOT NULL,
- `object_id` VARCHAR(64) NOT NULL,
- `level_id` VARCHAR(64) NOT NULL,
- `data` MEDIUMTEXT NOT NULL,
- PRIMARY KEY(`generation`, `object_id`, `level_id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
-
--- SSpersistence modules/level_objects
-CREATE TABLE IF NOT EXISTS `%_PREFIX_%persistence_static_map_objects` (
- `generation` INT(11) NOT NULL,
- `object_id` VARCHAR(64) NOT NULL,
- `map_id` VARCHAR(64) NOT NULL,
- `data` MEDIUMTEXT NOT NULL,
- PRIMARY KEY(`generation`, `object_id`, `map_id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
-
--- SSpersistence modules/level_objects
-CREATE TABLE IF NOT EXISTS `%_PREFIX_%persistence_static_global_objects` (
- `generation` INT(11) NOT NULL,
- `object_id` VARCHAR(64) NOT NULL,
- `data` MEDIUMTEXT NOT NULL,
- PRIMARY KEY(`generation`, `object_id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
-
--- SSpersistence modules/level_objects
-CREATE TABLE IF NOT EXISTS `%_PREFIX_%persistence_dynamic_objects` (
- `generation` INT(11) NOT NULL,
- `object_id` INT(24) NOT NULL AUTO_INCREMENT,
- `level_id` VARCHAR(64) NOT NULL,
- `prototype_id` VARCHAR(256) NOT NULL,
- `status` INT(24) NOT NULL DEFAULT 0,
- `data` MEDIUMTEXT NOT NULL,
- `x` INT(8) NOT NULL,
- `y` INT(8) NoT NULL,
- PRIMARY KEY(`object_id`, `generation`),
- INDEX(`object_id`),
- INDEX(`level_id`, `generation`),
- INDEX(`prototype_id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
-
--- SSpersistence modules/spatial_metadata
-CREATE TABLE IF NOT EXISTS `%_PREFIX_%persistence_level_metadata` (
- `created` DATETIME NOT NULL DEFAULT Now(),
- `saved` DATETIME NOT NULL,
- `saved_round_id` INT(11) NOT NULL,
- `level_id` VARCHAR(64) NOT NULL,
- `data` MEDIUMTEXT NOT NULL,
- `generation` INT(11) NOT NULL,
- PRIMARY KEY(`level_id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
-
--- SSpersistence modules/string_kv
-CREATE TABLE IF NOT EXISTS `%_PREFIX_%persistence_string_kv` (
- `created` DATETIME NOT NULL DEFAULT Now(),
- `modified` DATETIME NOT NULL,
- `key` VARCHAR(64) NOT NULL,
- `value` MEDIUMTEXT NULL,
- `group` VARCHAR(64) NOT NULL,
- `revision` INT(11) NOT NULL,
- PRIMARY KEY(`key`, `group`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
-
--- photography --
-
--- picture table --
--- used to store data about pictures --
--- hash is in sha1 format. --
-CREATE TABLE IF NOT EXISTS `%_PREFIX_%pictures` (
- `id` int(11) NOT NULL AUTO_INCREMENT,
- `hash` char(40) NOT NULL,
- `created` datetime NOT NULL DEFAULT Now(),
- `width` int NOT NULL,
- `height` int NOT NULL,
- PRIMARY KEY (`id`),
- UNIQUE KEY `hash` (`hash`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
-
--- photograph table --
--- used to store data about photographs --
--- picture is picture hash in picture table --
-CREATE TABLE IF NOT EXISTS `%_PREFIX_%photographs` (
- `id` int(11) NOT NULL AUTO_INCREMENT,
- `picture` char(40) NOT NULL,
- `created` datetime NOT NULL DEFAULT Now(),
- `scene` MEDIUMTEXT null,
- `desc` MEDIUMTEXT null,
- CONSTRAINT `linked_picture` FOREIGN KEY (`picture`)
- REFERENCES `%_PREFIX_%pictures` (`hash`)
- ON DELETE CASCADE
- ON UPDATE CASCADE,
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
-
--- Players --
-
--- Player lookup table --
--- Used to look up player ID from ckey, as well as --
--- store last computerid/ip for a ckey. --
-CREATE TABLE IF NOT EXISTS `%_PREFIX_%player_lookup` (
- `id` int(11) NOT NULL AUTO_INCREMENT,
- `ckey` varchar(32) NOT NULL,
- `firstseen` datetime NOT NULL,
- `lastseen` datetime NOT NULL,
- `ip` varchar(18) NOT NULL,
- `computerid` varchar(32) NOT NULL,
- `lastadminrank` varchar(32) NOT NULL DEFAULT 'Player',
- `playerid` int(11),
- PRIMARY KEY (`id`),
- UNIQUE KEY `ckey` (`ckey`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
-
--- Primary player table --
--- Allows for one-to-many player-ckey association. --
-CREATE TABLE IF NOT EXISTS `%_PREFIX_%player` (
- `id` int(11) NOT NULL AUTO_INCREMENT,
- `flags` int(24) NOT NULL DEFAULT 0,
- `firstseen` datetime NOT NULL DEFAULT Now(),
- `lastseen` datetime NOT NULL,
- `misc` MEDIUMTEXT NOT NULL,
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
-
--- Playtime / JEXP --
-
--- Role Time Table - Master --
--- Stores total role time. --
-
-CREATE TABLE IF NOT EXISTS `%_PREFIX_%playtime` (
- `player` INT(11) NOT NULL,
- `roleid` VARCHAR(64) NOT NULL,
- `minutes` INT UNSIGNED NOT NULL,
- PRIMARY KEY(`player`, `roleid`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
-
--- Role Time - Logging --
--- Stores changes in role time --
-CREATE TABLE IF NOT EXISTS `%_PREFIX_%playtime_log` (
- `player` INT(11),
- `id` BIGINT(20) NOT NULL AUTO_INCREMENT,
- `roleid` VARCHAR(64) NOT NULL,
- `delta` INT(11) NOT NULL,
- `datetime` TIMESTAMP NOT NULL DEFAULT NOW() ON UPDATE NOW(),
- PRIMARY KEY (`id`),
- KEY `player` (`player`),
- KEY `roleid` (`roleid`),
- KEY `datetime` (`datetime`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
-
-DELIMITER $$
-CREATE TRIGGER `playtimeTlogupdate` AFTER UPDATE ON `%_PREFIX_%playtime` FOR EACH ROW BEGIN INSERT into `%_PREFIX_%playtime_log` (player, roleid, delta) VALUES (NEW.player, NEW.roleid, NEW.minutes-OLD.minutes);
-END
-$$
-CREATE TRIGGER `playtimeTloginsert` AFTER INSERT ON `%_PREFIX_%playtime` FOR EACH ROW BEGIN INSERT into `%_PREFIX_%playtime_log` (player, roleid, delta) VALUES (NEW.player, NEW.roleid, NEW.minutes);
-END
-$$
-CREATE TRIGGER `playtimeTlogdelete` AFTER DELETE ON `%_PREFIX_%playtime` FOR EACH ROW BEGIN INSERT into `%_PREFIX_%playtime_log` (player, roleid, delta) VALUES (OLD.player, OLD.roleid, 0-OLD.minutes);
-END
-$$
-DELIMITER ;
-
-
--- Preferences --
-
--- Stores game preferences --
-CREATE TABLE IF NOT EXISTS `%_PREFIX_%game_preferences` (
- `player` INT(11) NOT NULL,
- `entries` MEDIUMTEXT NOT NULL,
- `misc` MEDIUMTEXT NOT NULL,
- `keybinds` MEDIUMTEXT NOT NULL,
- `toggles` MEDIUMTEXT NOT NULL,
- `modified` DATETIME NOT NULL,
- `version` INT(11) NOT NULL,
- PRIMARY KEY (`player`),
- CONSTRAINT `linked_player` FOREIGN KEY (`player`)
- REFERENCES `%_PREFIX_%player` (`id`)
- ON DELETE CASCADE
- ON UPDATE CASCADE
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
-
--- Security - Ipintel --
-
--- Ipintel Cache Table --
--- Stores cache entries for IPIntel --
--- IP is in INET_ATON. --
-CREATE TABLE IF NOT EXISTS `%_PREFIX_%ipintel` (
- `ip` INT(10) unsigned NOT NULL,
- `date` TIMESTAMP NOT NULL DEFAULT NOW() ON UPDATE NOW(),
- `intel` double NOT NULL DEFAULT '0',
- PRIMARY KEY (`ip`),
- KEY `idx_ipintel` (`ip`, `intel`, `date`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
-
---
--- Table structure for table `round`
---
-CREATE TABLE IF NOT EXISTS `%_PREFIX_%round` (
- `id` INT(11) NOT NULL AUTO_INCREMENT,
- `initialize_datetime` DATETIME NOT NULL,
- `start_datetime` DATETIME NULL,
- `shutdown_datetime` DATETIME NULL,
- `end_datetime` DATETIME NULL,
- `server_ip` INT(10) UNSIGNED NOT NULL,
- `server_port` SMALLINT(5) UNSIGNED NOT NULL,
- `commit_hash` CHAR(40) NULL,
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
-
--- Connection log --
--- Logs all connections to the server. --
-CREATE TABLE IF NOT EXISTS `%_PREFIX_%connection_log` (
- `id` INT(11) NOT NULL AUTO_INCREMENT,
- `datetime` datetime NOT NULL,
- `serverip` varchar(45) NOT NULL,
- `ckey` varchar(32) NOT NULL,
- `ip` varchar(45) NOT NULL,
- `computerid` varchar(32) NOT NULL,
- PRIMARY KEY(`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
-
--- /datum/character - Character Table --
-CREATE TABLE IF NOT EXISTS `%_PREFIX_%character` (
- `id` INT(11) NOT NULL AUTO_INCREMENT,
- `created` DATETIME NOT NULL DEFAULT Now(),
- `last_played` DATETIME NULL,
- `last_persisted` DATETIME NULL,
- `playerid` INT(11) NOT NULL,
- `canonical_name` VARCHAR(128) NOT NULL,
- `persist_data` MEDIUMTEXT NULL,
- `character_type` VARCHAR(64) NOT NULL,
- PRIMARY KEY(`id`),
- CONSTRAINT `character_has_player` FOREIGN KEY (`playerid`)
- REFERENCES `%_PREFIX_%player` (`id`)
- ON DELETE CASCADE
- ON UPDATE CASCADE,
- UNIQUE (`playerid`, `canonical_name`, `character_type`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
-
-CREATE TABLE IF NOT EXISTS `%_PREFIX_%admin` (
- `id` int(11) NOT NULL AUTO_INCREMENT,
- `ckey` varchar(32) NOT NULL,
- `rank` varchar(32) NOT NULL DEFAULT 'Administrator',
- `level` int(2) NOT NULL DEFAULT '0',
- `flags` int(16) NOT NULL DEFAULT '0',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
-
-CREATE TABLE IF NOT EXISTS `%_PREFIX_%admin_log` (
- `id` int(11) NOT NULL AUTO_INCREMENT,
- `datetime` datetime NOT NULL,
- `adminckey` varchar(32) NOT NULL,
- `adminip` varchar(18) NOT NULL,
- `log` text NOT NULL,
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
-
-CREATE TABLE IF NOT EXISTS `%_PREFIX_%ban` (
- `id` int(11) NOT NULL AUTO_INCREMENT,
- `bantime` datetime NOT NULL,
- `serverip` varchar(32) NOT NULL,
- `bantype` varchar(32) NOT NULL,
- `reason` text NOT NULL,
- `job` varchar(32) DEFAULT NULL,
- `duration` int(11) NOT NULL,
- `rounds` int(11) DEFAULT NULL,
- `expiration_time` datetime NOT NULL,
- `ckey` varchar(32) NOT NULL,
- `computerid` varchar(32) NOT NULL,
- `ip` varchar(32) NOT NULL,
- `a_ckey` varchar(32) NOT NULL,
- `a_computerid` varchar(32) NOT NULL,
- `a_ip` varchar(32) NOT NULL,
- `who` text NOT NULL,
- `adminwho` text NOT NULL,
- `edits` text,
- `unbanned` tinyint(1) DEFAULT NULL,
- `unbanned_datetime` datetime DEFAULT NULL,
- `unbanned_ckey` varchar(32) DEFAULT NULL,
- `unbanned_computerid` varchar(32) DEFAULT NULL,
- `unbanned_ip` varchar(32) DEFAULT NULL,
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
-
-CREATE TABLE IF NOT EXISTS `%_PREFIX_%feedback` (
- `id` int(11) NOT NULL AUTO_INCREMENT,
- `time` datetime NOT NULL,
- `round_id` int(8) NOT NULL,
- `var_name` varchar(32) NOT NULL,
- `var_value` int(16) DEFAULT NULL,
- `details` text,
- PRIMARY KEY (`id`)
-) ENGINE=MyISAM DEFAULT CHARSET=latin1 ;
-
-CREATE TABLE IF NOT EXISTS `%_PREFIX_%poll_option` (
- `id` int(11) NOT NULL AUTO_INCREMENT,
- `pollid` int(11) NOT NULL,
- `text` varchar(255) NOT NULL,
- `percentagecalc` tinyint(1) NOT NULL DEFAULT '1',
- `minval` int(3) DEFAULT NULL,
- `maxval` int(3) DEFAULT NULL,
- `descmin` varchar(32) DEFAULT NULL,
- `descmid` varchar(32) DEFAULT NULL,
- `descmax` varchar(32) DEFAULT NULL,
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
-
-CREATE TABLE IF NOT EXISTS `%_PREFIX_%poll_question` (
- `id` int(11) NOT NULL AUTO_INCREMENT,
- `polltype` varchar(16) NOT NULL DEFAULT 'OPTION',
- `starttime` datetime NOT NULL,
- `endtime` datetime NOT NULL,
- `question` varchar(255) NOT NULL,
- `adminonly` tinyint(1) DEFAULT '0',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
-
-CREATE TABLE IF NOT EXISTS `%_PREFIX_%poll_textreply` (
- `id` int(11) NOT NULL AUTO_INCREMENT,
- `datetime` datetime NOT NULL,
- `pollid` int(11) NOT NULL,
- `ckey` varchar(32) NOT NULL,
- `ip` varchar(18) NOT NULL,
- `replytext` text NOT NULL,
- `adminrank` varchar(32) NOT NULL DEFAULT 'Player',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
-
-CREATE TABLE IF NOT EXISTS `%_PREFIX_%poll_vote` (
- `id` int(11) NOT NULL AUTO_INCREMENT,
- `datetime` datetime NOT NULL,
- `pollid` int(11) NOT NULL,
- `optionid` int(11) NOT NULL,
- `ckey` varchar(255) NOT NULL,
- `ip` varchar(16) NOT NULL,
- `adminrank` varchar(32) NOT NULL,
- `rating` int(2) DEFAULT NULL,
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
-
-CREATE TABLE IF NOT EXISTS `%_PREFIX_%privacy` (
- `id` int(11) NOT NULL AUTO_INCREMENT,
- `datetime` datetime NOT NULL,
- `ckey` varchar(32) NOT NULL,
- `option` varchar(128) NOT NULL,
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
-
-CREATE TABLE IF NOT EXISTS `%_PREFIX_%death` (
- `id` INT(11) NOT NULL AUTO_INCREMENT ,
- `pod` TEXT NOT NULL COMMENT 'Place of death' ,
- `coord` TEXT NOT NULL COMMENT 'X, Y, Z POD' ,
- `tod` DATETIME NOT NULL COMMENT 'Time of death' ,
- `job` TEXT NOT NULL ,
- `special` TEXT NOT NULL ,
- `name` TEXT NOT NULL ,
- `byondkey` TEXT NOT NULL ,
- `laname` TEXT NOT NULL COMMENT 'Last attacker name' ,
- `lakey` TEXT NOT NULL COMMENT 'Last attacker key' ,
- `gender` TEXT NOT NULL ,
- `bruteloss` INT(11) NOT NULL ,
- `brainloss` INT(11) NOT NULL ,
- `fireloss` INT(11) NOT NULL ,
- `oxyloss` INT(11) NOT NULL ,
- PRIMARY KEY (`id`)
- ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
-
-CREATE TABLE IF NOT EXISTS `%_PREFIX_%karma` (
- `id` INT(11) NOT NULL AUTO_INCREMENT ,
- `spendername` TEXT NOT NULL ,
- `spenderkey` TEXT NOT NULL ,
- `receivername` TEXT NOT NULL ,
- `receiverkey` TEXT NOT NULL ,
- `receiverrole` TEXT NOT NULL ,
- `receiverspecial` TEXT NOT NULL ,
- `isnegative` TINYINT(1) NOT NULL ,
- `spenderip` TEXT NOT NULL ,
- `time` DATETIME NOT NULL ,
- PRIMARY KEY (`id`)
- ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
-
-CREATE TABLE IF NOT EXISTS `%_PREFIX_%karmatotals` (
- `id` INT(11) NOT NULL AUTO_INCREMENT ,
- `byondkey` TEXT NOT NULL ,
- `karma` INT(11) NOT NULL ,
- PRIMARY KEY (`id`)
- ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
-
-CREATE TABLE IF NOT EXISTS `%_PREFIX_%library` (
- `id` INT(11) NOT NULL AUTO_INCREMENT ,
- `author` TEXT NOT NULL ,
- `title` TEXT NOT NULL ,
- `content` TEXT NOT NULL ,
- `category` TEXT NOT NULL ,
- PRIMARY KEY (`id`)
- ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
-
-CREATE TABLE IF NOT EXISTS `%_PREFIX_%population` (
- `id` INT(11) NOT NULL AUTO_INCREMENT ,
- `playercount` INT(11) NULL DEFAULT NULL ,
- `admincount` INT(11) NULL DEFAULT NULL ,
- `time` DATETIME NOT NULL ,
- PRIMARY KEY (`id`)
- ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
diff --git a/SQL/unified_schema.sql b/SQL/unified_schema.sql
deleted file mode 100644
index 32441c5e22e..00000000000
--- a/SQL/unified_schema.sql
+++ /dev/null
@@ -1,17 +0,0 @@
-/**
- * make sure to bump schema version and mark changes in database_changelog.md!
- *
- * you MUST use unified_ as a prefix.
- *
- * unified schema for citadel, **sync changes to both servers.**
- **/
-
---
--- Table structure for table `schema_revision`
---
-CREATE TABLE IF NOT EXISTS `unified_schema_revision` (
- `major` TINYINT(3) unsigned NOT NULL,
- `minor` TINYINT(3) unsigned NOT NULL,
- `date` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
- PRIMARY KEY (`major`, `minor`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
diff --git a/citadel.dme b/citadel.dme
index abf6e203047..7746ae80ceb 100644
--- a/citadel.dme
+++ b/citadel.dme
@@ -686,6 +686,10 @@
#include "code\controllers\subsystem\sound\_sound.dm"
#include "code\controllers\subsystem\sound\channel_manager.dm"
#include "code\controllers\subsystem\sound\soundbyte_manager.dm"
+#include "code\controllers\toml_config\toml_config_entry.dm"
+#include "code\controllers\toml_config\toml_configuration.dm"
+#include "code\controllers\toml_config\entries\backend.dm"
+#include "code\controllers\toml_config\entries\backend.repository.dm"
#include "code\datums\ability.dm"
#include "code\datums\ability_handler.dm"
#include "code\datums\access.dm"
@@ -2249,6 +2253,7 @@
#include "code\modules\admin\verbs\debug\fucky_wucky.dm"
#include "code\modules\admin\verbs\debug\profiling.dm"
#include "code\modules\admin\verbs\debug\reestablish_db_connection.dm"
+#include "code\modules\admin\verbs\debug\reload_configuration.dm"
#include "code\modules\admin\verbs\debug\spawn.dm"
#include "code\modules\admin\verbs\SDQL2\SDQL_2.dm"
#include "code\modules\admin\verbs\SDQL2\SDQL_2_parser.dm"
diff --git a/code/__DEFINES/controllers/_repository.dm b/code/__DEFINES/controllers/_repository.dm
index b2f5702f752..9f08048dc8d 100644
--- a/code/__DEFINES/controllers/_repository.dm
+++ b/code/__DEFINES/controllers/_repository.dm
@@ -7,6 +7,9 @@
//* This is here in [code/__DEFINES/controllers/_repositories.dm] for compile order reasons. *//
/datum/controller/subsystem/repository/proc/__init_repositories()
+//* This is here in [code/__DEFINES/controllers/_repositories.dm] for compile order reasons. *//
+/datum/controller/subsystem/repository/proc/__get_all_repositories()
+
// todo: redo recover logic; maybe /datum/controller as a whole should be brushed up
#define REPOSITORY_DEF(what) \
GLOBAL_REAL(RS##what, /datum/controller/repository/##what); \
@@ -27,4 +30,12 @@ GLOBAL_REAL(RS##what, /datum/controller/repository/##what); \
..(); \
RS##what.Initialize(); \
} \
+/datum/controller/subsystem/repository/__get_all_repositories() { \
+ . = ..(); \
+ . += RS##what; \
+} \
/datum/controller/repository/##what
+
+/// Returned from /datum/controller/repository's fetch_or_defer() if we don't have something
+/// on hand, but also don't know that it doesn't exist.
+#define REPOSITORY_FETCH_DEFER "defer"
diff --git a/code/__DEFINES/controllers/dbcore.dm b/code/__DEFINES/controllers/dbcore.dm
index afc6709805c..19df14d5588 100644
--- a/code/__DEFINES/controllers/dbcore.dm
+++ b/code/__DEFINES/controllers/dbcore.dm
@@ -17,6 +17,11 @@
*/
#define DB_MINOR_VERSION 3
+//* Tables *//
+
+/// Prefixes are currently disabled.
+#define DB_PREFIX_TABLE_NAME(TABLE) TABLE
+
//* Misc *//
/// pass this into duplicate_key on mass_insert() to overwrite old values
diff --git a/code/__HELPERS/nameof.dm b/code/__HELPERS/nameof.dm
index 7cd5777f465..6e625578ae6 100644
--- a/code/__HELPERS/nameof.dm
+++ b/code/__HELPERS/nameof.dm
@@ -4,6 +4,12 @@
* datum may be null, but it does need to be a typed var.
**/
#define NAMEOF(datum, X) (#X || ##datum.##X)
+/**
+ * NAMEOF: Compile time checked variable name to string conversion
+ * evaluates to a string equal to "X", but compile errors if X isn't a var on datum.
+ * datum may be null, but it does need to be a typed var.
+ **/
+#define NAMEOF_PROC(datum, X) (#X || ##datum.##X())
/**
* NAMEOF that actually works in static definitions because src::type requires src to be defined
diff --git a/code/__HELPERS/text.dm b/code/__HELPERS/text.dm
index 7fcdc575e3a..5c4a63dc189 100644
--- a/code/__HELPERS/text.dm
+++ b/code/__HELPERS/text.dm
@@ -1,23 +1,12 @@
/**
* Holds procs designed to help with filtering text
* Contains groups:
- * ! SQL sanitization
* ! Text sanitization
* ! Text searches
* ! Text modification
* ! Misc
*/
-/**
- *! SQL sanitization
- */
-
-/proc/format_table_name(table)
- return CONFIG_GET(string/sql_server_prefix) + table
-
-/proc/format_unified_table_name(table)
- return CONFIG_GET(string/sql_unified_prefix) + table
-
/**
*! Text sanitization
*/
diff --git a/code/controllers/README.md b/code/controllers/README.md
new file mode 100644
index 00000000000..1364ca595ee
--- /dev/null
+++ b/code/controllers/README.md
@@ -0,0 +1,13 @@
+# Controllers
+
+Backend controllers orchestrating the game.
+
+## Globals
+
+Many, but not all, controllers are accessible from anywhere in the code with standardized names.
+
+- Master: As the name implies, the Master Controller performs init, shutdown, and acts as a process scheduler during a round.
+- Failsafe: A controller that ensures the Master Controller is running properly.
+- Configuration: A global datum that holds server configuration.
+- RSname: Repository controllers storing /datum/prototype's that can be queried.
+- SSname: Subsystems that handle init behavior, ticking, and other game functions..
diff --git a/code/controllers/configuration/configuration.dm b/code/controllers/configuration/configuration.dm
index b933dea3bd4..5474503030a 100644
--- a/code/controllers/configuration/configuration.dm
+++ b/code/controllers/configuration/configuration.dm
@@ -8,19 +8,6 @@
var/list/entries
var/list/entries_by_type
- // var/list/maplist
- // var/datum/map_config/defaultmap
-
- /*
- var/list/modes // allowed modes
- var/list/gamemode_cache
- var/list/votable_modes // votable modes
- var/list/storyteller_cache
- var/list/mode_names
- var/list/mode_reports
- var/list/mode_false_report_weight
- */
-
var/motd
/// If the configuration is loaded
@@ -59,7 +46,7 @@
loaded = TRUE
if (Master)
- Master.OnConfigLoad()
+ Master.on_config_loaded()
/datum/controller/configuration/proc/full_wipe()
if(IsAdminAdvancedProcCall())
diff --git a/code/controllers/configuration/entries/database.dm b/code/controllers/configuration/entries/database.dm
index 3fbc32d38fe..f930d31acbf 100644
--- a/code/controllers/configuration/entries/database.dm
+++ b/code/controllers/configuration/entries/database.dm
@@ -4,9 +4,6 @@
/datum/config_entry/string/sql_server_prefix
protection = CONFIG_ENTRY_LOCKED
-/datum/config_entry/string/sql_unified_prefix
- protection = CONFIG_ENTRY_LOCKED
-
/datum/config_entry/string/sql_address
protection = CONFIG_ENTRY_HIDDEN | CONFIG_ENTRY_LOCKED
config_entry_value = "localhost"
diff --git a/code/controllers/controller.dm b/code/controllers/controller.dm
index 93d5897ff45..252845318f5 100644
--- a/code/controllers/controller.dm
+++ b/code/controllers/controller.dm
@@ -15,6 +15,9 @@
// todo: kil
var/verbose_logging = FALSE
+/datum/controller/vv_delete()
+ return FALSE
+
/**
* Called to initialize a controller.
*
diff --git a/code/controllers/master.dm b/code/controllers/master.dm
index 7d0c002dad7..60a8334a375 100644
--- a/code/controllers/master.dm
+++ b/code/controllers/master.dm
@@ -117,6 +117,9 @@ GLOBAL_REAL(Master, /datum/controller/master) = new
load_configuration()
if(!config)
config = new
+ if(!Configuration)
+ Configuration = new
+ Configuration.Initialize()
//# 2. set up random seed
if(!random_seed)
@@ -883,10 +886,12 @@ GLOBAL_REAL(Master, /datum/controller/master) = new
var/datum/controller/subsystem/SS = S
SS.StopLoadingMap()
-/datum/controller/master/proc/OnConfigLoad()
+/datum/controller/master/proc/on_config_loaded()
for (var/thing in subsystems)
var/datum/controller/subsystem/SS = thing
- SS.OnConfigLoad()
+ SS.on_config_loaded()
+ for(var/datum/controller/repository/repository in SSrepository.get_all_repositories())
+ repository.on_config_loaded()
/**
* CitRP snowflake special: Check if any subsystems are sleeping.
diff --git a/code/controllers/repository.dm b/code/controllers/repository.dm
index 402a48e30dd..a53aa8e7ffc 100644
--- a/code/controllers/repository.dm
+++ b/code/controllers/repository.dm
@@ -26,6 +26,17 @@
/// expected type of prototype
var/expected_type
+ /// database key; this is immutable.
+ /// * persistence is disabled if this is not set
+ var/database_key
+ /// store version
+ /// * persistence is disabled if this is not set
+ /// * migration is triggered if this doesn't match a loaded entry
+ /// * this should only ever be incremented.
+ var/store_version
+ /// store enabled? Updated by config reloads.
+ var/store_enabled = FALSE
+
/// by-id lookup
var/list/id_lookup
/// by-type lookup
@@ -34,6 +45,11 @@
/// fetched subtype lists
var/tmp/list/subtype_lists
+ /// 'doesn't exist' cache for DB loads
+ var/tmp/list/doesnt_exist_cache
+ var/const/doesnt_exist_cache_trim_at = 1000
+ var/const/doesnt_exist_cache_trim_to = 500
+
/// temporary id to path lookup used during init
// todo: figure out a way to not do this, this is bad
var/tmp/list/init_reverse_lookup_shim
@@ -43,6 +59,7 @@
type_lookup = list()
subtype_lists = list()
init_reverse_lookup_shim = list()
+ doesnt_exist_cache = list()
for(var/datum/prototype/casted as anything in subtypesof(expected_type))
if(initial(casted.abstract_type) == casted)
continue
@@ -57,6 +74,14 @@
init_reverse_lookup_shim = null
return ..()
+/datum/controller/repository/vv_edit_var(var_name, var_value, mass_edit, raw_edit)
+ switch(var_name)
+ if(NAMEOF(src, store_version), NAMEOF(src, database_key), NAMEOF(src, store_enabled))
+ return FALSE
+ if(NAMEOF(src, expected_type))
+ return FALSE
+ return ..()
+
/**
* Repository Recover()
*
@@ -82,6 +107,13 @@
. = FALSE
src.subtype_lists = list()
+/**
+ * Called when config is reloaded.
+ */
+/datum/controller/repository/proc/on_config_loaded()
+ SHOULD_CALL_PARENT(TRUE)
+ store_enabled = Configuration.get_entry(/datum/toml_config_entry/backend/repository/persistence) && database_key && store_version
+
/**
* regenerates entries, kicking out anything that's in the way
*/
@@ -105,6 +137,7 @@
*
* * Allows passing in a prototype instance which will be returned as itself.
* Useful for procs that should accept types, IDs, *and* instances.
+ * * Unlike fetch local / fetch or defer, this **can** sleep!
*
* prototypes returned should never, ever be modified
*
@@ -119,7 +152,102 @@
if(init_reverse_lookup_shim)
var/potential_path = init_reverse_lookup_shim[type_or_id]
return fetch(potential_path)
- return id_lookup[type_or_id]
+ . = id_lookup[type_or_id]
+ if(.)
+ return
+ if(!store_enabled)
+ return
+ if(doesnt_exist_cache[type_or_id])
+ return
+ return handle_db_load(type_or_id)
+ else if(ispath(type_or_id))
+ . = type_lookup[type_or_id]
+ if(.)
+ return
+ if(initial(type_or_id.abstract_type) == type_or_id)
+ CRASH("tried to fetch an abstract prototype")
+ var/datum/prototype/loading = new type_or_id
+ loading.hardcoded = TRUE
+ load(loading)
+ return loading
+ else if(istype(type_or_id))
+ return type_or_id
+ else
+ CRASH("what?")
+
+/**
+ * Fetches a prototype by type or ID.
+ *
+ * * Allows passing in a prototype instance which will be returned as itself.
+ * Useful for procs that should accept types, IDs, *and* instances.
+ * * If something doesn't exist and we don't know if it exists in the database, we throw a runtime error.
+ * * If fetching a hardcoded path, this should generally be used as it never sleeps.
+ *
+ * prototypes returned should never, ever be modified
+ *
+ * @return prototype instance or null
+ */
+/datum/controller/repository/proc/fetch_local_or_throw(datum/prototype/type_or_id) as /datum/prototype
+ RETURN_TYPE(/datum/prototype)
+ // todo: optimize
+ if(isnull(type_or_id))
+ return
+ else if(istext(type_or_id))
+ if(init_reverse_lookup_shim)
+ var/potential_path = init_reverse_lookup_shim[type_or_id]
+ return fetch_local_or_throw(potential_path)
+ . = id_lookup[type_or_id]
+ if(.)
+ return
+ if(!store_enabled)
+ return
+ if(doesnt_exist_cache[type_or_id])
+ return
+ CRASH("fetch_local_or_throw of [type_or_id] couldn't determine if id existed without a fetch.")
+ else if(ispath(type_or_id))
+ . = type_lookup[type_or_id]
+ if(.)
+ return
+ if(initial(type_or_id.abstract_type) == type_or_id)
+ CRASH("tried to fetch an abstract prototype")
+ var/datum/prototype/loading = new type_or_id
+ loading.hardcoded = TRUE
+ load(loading)
+ return loading
+ else if(istype(type_or_id))
+ return type_or_id
+ else
+ CRASH("what?")
+
+/**
+ * Fetches a prototype by type or ID.
+ *
+ * * Allows passing in a prototype instance which will be returned as itself.
+ * Useful for procs that should accept types, IDs, *and* instances.
+ * * If something doesn't exist and we don't know if it exists in the database, we return
+ * REPOSITORY_FETCH_DEFER. The caller should invoke normal fetch() at a time when sleeping is allowed.
+ *
+ * prototypes returned should never, ever be modified
+ *
+ * @return prototype instance or null
+ */
+/datum/controller/repository/proc/fetch_or_defer(datum/prototype/type_or_id) as /datum/prototype
+ RETURN_TYPE(/datum/prototype)
+ // todo: optimize
+ if(isnull(type_or_id))
+ return
+ else if(istext(type_or_id))
+ if(init_reverse_lookup_shim)
+ var/potential_path = init_reverse_lookup_shim[type_or_id]
+ return fetch_or_defer(potential_path)
+ . = id_lookup[type_or_id]
+ if(.)
+ return
+ if(!store_enabled)
+ return
+ if(doesnt_exist_cache[type_or_id])
+ return
+ return REPOSITORY_FETCH_DEFER
else if(ispath(type_or_id))
. = type_lookup[type_or_id]
if(.)
@@ -165,7 +293,7 @@
for(var/datum/prototype/casted as anything in subtypesof(path))
if(initial(casted.abstract_type) == casted)
continue
- var/datum/prototype/instance = fetch(casted)
+ var/datum/prototype/instance = fetch_local_or_throw(casted)
generating += instance
return generating
@@ -184,7 +312,11 @@
* After this call, the repository now owns the instance, not whichever system created it.
*/
/datum/controller/repository/proc/register(datum/prototype/instance)
- return load(instance)
+ . = load(instance)
+ if(!.)
+ return
+ if(store_enabled)
+ handle_db_store(instance)
//* Private API *//
@@ -203,7 +335,7 @@
CRASH("attempted to load an instance that collides with a currently loaded instance on type.")
if(!instance.register())
. = FALSE
- CRASH("instance refused to unregister. this is undefined behavior.")
+ CRASH("instance failed to register. this is undefined behavior.")
id_lookup[instance.id] = instance
if(instance.hardcoded)
// invalidate cache
@@ -222,7 +354,7 @@
PROTECTED_PROC(TRUE)
if(!instance.unregister())
. = FALSE
- CRASH("instance refused to unregister. this is undefined behavior.")
+ CRASH("instance failed to unregister. this is undefined behavior.")
id_lookup -= instance.id
if(instance.hardcoded)
// invalidate cache
@@ -230,3 +362,90 @@
subtype_lists = list()
type_lookup -= instance.type
return TRUE
+
+/**
+ * Perform migration on a data-list from the database.
+ *
+ * * Edit the passed in list directly.
+ * * This should update to latest.
+ *
+ * todo: proc to auto-migrate everything.
+ */
+/datum/controller/repository/proc/migrate(list/modifying, from_version)
+ PROTECTED_PROC(TRUE)
+
+/datum/controller/repository/proc/handle_db_store(datum/prototype/instance)
+ doesnt_exist_cache -= instance.id
+
+ // intentionally allow admin proccalls to bypass checks in NewQuery()
+ var/old_usr = usr
+ usr = null
+
+ var/datum/db_query/store_query = SSdbcore.NewQuery(
+ "INSERT INTO " + DB_PREFIX_TABLE_NAME("backend_repository") + "(repository, id, version, data) VALUES \
+ (:repo, :id, :version, :data) ON DUPLICATE KEY UPDATE data = :data, modifiedTime = Now(), version = :version",
+ list(
+ "repo" = database_key,
+ "id" = instance.id,
+ "version" = store_version,
+ "data" = json_encode(instance.serialize()),
+ ),
+ )
+
+ usr = old_usr
+
+ store_query.Execute(TRUE)
+ qdel(store_query)
+
+/datum/controller/repository/proc/handle_db_load(instance_id)
+ if(doesnt_exist_cache[instance_id])
+ return
+
+ // intentionally allow admin proccalls to bypass checks in NewQuery()
+ var/old_usr = usr
+ usr = null
+
+ var/datum/db_query/load_query = SSdbcore.NewQuery(
+ "SELECT version, data FROM " + DB_PREFIX_TABLE_NAME("backend_repository") + " WHERE repository = :repo, id = :id",
+ list(
+ "repo" = database_key,
+ "id" = instance_id,
+ ),
+ )
+
+ usr = old_usr
+
+ load_query.Execute(TRUE)
+
+ if(!length(load_query.item))
+ mark_doesnt_exist(instance_id)
+ else
+ var/list/fetched = load_query.item[1]
+ var/version = fetched[1]
+ var/encoded_data = fetched[2]
+ var/list/decoded_data = json_decode(encoded_data)
+ var/migrated = FALSE
+
+ if(version < store_version)
+ migrate(decoded_data, version)
+ migrated = TRUE
+ else if(version == store_version)
+ mark_doesnt_exist(instance_id)
+ CRASH("[version] was not less or eq to [store_version]. something's very wrong!")
+
+ var/datum/prototype/loaded_instance = new expected_type
+ loaded_instance.deserialize(decoded_data)
+ if(!load(loaded_instance))
+ mark_doesnt_exist(instance_id)
+ CRASH("[instance_id] failed to load into the repository during database load!")
+ . = loaded_instance
+
+ if(migrated)
+ handle_db_store(loaded_instance)
+
+ qdel(load_query)
+
+/datum/controller/repository/proc/mark_doesnt_exist(instance_id)
+ doesnt_exist_cache[instance_id] = TRUE
+ if(length(doesnt_exist_cache) > doesnt_exist_cache_trim_at)
+ doesnt_exist_cache.len = doesnt_exist_cache_trim_to
diff --git a/code/controllers/repository/designs.dm b/code/controllers/repository/designs.dm
index 23ed3186a24..2667472b765 100644
--- a/code/controllers/repository/designs.dm
+++ b/code/controllers/repository/designs.dm
@@ -4,6 +4,7 @@
REPOSITORY_DEF(designs)
name = "Repository - Designs"
expected_type = /datum/prototype/design
+ database_key = "design"
//* caches *//
diff --git a/code/controllers/repository/guidebook.dm b/code/controllers/repository/guidebook.dm
index f5ea86eb187..33c878a9fb7 100644
--- a/code/controllers/repository/guidebook.dm
+++ b/code/controllers/repository/guidebook.dm
@@ -1,6 +1,7 @@
//* This file is explicitly licensed under the MIT license. *//
//* Copyright (c) 2023 Citadel Station developers. *//
+// todo: this shouldn't be a repository, it can just be a controller
REPOSITORY_DEF(guidebook)
name = "Repository - Guidebook"
expected_type = /datum/prototype/guidebook_section
diff --git a/code/controllers/subsystem.dm b/code/controllers/subsystem.dm
index bf1333d28b4..3287b34004f 100644
--- a/code/controllers/subsystem.dm
+++ b/code/controllers/subsystem.dm
@@ -421,7 +421,7 @@
state = SS_PAUSING
/// Called after the config has been loaded or reloaded.
-/datum/controller/subsystem/proc/OnConfigLoad()
+/datum/controller/subsystem/proc/on_config_loaded()
return
/**
diff --git a/code/controllers/subsystem/assets.dm b/code/controllers/subsystem/assets.dm
index eff83427a20..ff29b03f16e 100644
--- a/code/controllers/subsystem/assets.dm
+++ b/code/controllers/subsystem/assets.dm
@@ -191,7 +191,7 @@ SUBSYSTEM_DEF(assets)
/datum/controller/subsystem/assets/proc/get_dynamic_item_url_by_name(name)
return dynamic_asset_items_by_name[name]?.get_url()
-/datum/controller/subsystem/assets/OnConfigLoad()
+/datum/controller/subsystem/assets/on_config_loaded()
var/newtransporttype = /datum/asset_transport/browse_rsc
switch (CONFIG_GET(string/asset_transport))
if ("webroot")
diff --git a/code/controllers/subsystem/characters/storage.dm b/code/controllers/subsystem/characters/storage.dm
index 5a1b6045010..bb84401ee12 100644
--- a/code/controllers/subsystem/characters/storage.dm
+++ b/code/controllers/subsystem/characters/storage.dm
@@ -33,7 +33,7 @@
// last played is not updated by this proc
// everything else can though!
var/datum/db_query/update_query = SSdbcore.NewQuery(
- "UPDATE [format_table_name("character")] \
+ "UPDATE [DB_PREFIX_TABLE_NAME("character")] \
SET[persisting? " last_persisted = NOW()," : ""] canonical_name = :name, persist_data = :data, \
playerid = :pid \
WHERE id = :id",
@@ -48,7 +48,7 @@
qdel(update_query)
else
var/datum/db_query/insert_query = SSdbcore.NewQuery(
- "INSERT INTO [format_table_name("character")] \
+ "INSERT INTO [DB_PREFIX_TABLE_NAME("character")] \
(`created`, `last_played`, `last_persisted`, `playerid`, `canonical_name`, \
`persist_data`, `character_type`) \
VALUES (NOW(), NULL, [persisting? "NOW" : "NULL"], :pid, :name, :data, :type)",
@@ -85,7 +85,7 @@
var/datum/db_query/load_query = SSdbcore.NewQuery(
"SELECT `id` FROM \
- [format_table_name("character")] WHERE playerid = :id AND canonical_name = :name AND character_type = :type",
+ [DB_PREFIX_TABLE_NAME("character")] WHERE playerid = :id AND canonical_name = :name AND character_type = :type",
list(
"id" = playerid,
"canonical_name" = name,
@@ -134,7 +134,7 @@
var/datum/db_query/load_query = SSdbcore.NewQuery(
"SELECT `created`, `last_played`, `last_persisted`, `playerid`, `canonical_name`, `persist_data`, `character_type` FROM \
- [format_table_name("character")] WHERE id = :id",
+ [DB_PREFIX_TABLE_NAME("character")] WHERE id = :id",
list(
"id" = id,
)
@@ -190,7 +190,7 @@
. = list()
var/datum/db_query/iteration_query = SSdbcore.ExecuteQuery(
- "SELECT id FROM [format_table_name("character")] WHERE playerid = :id",
+ "SELECT id FROM [DB_PREFIX_TABLE_NAME("character")] WHERE playerid = :id",
list(
"id" = playerid
)
@@ -223,7 +223,7 @@
// section below can never be allowed to runtime
var/datum/db_query/mark_query = SSdbcore.ExecuteQuery(
- "UPDATE [format_table_name("character")] SET last_played = NOW() WHERE id = :id",
+ "UPDATE [DB_PREFIX_TABLE_NAME("character")] SET last_played = NOW() WHERE id = :id",
list(
"id" = id
)
diff --git a/code/controllers/subsystem/dbcore/_dbcore.dm b/code/controllers/subsystem/dbcore/_dbcore.dm
index 106a7fe0911..7e2b57d43fe 100644
--- a/code/controllers/subsystem/dbcore/_dbcore.dm
+++ b/code/controllers/subsystem/dbcore/_dbcore.dm
@@ -46,7 +46,7 @@ SUBSYSTEM_DEF(dbcore)
//This is as close as we can get to the true round end before Disconnect() without changing where it's called, defeating the reason this is a subsystem
if(SSdbcore.Connect())
var/datum/db_query/query_round_shutdown = SSdbcore.NewQuery(
- "UPDATE [format_table_name("round")] SET shutdown_datetime = Now() WHERE id = :round_id",
+ "UPDATE [DB_PREFIX_TABLE_NAME("round")] SET shutdown_datetime = Now() WHERE id = :round_id",
list("round_id" = GLOB.round_id)
)
query_round_shutdown.Execute()
@@ -114,7 +114,7 @@ SUBSYSTEM_DEF(dbcore)
if(CONFIG_GET(flag/sql_enabled))
if(Connect())
log_world("Database connection established.")
- var/datum/db_query/query_db_version = NewQuery("SELECT major, minor FROM [format_table_name("schema_revision")] ORDER BY date DESC LIMIT 1")
+ var/datum/db_query/query_db_version = NewQuery("SELECT major, minor FROM [DB_PREFIX_TABLE_NAME("schema_revision")] ORDER BY date DESC LIMIT 1")
query_db_version.Execute()
if(query_db_version.NextRow())
db_major = text2num(query_db_version.item[1])
@@ -135,7 +135,7 @@ SUBSYSTEM_DEF(dbcore)
if(!Connect())
return
var/datum/db_query/query_round_initialize = SSdbcore.NewQuery(
- "INSERT INTO [format_table_name("round")] (initialize_datetime, server_ip, server_port) VALUES (Now(), INET_ATON(:internet_address), :port)",
+ "INSERT INTO [DB_PREFIX_TABLE_NAME("round")] (initialize_datetime, server_ip, server_port) VALUES (Now(), INET_ATON(:internet_address), :port)",
list("internet_address" = world.internet_address || "0", "port" = "[world.port]")
)
query_round_initialize.Execute(async = FALSE)
@@ -147,7 +147,7 @@ SUBSYSTEM_DEF(dbcore)
if(!Connect())
return
var/datum/db_query/query_round_start = SSdbcore.NewQuery(
- "UPDATE [format_table_name("round")] SET start_datetime = Now() WHERE id = :round_id",
+ "UPDATE [DB_PREFIX_TABLE_NAME("round")] SET start_datetime = Now() WHERE id = :round_id",
list("round_id" = GLOB.round_id)
)
query_round_start.Execute()
@@ -157,7 +157,7 @@ SUBSYSTEM_DEF(dbcore)
if(!Connect())
return
var/datum/db_query/query_round_end = SSdbcore.NewQuery(
- "UPDATE [format_table_name("round")] SET end_datetime = Now() WHERE id = :round_id",
+ "UPDATE [DB_PREFIX_TABLE_NAME("round")] SET end_datetime = Now() WHERE id = :round_id",
list("round_id" = GLOB.round_id)
)
query_round_end.Execute()
diff --git a/code/controllers/subsystem/ipintel.dm b/code/controllers/subsystem/ipintel.dm
index 170e520e4cf..e0f1dfd5cbb 100644
--- a/code/controllers/subsystem/ipintel.dm
+++ b/code/controllers/subsystem/ipintel.dm
@@ -20,7 +20,7 @@ SUBSYSTEM_DEF(ipintel)
/// max retries
var/max_retries = 1
-/datum/controller/subsystem/ipintel/OnConfigLoad()
+/datum/controller/subsystem/ipintel/on_config_loaded()
. = ..()
enabled = !!CONFIG_GET(flag/ipintel_enabled)
consequetive_errors = 0
@@ -139,7 +139,7 @@ SUBSYSTEM_DEF(ipintel)
/datum/controller/subsystem/ipintel/proc/ipintel_cache_fetch_impl(address)
PRIVATE_PROC(TRUE)
var/datum/db_query/fetch = SSdbcore.NewQuery(
- "SELECT date, intel, TIMESTAMPDIFF(MINUTE,date,NOW()) FROM [format_table_name("ipintel")] WHERE ip = INET_ATON(:ip)",
+ "SELECT date, intel, TIMESTAMPDIFF(MINUTE,date,NOW()) FROM [DB_PREFIX_TABLE_NAME("ipintel")] WHERE ip = INET_ATON(:ip)",
list(
"ip" = address,
)
@@ -167,7 +167,7 @@ SUBSYSTEM_DEF(ipintel)
/datum/controller/subsystem/ipintel/proc/ipintel_cache_store_impl(datum/ipintel/entry)
PRIVATE_PROC(TRUE)
var/datum/db_query/update = SSdbcore.NewQuery(
- "INSERT INTO [format_table_name("ipintel")] (ip, intel) VALUES (INET_ATON(:ip), :intel) \
+ "INSERT INTO [DB_PREFIX_TABLE_NAME("ipintel")] (ip, intel) VALUES (INET_ATON(:ip), :intel) \
ON DUPLICATE KEY UPDATE intel = VALUES(intel), date = NOW()",
list(
"ip" = entry.address,
diff --git a/code/controllers/subsystem/materials.dm b/code/controllers/subsystem/materials.dm
index 4cd8fae0414..edd53d80467 100644
--- a/code/controllers/subsystem/materials.dm
+++ b/code/controllers/subsystem/materials.dm
@@ -108,12 +108,16 @@ SUBSYSTEM_DEF(materials)
// todo: optimize
. = list()
for(var/i in 1 to length(L))
- var/key = L[i]
- var/datum/prototype/material/resolved = RSmaterials.fetch(key)
- if(isnull(resolved))
- continue
+ var/datum/prototype/material/key = L[i]
var/value = L[key]
- .[resolved.id] = value
+ if(istype(key))
+ key = key.id
+ else if(ispath(key))
+ key = initial(key.id)
+ else if(istext(key))
+ else
+ CRASH("what? '[key]'")
+ .[key] = value
/**
* ensures a list is full of material references for keys
@@ -126,10 +130,14 @@ SUBSYSTEM_DEF(materials)
. = list()
for(var/i in 1 to length(L))
var/key = L[i]
- var/datum/prototype/material/resolved = RSmaterials.fetch(key)
- if(isnull(resolved))
- continue
var/value = L[key]
+ var/datum/prototype/material/resolved = RSmaterials.fetch_or_defer(key)
+ switch(resolved)
+ if(null)
+ continue
+ if(REPOSITORY_FETCH_DEFER)
+ // todo: handle this
+ continue
.[resolved] = value
/**
@@ -142,9 +150,15 @@ SUBSYSTEM_DEF(materials)
. = list()
for(var/i in 1 to length(L))
var/key = L[i]
- var/value = L[key]
- var/datum/prototype/material/resolved = RSmaterials.fetch(value)
- .[key] = resolved?.id
+ var/datum/prototype/material/value = L[key]
+ if(istype(value))
+ value = value.id
+ else if(ispath(value))
+ value = initial(value.id)
+ else if(istext(value))
+ else
+ CRASH("what? '[value]'")
+ .[key] = value
/**
* ensures a list is full of material references for values
@@ -157,7 +171,12 @@ SUBSYSTEM_DEF(materials)
for(var/i in 1 to length(L))
var/key = L[i]
var/value = L[key]
- var/datum/prototype/material/resolved = RSmaterials.fetch(value)
+ var/datum/prototype/material/resolved = RSmaterials.fetch_or_defer(value)
+ switch(resolved)
+ if(REPOSITORY_FETCH_DEFER)
+ // todo: handle this
+ else
+ value = resolved
.[key] = resolved
/**
diff --git a/code/controllers/subsystem/persistence/modules/bulk_entity.dm b/code/controllers/subsystem/persistence/modules/bulk_entity.dm
index 7d04d37568e..a17d389e00b 100644
--- a/code/controllers/subsystem/persistence/modules/bulk_entity.dm
+++ b/code/controllers/subsystem/persistence/modules/bulk_entity.dm
@@ -19,7 +19,7 @@
for(var/datum/bulk_entity_chunk/chunk as anything in chunks)
var/datum/db_query/query = SSdbcore.NewQuery(
- "INSERT INTO [format_table_name("persistence_bulk_entity")] \
+ "INSERT INTO [DB_PREFIX_TABLE_NAME("persistence_bulk_entity")] \
(generation, persistence_key, level_id, data, round_id) \
VALUES (:generation, :persistence, :level, :data, :round)",
list(
@@ -47,7 +47,7 @@
usr = null
var/datum/db_query/query = SSdbcore.NewQuery(
- "SELECT data FROM [format_table_name("persistence_bulk_entity")] \
+ "SELECT data FROM [DB_PREFIX_TABLE_NAME("persistence_bulk_entity")] \
WHERE generation = :generation AND persistence_key = :persistence AND level_id = :level",
list(
"generation" = generation,
@@ -85,7 +85,7 @@
SSdbcore.dangerously_block_on_multiple_unsanitized_queries(
list(
- "TRUNCATE TABLE [format_table_name("persistence_bulk_entity")]",
+ "TRUNCATE TABLE [DB_PREFIX_TABLE_NAME("persistence_bulk_entity")]",
),
)
@@ -99,7 +99,7 @@
usr = null
SSdbcore.RunQuery(
- "DELETE FROM [format_table_name("persistence_bulk_entity")] WHERE level_id = :level",
+ "DELETE FROM [DB_PREFIX_TABLE_NAME("persistence_bulk_entity")] WHERE level_id = :level",
list(
"level" = level_id,
),
diff --git a/code/controllers/subsystem/persistence/modules/level_objects.dm b/code/controllers/subsystem/persistence/modules/level_objects.dm
index 43072527d78..8016594e631 100644
--- a/code/controllers/subsystem/persistence/modules/level_objects.dm
+++ b/code/controllers/subsystem/persistence/modules/level_objects.dm
@@ -20,7 +20,7 @@
switch(entity.obj_persist_static_mode)
if(OBJ_PERSIST_STATIC_MODE_LEVEL)
query = SSdbcore.NewQuery(
- "INSERT INTO [format_table_name("persistence_static_level_objects")] (generation, object_id, level_id, data) \
+ "INSERT INTO [DB_PREFIX_TABLE_NAME("persistence_static_level_objects")] (generation, object_id, level_id, data) \
VALUES (:generation, :object_id, :level_id, :data) ON DUPLICATE KEY UPDATE \
data = VALUES(data)",
list(
@@ -32,7 +32,7 @@
)
if(OBJ_PERSIST_STATIC_MODE_MAP)
query = SSdbcore.NewQuery(
- "INSERT INTO [format_table_name("persistence_static_map_objects")] (generation, object_id, map_id, data) \
+ "INSERT INTO [DB_PREFIX_TABLE_NAME("persistence_static_map_objects")] (generation, object_id, map_id, data) \
VALUES (:generation, :object_id, :map_id, :data) ON DUPLICATE KEY UPDATE \
data = VALUES(data)",
list(
@@ -44,7 +44,7 @@
)
if(OBJ_PERSIST_STATIC_MODE_GLOBAL)
query = SSdbcore.NewQuery(
- "INSERT INTO [format_table_name("persistence_static_global_objects")] (generation, object_id, data) \
+ "INSERT INTO [DB_PREFIX_TABLE_NAME("persistence_static_global_objects")] (generation, object_id, data) \
VALUES (:generation, :object_id, :data) ON DUPLICATE KEY UPDATE \
data = VALUES(data)",
list(
@@ -79,7 +79,7 @@
var/datum/db_query/query
if(entity.obj_persist_dynamic_id != PERSISTENCE_DYNAMIC_ID_AUTOSET)
query = SSdbcore.NewQuery(
- "INSERT INTO [format_table_name("persistence_dynamic_objects")] (id, generation, status, data, prototype_id, level_id, x, y) \
+ "INSERT INTO [DB_PREFIX_TABLE_NAME("persistence_dynamic_objects")] (id, generation, status, data, prototype_id, level_id, x, y) \
VALUES (:status, :data, :prototype, :level, :x, :y) ON DUPLICATE KEY UPDATE \
x = VALUES(x), y = VALUES(y), data = VALUES(data), prototype = VALUES(prototype), level = VALUES(level), \
status = VALUES(status)",
@@ -97,7 +97,7 @@
query.warn_execute()
else
query = SSdbcore.NewQuery(
- "INSERT INTO [format_table_name("persistence_dynamic_objects")] (status, data, prototype_id, level_id, x, y) \
+ "INSERT INTO [DB_PREFIX_TABLE_NAME("persistence_dynamic_objects")] (status, data, prototype_id, level_id, x, y) \
VALUES (:status, :data, :prototype, :level, :x, :y)",
list(
"status" = entity.obj_persist_dynamic_status,
@@ -139,7 +139,7 @@
var/datum/db_query/query = SSdbcore.NewQuery(
"SELECT object_id, prototype_id, status, data, x, y \
- FROM [format_table_name("persistence_dynamic_objects")] \
+ FROM [DB_PREFIX_TABLE_NAME("persistence_dynamic_objects")] \
WHERE level_id = :level AND generation = :generation",
list(
"generation" = generation,
@@ -200,7 +200,7 @@
switch(entity.obj_persist_static_mode)
if(OBJ_PERSIST_STATIC_MODE_GLOBAL)
query = SSdbcore.NewQuery(
- "SELECT data FROM [format_table_name("persistence_static_global_objects")] \
+ "SELECT data FROM [DB_PREFIX_TABLE_NAME("persistence_static_global_objects")] \
WHERE object_id = :object AND generation = :generation",
list(
"object" = entity.obj_persist_static_id,
@@ -209,7 +209,7 @@
)
if(OBJ_PERSIST_STATIC_MODE_LEVEL)
query = SSdbcore.NewQuery(
- "SELECT data FROM [format_table_name("persistence_static_level_objects")] \
+ "SELECT data FROM [DB_PREFIX_TABLE_NAME("persistence_static_level_objects")] \
WHERE object_id = :object AND level_id = :level AND generation = :generation",
list(
"object" = entity.obj_persist_static_id,
@@ -220,7 +220,7 @@
bind_id = level_id
if(OBJ_PERSIST_STATIC_MODE_MAP)
query = SSdbcore.NewQuery(
- "SELECT data FROM [format_table_name("persistence_static_map_objects")] \
+ "SELECT data FROM [DB_PREFIX_TABLE_NAME("persistence_static_map_objects")] \
WHERE object_id = :object AND map_id = :map AND generation = :generation",
list(
"object" = entity.obj_persist_static_id,
@@ -258,9 +258,9 @@
SSdbcore.dangerously_block_on_multiple_unsanitized_queries(
list(
- "TRUNCATE TABLE [format_table_name("persistence_static_map_objects")]",
- "TRUNCATE TABLE [format_table_name("persistence_static_level_objects")]",
- "TRUNCATE TABLE [format_table_name("persistence_static_global_objects")]",
+ "TRUNCATE TABLE [DB_PREFIX_TABLE_NAME("persistence_static_map_objects")]",
+ "TRUNCATE TABLE [DB_PREFIX_TABLE_NAME("persistence_static_level_objects")]",
+ "TRUNCATE TABLE [DB_PREFIX_TABLE_NAME("persistence_static_global_objects")]",
),
)
@@ -276,7 +276,7 @@
usr = null
SSdbcore.RunQuery(
- "DELETE FROM [format_table_name("persistence_static_level_objects")] WHERE level_id = :level",
+ "DELETE FROM [DB_PREFIX_TABLE_NAME("persistence_static_level_objects")] WHERE level_id = :level",
list(
"level" = level_id,
),
@@ -294,7 +294,7 @@
usr = null
SSdbcore.RunQuery(
- "DELETE FROM [format_table_name("persistence_static_map_objects")] WHERE map_id = :map",
+ "DELETE FROM [DB_PREFIX_TABLE_NAME("persistence_static_map_objects")] WHERE map_id = :map",
list(
"map" = map_id,
),
@@ -312,7 +312,7 @@
usr = null
SSdbcore.RunQuery(
- "DELETE FROM [format_table_name("persistence_static_global_objects")]",
+ "DELETE FROM [DB_PREFIX_TABLE_NAME("persistence_static_global_objects")]",
)
usr = intentionally_allow_admin_proccall
@@ -327,7 +327,7 @@
usr = null
SSdbcore.RunQuery(
- "TRUNCATE TABLE [format_table_name("persistence_dynamic_objects")]",
+ "TRUNCATE TABLE [DB_PREFIX_TABLE_NAME("persistence_dynamic_objects")]",
)
usr = intentionally_allow_admin_proccall
@@ -342,7 +342,7 @@
usr = null
SSdbcore.RunQuery(
- "DELETE FROM [format_table_name("persistence_dynamic_objects")] WHERE level_id = :level",
+ "DELETE FROM [DB_PREFIX_TABLE_NAME("persistence_dynamic_objects")] WHERE level_id = :level",
list(
"level" = level_id,
),
diff --git a/code/controllers/subsystem/persistence/modules/spatial_metadata.dm b/code/controllers/subsystem/persistence/modules/spatial_metadata.dm
index 8318e210040..22d8c1a1b4b 100644
--- a/code/controllers/subsystem/persistence/modules/spatial_metadata.dm
+++ b/code/controllers/subsystem/persistence/modules/spatial_metadata.dm
@@ -66,7 +66,7 @@
var/datum/db_query/query = SSdbcore.NewQuery(
"SELECT TIMESTAMPDIFF(HOUR, saved, NOW()), saved_round_id, data, generation \
- FROM [format_table_name("persistence_level_metadata")] \
+ FROM [DB_PREFIX_TABLE_NAME("persistence_level_metadata")] \
WHERE level_id = :level",
list(
"level" = level_id,
@@ -103,7 +103,7 @@
src.round_id_saved = GLOB.round_number
SSdbcore.RunQuery(
- "INSERT INTO [format_table_name("persistence_level_metadata")] (saved, saved_round_id, level_id, data, generation) \
+ "INSERT INTO [DB_PREFIX_TABLE_NAME("persistence_level_metadata")] (saved, saved_round_id, level_id, data, generation) \
VALUES (Now(), :round, :level, :data, :generation) ON DUPLICATE KEY UPDATE \
data = VALUES(data), generation = VALUES(generation), saved_round_id = VALUES(saved_round_id), saved = VALUES(saved)",
list(
diff --git a/code/controllers/subsystem/persistence/modules/string_kkv.dm b/code/controllers/subsystem/persistence/modules/string_kkv.dm
index 6ae51d36a22..66b1ff79468 100644
--- a/code/controllers/subsystem/persistence/modules/string_kkv.dm
+++ b/code/controllers/subsystem/persistence/modules/string_kkv.dm
@@ -60,7 +60,7 @@
var/oldusr = usr
usr = null
var/datum/db_query/query = SSdbcore.NewQuery(
- "SELECT `value` FROM [format_table_name("persistence_string_kkv")] WHERE `group` = :group AND `key` = :key",
+ "SELECT `value` FROM [DB_PREFIX_TABLE_NAME("persistence_string_kkv")] WHERE `group` = :group AND `key` = :key",
list(
"group" = group,
"key" = key
@@ -79,7 +79,7 @@
var/oldusr = usr
usr = null
var/datum/db_query/query = SSdbcore.NewQuery(
- "INSERT INTO [format_table_name("persistence_string_kkv")] (`group`, `key`, `value`) VALUES (:group, :key, :value) ON DUPLICATE KEY UPDATE `value` = VALUES(`value`), `modified` = Now(), `revision` = `revision` + 1",
+ "INSERT INTO [DB_PREFIX_TABLE_NAME("persistence_string_kkv")] (`group`, `key`, `value`) VALUES (:group, :key, :value) ON DUPLICATE KEY UPDATE `value` = VALUES(`value`), `modified` = Now(), `revision` = `revision` + 1",
list(
"group" = group,
"key" = key,
diff --git a/code/controllers/subsystem/persistence/world.dm b/code/controllers/subsystem/persistence/world.dm
index 30ec4b2cfd2..e1f82acdc8d 100644
--- a/code/controllers/subsystem/persistence/world.dm
+++ b/code/controllers/subsystem/persistence/world.dm
@@ -234,21 +234,21 @@
for(var/datum/map_level_persistence/level_metadata as anything in ordered_level_metadata)
SSdbcore.RunQuery(
- "DELETE FROM [format_table_name("persistence_bulk_entity")] WHERE level_id = :level, generation != :generation",
+ "DELETE FROM [DB_PREFIX_TABLE_NAME("persistence_bulk_entity")] WHERE level_id = :level, generation != :generation",
list(
"level" = level_metadata.level_id,
"generation" = level_metadata.generation,
),
)
SSdbcore.RunQuery(
- "DELETE FROM [format_table_name("persistence_static_level_objects")] WHERE level_id = :level, generation != :generation",
+ "DELETE FROM [DB_PREFIX_TABLE_NAME("persistence_static_level_objects")] WHERE level_id = :level, generation != :generation",
list(
"level" = level_metadata.level_id,
"generation" = level_metadata.generation,
),
)
SSdbcore.RunQuery(
- "DELETE FROM [format_table_name("persistence_dynamic_objects")] WHERE level_id = :level, generation != :generation",
+ "DELETE FROM [DB_PREFIX_TABLE_NAME("persistence_dynamic_objects")] WHERE level_id = :level, generation != :generation",
list(
"level" = level_metadata.level_id,
"generation" = level_metadata.generation,
diff --git a/code/controllers/subsystem/photography.dm b/code/controllers/subsystem/photography.dm
index 7e4fbbcbccd..37f23abe4c9 100644
--- a/code/controllers/subsystem/photography.dm
+++ b/code/controllers/subsystem/photography.dm
@@ -115,7 +115,7 @@ SUBSYSTEM_DEF(photography)
var/datum/db_query/query = SSdbcore.NewQuery(
{"
- INSERT INTO [format_table_name("pictures")]
+ INSERT INTO [DB_PREFIX_TABLE_NAME("pictures")]
(`hash`, `width`, `height`) VALUES
(:hash, :width, :height)
"},
@@ -140,7 +140,7 @@ SUBSYSTEM_DEF(photography)
var/datum/db_query/query = SSdbcore.NewQuery(
{"
SELECT `width`, `height`
- FROM [format_table_name("pictures")]
+ FROM [DB_PREFIX_TABLE_NAME("pictures")]
WHERE `hash` = :hash
"},
list(
@@ -195,7 +195,7 @@ SUBSYSTEM_DEF(photography)
var/datum/db_query/query = SSdbcore.NewQuery(
{"
- INSERT INTO [format_table_name("photographs")]
+ INSERT INTO [DB_PREFIX_TABLE_NAME("photographs")]
(`picture`, `scene`, `desc`) VALUES
(:hash, :scene, :desc)
"},
@@ -220,7 +220,7 @@ SUBSYSTEM_DEF(photography)
var/datum/db_query/query = SSdbcore.NewQuery(
{"
SELECT `picture`, `scene`, `desc`
- FROM [format_table_name("photographs")]
+ FROM [DB_PREFIX_TABLE_NAME("photographs")]
WHERE `id` = :id
"},
list(
diff --git a/code/controllers/subsystem/playtime.dm b/code/controllers/subsystem/playtime.dm
index 617cdbf0335..5f1d1c2ec22 100644
--- a/code/controllers/subsystem/playtime.dm
+++ b/code/controllers/subsystem/playtime.dm
@@ -46,7 +46,7 @@ SUBSYSTEM_DEF(playtime)
"player" = playerid
)
C.persistent.playtime_queued = list()
- SSdbcore.MassInsertLegacy(format_table_name("playtime"), built, duplicate_key = "ON DUPLICATE KEY UPDATE minutes = minutes + VALUES(minutes)")
+ SSdbcore.MassInsertLegacy(DB_PREFIX_TABLE_NAME("playtime"), built, duplicate_key = "ON DUPLICATE KEY UPDATE minutes = minutes + VALUES(minutes)")
/**
* returns a list of playtime roles
diff --git a/code/controllers/subsystem/repository.dm b/code/controllers/subsystem/repository.dm
index 04db037a497..4464288f229 100644
--- a/code/controllers/subsystem/repository.dm
+++ b/code/controllers/subsystem/repository.dm
@@ -11,3 +11,6 @@ SUBSYSTEM_DEF(repository)
__create_repositories()
__init_repositories()
return SS_INIT_SUCCESS
+
+/datum/controller/subsystem/repository/proc/get_all_repositories()
+ return __get_all_repositories()
diff --git a/code/controllers/subsystem/statpanel.dm b/code/controllers/subsystem/statpanel.dm
index 44f7944a2b9..5a204c1320d 100644
--- a/code/controllers/subsystem/statpanel.dm
+++ b/code/controllers/subsystem/statpanel.dm
@@ -89,6 +89,10 @@ SUBSYSTEM_DEF(statpanels)
STATPANEL_DATA_CLICK(config.stat_key(), config.stat_entry(), "\ref[config]")
else
STATPANEL_DATA_LINE("FATAL - NO CONFIG")
+ if(config)
+ STATPANEL_DATA_CLICK(Configuration.stat_key(), Configuration.stat_entry(), "\ref[Configuration]")
+ else
+ STATPANEL_DATA_LINE("FATAL - NO CONFIG (NEW)")
STATPANEL_DATA_ENTRY("BYOND:", "(FPS:[world.fps]) (TickCount:[world.time/world.tick_lag]) (TickDrift:[round(Master.tickdrift,1)]([round((Master.tickdrift/(world.time/world.tick_lag))*100,0.1)]%)) (Internal Tick Usage: [round(MAPTICK_LAST_INTERNAL_TICK_USAGE,0.1)]%)")
if(Master)
STATPANEL_DATA_CLICK(Master.stat_key(), Master.stat_entry(), "\ref[Master]")
diff --git a/code/controllers/toml_config/README.md b/code/controllers/toml_config/README.md
new file mode 100644
index 00000000000..025e5b593f1
--- /dev/null
+++ b/code/controllers/toml_config/README.md
@@ -0,0 +1,3 @@
+# Configuration Module
+
+Experimental new TOML configuration to replace old configuration with eventually.
diff --git a/code/controllers/toml_config/entries/backend.dm b/code/controllers/toml_config/entries/backend.dm
new file mode 100644
index 00000000000..25e66949ac3
--- /dev/null
+++ b/code/controllers/toml_config/entries/backend.dm
@@ -0,0 +1,6 @@
+//* This file is explicitly licensed under the MIT license. *//
+//* Copyright (c) 2024 Citadel Station Developers *//
+
+/datum/toml_config_entry/backend
+ abstract_type = /datum/toml_config_entry/backend
+ category = "backend"
diff --git a/code/controllers/toml_config/entries/backend.repository.dm b/code/controllers/toml_config/entries/backend.repository.dm
new file mode 100644
index 00000000000..9c812b38a10
--- /dev/null
+++ b/code/controllers/toml_config/entries/backend.repository.dm
@@ -0,0 +1,14 @@
+//* This file is explicitly licensed under the MIT license. *//
+//* Copyright (c) 2024 Citadel Station Developers *//
+
+/datum/toml_config_entry/backend/repository
+ abstract_type = /datum/toml_config_entry/backend/repository
+ category = "backend.repository"
+
+/datum/toml_config_entry/backend/repository/persistence
+ key = "persistence"
+ desc = {"
+ Enable repository persistence. This requires the database to be available. Without this, most persistence
+ features will not function.
+ "}
+ default = TRUE
diff --git a/code/controllers/toml_config/toml_config_entry.dm b/code/controllers/toml_config/toml_config_entry.dm
new file mode 100644
index 00000000000..88eb4e6039a
--- /dev/null
+++ b/code/controllers/toml_config/toml_config_entry.dm
@@ -0,0 +1,107 @@
+//* This file is explicitly licensed under the MIT license. *//
+//* Copyright (c) 2024 Citadel Station Developers *//
+
+/**
+ * Config entry.
+ *
+ * Supports at time of writing:
+ * * numbers
+ * * strings
+ * * (nested) lists
+ * * (nested) dictionaries
+ *
+ * Supports at time of writing auditing VV edits to:
+ * * numbers
+ * * strings
+ */
+/datum/toml_config_entry
+ abstract_type = /datum/toml_config_entry
+ /// key / name
+ var/key
+ /// category / where this is
+ var/category
+
+ /// description of this entry
+ var/desc
+
+ /// default value
+ var/default
+ /// current value
+ var/value
+
+ /// vv edit disallowed
+ /// * Does not stop get_entry and set_entry from setting our value. Those are not considered vv-protected.
+ var/vv_locked = FALSE
+ /// vv read disallowed
+ /// * Does not automatically imply [vv_locked].
+ /// * Does not stop get_entry and set_entry from pulling our value. Those are not considered vv-protected.
+ var/vv_secret = FALSE
+ /// sensitive
+ /// * Requires get_sensitive_entry() and set_sensitive_entry() to read/write.
+ /// * Does not actually imply [vv_locked] and [vv_secret].
+ var/sensitive = FALSE
+
+/datum/toml_config_entry/vv_edit_var(var_name, var_value, mass_edit, raw_edit)
+ switch(var_name)
+ if(NAMEOF(src, default))
+ return FALSE
+ if(NAMEOF(src, value))
+ if(vv_locked)
+ return FALSE
+ if(NAMEOF(src, key))
+ return FALSE
+ if(NAMEOF(src, category))
+ return FALSE
+ if(NAMEOF(src, desc))
+ return FALSE
+ if(NAMEOF(src, vv_locked))
+ return FALSE
+ if(NAMEOF(src, vv_secret))
+ return FALSE
+ if(NAMEOF(src, sensitive))
+ return FALSE
+ return ..()
+
+/datum/toml_config_entry/vv_get_var(var_name, resolve)
+ switch(var_name)
+ if(NAMEOF(src, value))
+ if(vv_locked)
+ return "-- secret --"
+ return ..()
+
+/datum/toml_config_entry/CanProcCall(procname)
+ switch(procname)
+ if(NAMEOF_PROC(src, New), NAMEOF_PROC(src, Destroy))
+ return FALSE
+ if(NAMEOF_PROC(src, reset))
+ return FALSE
+ if(NAMEOF_PROC(src, apply))
+ return FALSE
+ return ..()
+
+/datum/toml_config_entry/vv_delete()
+ return FALSE
+
+/**
+ * Called once when resetting.
+ */
+/datum/toml_config_entry/proc/reset()
+ if(isnum(default))
+ value = default
+ else if(istext(default))
+ value = default
+ else if(islist(default))
+ value = deep_copy_list(default)
+ else
+ CRASH("unexpected value in default.")
+
+/**
+ * Called once with the value from each load.
+ *
+ * Can be used to overlay values.
+ *
+ * @params
+ * * raw_config_value - Raw parsed data. We own the reference to this once this proc is called.
+ */
+/datum/toml_config_entry/proc/apply(raw_config_value)
+ value = raw_config_value
diff --git a/code/controllers/toml_config/toml_configuration.dm b/code/controllers/toml_config/toml_configuration.dm
new file mode 100644
index 00000000000..ec2984bcdde
--- /dev/null
+++ b/code/controllers/toml_config/toml_configuration.dm
@@ -0,0 +1,169 @@
+//* This file is explicitly licensed under the MIT license. *//
+//* Copyright (c) 2024 Citadel Station Developers *//
+
+// todo: maybe rename to config? or keep it as Configuration to keep with naming scheme of other 'system / backend' modules like the MC?
+GLOBAL_REAL(Configuration, /datum/controller/toml_configuration)
+
+// todo: /datum/controller/configuration
+/datum/controller/toml_configuration
+ /// Entries by type.
+ VAR_PRIVATE/list/datum/toml_config_entry/typed_entries
+ /// Entries as same structure as the underlying toml/json
+ VAR_PRIVATE/list/datum/toml_config_entry/keyed_entries
+
+/datum/controller/toml_configuration/CanProcCall(procname)
+ switch(procname)
+ if(NAMEOF_PROC(src, New), NAMEOF_PROC(src, Destroy), NAMEOF_PROC(src, Initialize))
+ return FALSE
+ if(NAMEOF_PROC(src, get_entry), NAMEOF_PROC(src, set_entry))
+ return FALSE
+ if(NAMEOF_PROC(src, get_sensitive_entry), NAMEOF_PROC(src, set_sensitive_entry))
+ return FALSE
+ if(NAMEOF_PROC(src, reload), NAMEOF_PROC(src, reset), NAMEOF_PROC(src, load), NAMEOF_PROC(src, recursively_load_from_list))
+ return FALSE
+ return ..()
+
+/datum/controller/toml_configuration/vv_edit_var(var_name, var_value, mass_edit, raw_edit)
+ switch(var_name)
+ if(NAMEOF(src, keyed_entries))
+ return FALSE
+ return ..()
+
+/datum/controller/toml_configuration/New()
+ if(Configuration != src)
+ if(Configuration)
+ qdel(Configuration)
+ Configuration = src
+
+/datum/controller/toml_configuration/Initialize()
+ keyed_entries = list()
+ typed_entries = list()
+ for(var/datum/toml_config_entry/path as anything in typesof(/datum/toml_config_entry))
+ if(initial(path.abstract_type) == path)
+ continue
+ var/datum/toml_config_entry/entry = new path
+ typed_entries[entry.type] = entry
+ var/list/nesting = splittext(entry.category, ".")
+ var/list/current_list = keyed_entries
+ for(var/i in 1 to length(nesting))
+ LAZYINITLIST(current_list[nesting[i]])
+ current_list = current_list[nesting[i]]
+ current_list[entry.key] = entry
+ reload()
+
+/datum/controller/toml_configuration/stat_key()
+ return "Configuration (New):"
+
+/datum/controller/toml_configuration/stat_entry()
+ return "Edit"
+
+/**
+ * HEY! LISTEN! By calling this proc you are affirming that:
+ *
+ * * The entry type you are passing in is static and not a variable that can be tampered with.
+ * * The value you get will be immediately consumed in a non-VV-able manner.
+ */
+/datum/controller/toml_configuration/proc/get_sensitive_entry(datum/toml_config_entry/entry_type)
+ // todo: cache / optimize
+ var/datum/toml_config_entry/entry = typed_entries[entry_type]
+ if(!entry)
+ return
+ if(!entry.sensitive)
+ CRASH("attempted to get sensitive entry with sensitive get entry.")
+ return entry.value
+
+/**
+ * HEY! LISTEN! By calling this proc you are affirming that:
+ *
+ * * The entry type you are passing in is static and not a variable that can be tampered with.
+ * * The value you are passing in is trusted and validated and not a variable that can be tampered with.
+ */
+/datum/controller/toml_configuration/proc/set_sensitive_entry(datum/toml_config_entry/entry_type, value)
+ // todo: cache / optimize
+ var/datum/toml_config_entry/entry = typed_entries[entry_type]
+ if(!entry)
+ return
+ if(entry.sensitive)
+ CRASH("attempted to set non-sensitive entry with sensitive set entry.")
+ entry.value = value
+
+/datum/controller/toml_configuration/proc/get_entry(datum/toml_config_entry/entry_type)
+ // todo: cache / optimize
+ var/datum/toml_config_entry/entry = typed_entries[entry_type]
+ if(!entry)
+ return
+ if(entry.sensitive)
+ CRASH("attempted to get sensitive entry with normal get entry.")
+ return entry.value
+
+/datum/controller/toml_configuration/proc/set_entry(datum/toml_config_entry/entry_type, value)
+ // todo: cache / optimize
+ var/datum/toml_config_entry/entry = typed_entries[entry_type]
+ if(!entry)
+ return
+ if(entry.sensitive)
+ CRASH("attempted to set sensitive entry with normal set entry.")
+ entry.value = value
+
+/datum/controller/toml_configuration/proc/admin_reload()
+ reload()
+
+/**
+ * Automatically loads default config, and the server's config file.
+ *
+ * todo: allow for overriding directories
+ */
+/datum/controller/toml_configuration/proc/reload()
+ reset()
+ load("config.default/config.toml")
+ load("config/config.toml")
+
+/**
+ * Resets the configuration.
+ */
+/datum/controller/toml_configuration/proc/reset()
+ for(var/path in typed_entries)
+ var/datum/toml_config_entry/entry = typed_entries[path]
+ entry.reset()
+
+/**
+ * Loads from a given layer.
+ * * This will not reset the configuration. Repeated calls to load will allow for layered configuration.
+ *
+ * HEY! LISTEN! By calling this proc you are affirming that:
+ * * The file you are passing in is trusted and not a variable that can be tampered with via VV.
+ */
+/datum/controller/toml_configuration/proc/load(filelike)
+ var/list/decoded
+ if(istext(filelike))
+ if(!fexists(filelike))
+ CRASH("failed to load [filelike]: does not exist")
+ decoded = rustg_read_toml_file(filelike)
+ else if(isfile(filelike))
+ // noa path, it might be rsc cache; rust_g can't read that directly.
+ fdel("tmp/config/loading.toml")
+ fcopy(filelike, "tmp/config/loading.toml")
+ decoded = rustg_read_toml_file("tmp/config/loading.toml")
+ fdel("tmp/config/loading.toml")
+ if(!decoded)
+ CRASH("failed to decode config [filelike]!")
+
+ recursively_load_from_list(decoded, keyed_entries)
+
+/datum/controller/toml_configuration/proc/recursively_load_from_list(list/decoded_list, list/entry_list)
+ if(!decoded_list || !entry_list)
+ return
+ for(var/key in decoded_list)
+ var/value = decoded_list[key]
+ if(islist(value))
+ var/list/next_entry_list = entry_list[key]
+ if(!islist(next_entry_list))
+ // todo: warn
+ else
+ recursively_load_from_list(value, next_entry_list[key])
+ else
+ var/datum/toml_config_entry/entry = entry_list[key]
+ if(!istype(entry))
+ // todo: warn
+ else
+ entry.apply(value)
diff --git a/code/datums/datumvars.dm b/code/datums/datumvars.dm
index c93c2373e7b..745ad7051e4 100644
--- a/code/datums/datumvars.dm
+++ b/code/datums/datumvars.dm
@@ -1,3 +1,10 @@
+/**
+ * Called when an admin attempts to delete us with introspection tools.
+ */
+/datum/proc/vv_delete()
+ . = TRUE
+ qdel(src)
+
/datum/proc/CanProcCall(procname)
return TRUE
diff --git a/code/game/machinery/telecomms/blackbox.dm b/code/game/machinery/telecomms/blackbox.dm
index 61e83517e4c..fb9cef3c7c4 100644
--- a/code/game/machinery/telecomms/blackbox.dm
+++ b/code/game/machinery/telecomms/blackbox.dm
@@ -182,7 +182,7 @@ var/obj/machinery/blackbox_recorder/blackbox
var/round_id
var/datum/db_query/query = SSdbcore.RunQuery(
- "SELECT MAX(round_id) AS round_id FROM [format_table_name("feedback")]",
+ "SELECT MAX(round_id) AS round_id FROM [DB_PREFIX_TABLE_NAME("feedback")]",
list()
)
@@ -195,7 +195,7 @@ var/obj/machinery/blackbox_recorder/blackbox
for(var/datum/feedback_variable/FV in feedback)
SSdbcore.RunQuery(
- "INSERT INTO [format_table_name("feedback")] VALUES (null, Now(), :round_id, :variable, :value, :details)",
+ "INSERT INTO [DB_PREFIX_TABLE_NAME("feedback")] VALUES (null, Now(), :round_id, :variable, :value, :details)",
list(
"round_id" = "[round_id]",
"variable" = "[FV.get_variable()]",
diff --git a/code/game/objects/materials.dm b/code/game/objects/materials.dm
index 8f6e73ce51c..7a8c5573657 100644
--- a/code/game/objects/materials.dm
+++ b/code/game/objects/materials.dm
@@ -91,7 +91,12 @@
if(islist(material_parts))
var/list/parts = list()
for(var/key in material_parts)
- parts[key] = RSmaterials.fetch(key)
+ var/datum/prototype/material/result = RSmaterials.fetch_or_defer(key)
+ switch(result)
+ if(REPOSITORY_FETCH_DEFER)
+ // todo: handle this
+ result = null
+ parts[key] = result
update_material_multi(parts)
else if(material_parts == MATERIAL_DEFAULT_DISABLED)
else if(material_parts == MATERIAL_DEFAULT_ABSTRACTED)
@@ -99,7 +104,12 @@
// skip specifying parts because abstracted
update_material_multi()
else
- update_material_single((material_parts = RSmaterials.fetch(material_parts)))
+ var/datum/prototype/material/result = RSmaterials.fetch_or_defer(material_parts)
+ switch(result)
+ if(REPOSITORY_FETCH_DEFER)
+ // todo: handle this
+ result = null
+ update_material_single((material_parts = result))
/**
* forces a material update
diff --git a/code/game/objects/structures/barricade.dm b/code/game/objects/structures/barricade.dm
index e490a2965fa..e34557966bd 100644
--- a/code/game/objects/structures/barricade.dm
+++ b/code/game/objects/structures/barricade.dm
@@ -13,7 +13,12 @@
/obj/structure/barricade/Initialize(mapload, datum/prototype/material/material_like)
if(!isnull(material_like))
- set_primary_material(RSmaterials.fetch(material_like))
+ var/resolved_material = RSmaterials.fetch_or_defer(material_like)
+ switch(resolved_material)
+ if(REPOSITORY_FETCH_DEFER)
+ // todo: handle
+ else
+ set_primary_material(resolved_material)
return ..()
/obj/structure/barricade/update_material_single(datum/prototype/material/material)
diff --git a/code/game/objects/structures/low_wall.dm b/code/game/objects/structures/low_wall.dm
index e3419164af5..e3d4b324711 100644
--- a/code/game/objects/structures/low_wall.dm
+++ b/code/game/objects/structures/low_wall.dm
@@ -48,9 +48,14 @@ GLOBAL_LIST_INIT(wallframe_typecache, typecacheof(list(
paint_color = COLOR_WALL_GUNMETAL
stripe_color = COLOR_WALL_GUNMETAL
-/obj/structure/wall_frame/Initialize(mapload, material)
- if(!isnull(material))
- set_primary_material(RSmaterials.fetch(material))
+/obj/structure/wall_frame/Initialize(mapload, datum/prototype/material/material_like)
+ if(!isnull(material_like))
+ var/resolved_material = RSmaterials.fetch_or_defer(material_like)
+ switch(resolved_material)
+ if(REPOSITORY_FETCH_DEFER)
+ // todo: handle
+ else
+ set_primary_material(resolved_material)
. = ..()
update_overlays()
diff --git a/code/game/objects/structures/props/puzzledoor.dm b/code/game/objects/structures/props/puzzledoor.dm
index 66c6b173682..a73e4cd1631 100644
--- a/code/game/objects/structures/props/puzzledoor.dm
+++ b/code/game/objects/structures/props/puzzledoor.dm
@@ -36,7 +36,7 @@
/obj/machinery/door/blast/puzzle/Initialize(mapload)
. = ..()
- implicit_material = RSmaterials.fetch(/datum/prototype/material/alienalloy/dungeonium)
+ implicit_material = RSmaterials.fetch_local_or_throw(/datum/prototype/material/alienalloy/dungeonium)
if(locks.len)
return
var/check_range = world.view * checkrange_mult
diff --git a/code/game/objects/structures/simple_doors.dm b/code/game/objects/structures/simple_doors.dm
index 273b68e575f..09824f2a693 100644
--- a/code/game/objects/structures/simple_doors.dm
+++ b/code/game/objects/structures/simple_doors.dm
@@ -15,9 +15,14 @@
var/isSwitchingStates = 0
var/oreAmount = 7
-/obj/structure/simple_door/Initialize(mapload, material)
- if(!isnull(material))
- set_primary_material(RSmaterials.fetch(material))
+/obj/structure/simple_door/Initialize(mapload, datum/prototype/material/material_like)
+ if(!isnull(material_like))
+ var/resolved_material = RSmaterials.fetch_or_defer(material_like)
+ switch(resolved_material)
+ if(REPOSITORY_FETCH_DEFER)
+ // todo: handle
+ else
+ set_primary_material(resolved_material)
return ..()
/obj/structure/simple_door/update_material_single(datum/prototype/material/material)
diff --git a/code/game/statistics.dm b/code/game/statistics.dm
index e8f73892bd6..2a67a26b905 100644
--- a/code/game/statistics.dm
+++ b/code/game/statistics.dm
@@ -9,7 +9,7 @@
log_game("SQL ERROR during population polling. Failed to connect.")
else
var/datum/db_query/query = SSdbcore.NewQuery(
- "INSERT INTO [format_table_name("population")] (playercount, admincount, time) VALUES (:pc, :ac, NOW())",
+ "INSERT INTO [DB_PREFIX_TABLE_NAME("population")] (playercount, admincount, time) VALUES (:pc, :ac, NOW())",
list(
"pc" = sanitizeSQL(playercount),
"ac" = sanitizeSQL(admincount),
@@ -48,7 +48,7 @@
log_game("SQL ERROR during death reporting. Failed to connect.")
else
var/datum/db_query/query = SSdbcore.NewQuery(
- "INSERT INTO [format_table_name("death")] (name, byondkey, job, special, pod, tod, laname, lakey, gender, bruteloss, fireloss, brainloss, oxyloss, coord) VALUES \
+ "INSERT INTO [DB_PREFIX_TABLE_NAME("death")] (name, byondkey, job, special, pod, tod, laname, lakey, gender, bruteloss, fireloss, brainloss, oxyloss, coord) VALUES \
(:name, :key, :job, :special, :pod, :time, :laname, :lakey, :gender, :bruteloss, :fireloss, :brainloss, :oxyloss, :coord)",
list(
"name" = sqlname,
@@ -98,7 +98,7 @@
log_game("SQL ERROR during death reporting. Failed to connect.")
else
var/datum/db_query/query = SSdbcore.NewQuery(
- "INSERT INTO [format_table_name("death")] (name, byondkey, job, special, pod, tod, laname, lakey, gender, bruteloss, fireloss, brainloss, oxyloss, coord) VALUES \
+ "INSERT INTO [DB_PREFIX_TABLE_NAME("death")] (name, byondkey, job, special, pod, tod, laname, lakey, gender, bruteloss, fireloss, brainloss, oxyloss, coord) VALUES \
(:name, :key, :job, :special, :pod, :time, :laname, :lakey, :geender, :bruteloss, :fireloss, :brainloss, :oxyloss, :coord)",
list(
"name" = sqlname,
@@ -146,7 +146,7 @@
else
var/datum/db_query/max_query = SSdbcore.RunQuery(
- "SELECT MAX(roundid) AS max_round_id FROM [format_table_name("feedback")]",
+ "SELECT MAX(roundid) AS max_round_id FROM [DB_PREFIX_TABLE_NAME("feedback")]",
list(),
)
@@ -168,7 +168,7 @@
var/value = item.get_value()
var/datum/db_query/query = SSdbcore.NewQuery(
- "INSERT INTO [format_table_name("feedback")] (id, roundid, time, variable, value) VALUES (null, :rid, Now(), :var, :val)",
+ "INSERT INTO [DB_PREFIX_TABLE_NAME("feedback")] (id, roundid, time, variable, value) VALUES (null, :rid, Now(), :var, :val)",
list(
"rid" = newroundid,
"var" = sanitizeSQL(variable),
diff --git a/code/game/turfs/simulated/floor/floor.dm b/code/game/turfs/simulated/floor/floor.dm
index 793169f852d..98b2f44c557 100644
--- a/code/game/turfs/simulated/floor/floor.dm
+++ b/code/game/turfs/simulated/floor/floor.dm
@@ -73,7 +73,7 @@
CRASH("additional arg detected in /floor Initialize. turfs do not have init arguments as ChangeTurf does not accept them.")
var/datum/prototype/flooring/set_flooring_to
- if(initial_flooring && (set_flooring_to = RSflooring.fetch(initial_flooring)))
+ if(initial_flooring && (set_flooring_to = RSflooring.fetch_local_or_throw(initial_flooring)))
set_flooring(set_flooring_to, TRUE)
else
// todo: these are only here under else because set flooring will trigger it
diff --git a/code/game/turfs/simulated/floor_types/water.dm b/code/game/turfs/simulated/floor_types/water.dm
index 3e1fd52501f..beaee03cc0e 100644
--- a/code/game/turfs/simulated/floor_types/water.dm
+++ b/code/game/turfs/simulated/floor_types/water.dm
@@ -24,7 +24,7 @@
/turf/simulated/floor/water/Initialize(mapload)
. = ..()
- var/datum/prototype/flooring/F = RSflooring.fetch(/datum/prototype/flooring/water)
+ var/datum/prototype/flooring/F = RSflooring.fetch_local_or_throw(/datum/prototype/flooring/water)
footstep_sounds = F?.footstep_sounds
update_icon()
diff --git a/code/game/turfs/simulated/wall/materials.dm b/code/game/turfs/simulated/wall/materials.dm
index 507a17b1032..1867c7a0725 100644
--- a/code/game/turfs/simulated/wall/materials.dm
+++ b/code/game/turfs/simulated/wall/materials.dm
@@ -1,7 +1,7 @@
/turf/simulated/wall/proc/init_materials(datum/prototype/material/outer = material_outer, datum/prototype/material/reinforcing = material_reinf, datum/prototype/material/girder = material_girder)
- outer = RSmaterials.fetch(outer)
- reinforcing = RSmaterials.fetch(reinforcing)
- girder = RSmaterials.fetch(girder)
+ outer = RSmaterials.fetch_local_or_throw(outer)
+ reinforcing = RSmaterials.fetch_local_or_throw(reinforcing)
+ girder = RSmaterials.fetch_local_or_throw(girder)
if(!isnull(outer))
material_outer = outer
diff --git a/code/game/turfs/turf.dm b/code/game/turfs/turf.dm
index 6d439de3b5a..93ceaf8ba58 100644
--- a/code/game/turfs/turf.dm
+++ b/code/game/turfs/turf.dm
@@ -682,3 +682,8 @@
thing.update_hiding_underfloor(
(thing.hides_underfloor != OBJ_UNDERFLOOR_NEVER) && we_should_cover,
)
+
+//* VV *//
+
+/turf/vv_delete()
+ ScrapeAway()
diff --git a/code/modules/admin/DB ban/functions.dm b/code/modules/admin/DB ban/functions.dm
index 0f195dd1d71..e332f48c88f 100644
--- a/code/modules/admin/DB ban/functions.dm
+++ b/code/modules/admin/DB ban/functions.dm
@@ -72,7 +72,7 @@
computerid = ""
if(isnull(ip))
ip = ""
- var/sql = "INSERT INTO [format_table_name("ban")] \
+ var/sql = "INSERT INTO [DB_PREFIX_TABLE_NAME("ban")] \
(`id`,`bantime`,`serverip`,`bantype`,`reason`,`job`,`duration`,`rounds`,`expiration_time`,`ckey`,`computerid`,`ip`,`a_ckey`,`a_computerid`,`a_ip`,`who`,`adminwho`,`edits`,`unbanned`,`unbanned_datetime`,`unbanned_ckey`,`unbanned_computerid`,`unbanned_ip`) \
VALUES (null, Now(), :serverip, :type, :reason, :job, :duration, :rounds, Now() + INTERVAL :duration MINUTE, :ckey, :cid, :ip, :a_ckey, :a_cid, :a_ip, :who, :adminwho, '', null, null, null, null, null)"
SSdbcore.RunQuery(
@@ -133,7 +133,7 @@
else
bantype_sql = "bantype = '[bantype_str]'"
- var/sql = "SELECT id FROM [format_table_name("ban")] WHERE ckey = :ckey AND [bantype_sql] AND (unbanned is null OR unbanned = false)"
+ var/sql = "SELECT id FROM [DB_PREFIX_TABLE_NAME("ban")] WHERE ckey = :ckey AND [bantype_sql] AND (unbanned is null OR unbanned = false)"
if(job)
sql += " AND job = :job"
@@ -183,7 +183,7 @@
return
var/datum/db_query/query = SSdbcore.RunQuery(
- "SELECT ckey, duration, reason FROM [format_table_name("ban")] WHERE id = :id",
+ "SELECT ckey, duration, reason FROM [DB_PREFIX_TABLE_NAME("ban")] WHERE id = :id",
list(
"id" = banid
)
@@ -215,7 +215,7 @@
return
SSdbcore.RunQuery(
- "UPDATE [format_table_name("ban")] SET reason = :reason, \
+ "UPDATE [DB_PREFIX_TABLE_NAME("ban")] SET reason = :reason, \
edits = CONCAT(edits, '- :ckey changed ban reason from \\\":oldreason\\\" to \\\":reason\\\"
') \
WHERE id = :id",
list(
@@ -233,7 +233,7 @@
to_chat(usr, "Cancelled")
return
SSdbcore.RunQuery(
- "UPDATE [format_table_name("ban")] SET duration = :duration, \
+ "UPDATE [DB_PREFIX_TABLE_NAME("ban")] SET duration = :duration, \
edits = CONCAT(edits, '- :ckey changed ban duration from :oldduration to :duration
'), expiration_time = DATE_ADD(bantime, INTERVAL :duration MINUTE) \
WHERE id = :id",
list(
@@ -264,7 +264,7 @@
var/pckey
var/datum/db_query/query = SSdbcore.RunQuery(
- "SELECT ckey FROM [format_table_name("ban")] WHERE id = :id",
+ "SELECT ckey FROM [DB_PREFIX_TABLE_NAME("ban")] WHERE id = :id",
list(
"id" = id
)
@@ -292,7 +292,7 @@
message_admins("[key_name_admin(usr)] has lifted [pckey]'s ban.",1)
SSdbcore.RunQuery(
- "UPDATE [format_table_name("ban")] SET unbanned = 1, unbanned_datetime = Now(), unbanned_ckey = :ckey, unbanned_computerid = :cid, unbanned_ip = :ip WHERE id = :id",
+ "UPDATE [DB_PREFIX_TABLE_NAME("ban")] SET unbanned = 1, unbanned_datetime = Now(), unbanned_ckey = :ckey, unbanned_computerid = :cid, unbanned_ip = :ip WHERE id = :id",
list(
"ckey" = unban_ckey,
"cid" = unban_computerid,
@@ -458,7 +458,7 @@
var/datum/db_query/select_query = SSdbcore.RunQuery(
"SELECT id, bantime, bantype, reason, job, duration, expiration_time, ckey, a_ckey, unbanned, unbanned_ckey, unbanned_datetime, edits, ip, computerid \
- FROM [format_table_name("ban")] \
+ FROM [DB_PREFIX_TABLE_NAME("ban")] \
WHERE 1 [playersearch] [adminsearch] [ipsearch] [cidsearch] [bantypesearch] ORDER BY bantime DESC LIMIT 100",
search_params
)
diff --git a/code/modules/admin/IsBanned.dm b/code/modules/admin/IsBanned.dm
index 2eb8325ac57..42bfc1dc365 100644
--- a/code/modules/admin/IsBanned.dm
+++ b/code/modules/admin/IsBanned.dm
@@ -88,7 +88,7 @@
cidquery = " OR computerid = ':cid' "
var/datum/db_query/query = SSdbcore.RunQuery(
- "SELECT ckey, ip, computerid, a_ckey, reason, expiration_time, duration, bantime, bantype FROM [format_table_name("ban")] WHERE (ckey = :ckey [ipquery] [cidquery]) AND (bantype = 'PERMABAN' OR (bantype = 'TEMPBAN' AND expiration_time > Now())) AND isnull(unbanned)",
+ "SELECT ckey, ip, computerid, a_ckey, reason, expiration_time, duration, bantime, bantype FROM [DB_PREFIX_TABLE_NAME("ban")] WHERE (ckey = :ckey [ipquery] [cidquery]) AND (bantype = 'PERMABAN' OR (bantype = 'TEMPBAN' AND expiration_time > Now())) AND isnull(unbanned)",
list(
"ckey" = ckeytext,
"ip" = address,
diff --git a/code/modules/admin/admin_ranks.dm b/code/modules/admin/admin_ranks.dm
index 29500fb71be..58583b9bad2 100644
--- a/code/modules/admin/admin_ranks.dm
+++ b/code/modules/admin/admin_ranks.dm
@@ -113,7 +113,7 @@ var/list/admin_ranks = list() //list of all ranks with associated rights
return
var/datum/db_query/query = SSdbcore.RunQuery(
- "SELECT ckey, rank, level, flags FROM [format_table_name("admin")]",
+ "SELECT ckey, rank, level, flags FROM [DB_PREFIX_TABLE_NAME("admin")]",
list()
)
diff --git a/code/modules/admin/banjob.dm b/code/modules/admin/banjob.dm
index 147e5c3cd7c..65148f569a9 100644
--- a/code/modules/admin/banjob.dm
+++ b/code/modules/admin/banjob.dm
@@ -74,7 +74,7 @@ DEBUG
//Job permabans
var/datum/db_query/query = SSdbcore.RunQuery(
- "SELECT ckey, job FROM [format_table_name("ban")] WHERE bantype = 'JOB_PERMABAN' AND isnull(unbanned)",
+ "SELECT ckey, job FROM [DB_PREFIX_TABLE_NAME("ban")] WHERE bantype = 'JOB_PERMABAN' AND isnull(unbanned)",
list()
)
@@ -86,7 +86,7 @@ DEBUG
//Job tempbans
var/datum/db_query/query1 = SSdbcore.RunQuery(
- "SELECT ckey, job FROM [format_table_name("ban")] WHERE bantype = 'JOB_TEMPBAN' AND isnull(unbanned) AND expiration_time > Now()",
+ "SELECT ckey, job FROM [DB_PREFIX_TABLE_NAME("ban")] WHERE bantype = 'JOB_TEMPBAN' AND isnull(unbanned) AND expiration_time > Now()",
list()
)
diff --git a/code/modules/admin/permissionverbs/permissionedit.dm b/code/modules/admin/permissionverbs/permissionedit.dm
index fad21524481..d3a701a4055 100644
--- a/code/modules/admin/permissionverbs/permissionedit.dm
+++ b/code/modules/admin/permissionverbs/permissionedit.dm
@@ -78,7 +78,7 @@
return
var/datum/db_query/select_query = SSdbcore.RunQuery(
- "SELECT id FROM [format_table_name("admin")] WHERE ckey = :ckey",
+ "SELECT id FROM [DB_PREFIX_TABLE_NAME("admin")] WHERE ckey = :ckey",
list(
"ckey" = adm_ckey
)
@@ -92,14 +92,14 @@
if(new_admin)
SSdbcore.RunQuery(
- "INSERT INTO [format_table_name("admin")] (id, ckey, rank, level, flags) VALUES (null, :ckey, :rank, -1, 0)",
+ "INSERT INTO [DB_PREFIX_TABLE_NAME("admin")] (id, ckey, rank, level, flags) VALUES (null, :ckey, :rank, -1, 0)",
list(
"ckey" = adm_ckey,
"rank" = new_rank
)
)
SSdbcore.RunQuery(
- "INSERT INTO [format_table_name("admin_log")] (id, datetime, adminckey, adminip, log) VALUES (NULL, NOW(), :ckey, :ip, :logstr)",
+ "INSERT INTO [DB_PREFIX_TABLE_NAME("admin_log")] (id, datetime, adminckey, adminip, log) VALUES (NULL, NOW(), :ckey, :ip, :logstr)",
list(
"ckey" = sanitizeSQL(usr.ckey),
"ip" = sanitizeSQL(usr.client.address),
@@ -110,14 +110,14 @@
else
if(!isnull(admin_id) && isnum(admin_id))
SSdbcore.RunQuery(
- "UPDATE [format_table_name("admin")] SET rank = :rank WHERE id = :id",
+ "UPDATE [DB_PREFIX_TABLE_NAME("admin")] SET rank = :rank WHERE id = :id",
list(
"rank" = new_rank,
"id" = admin_id
)
)
SSdbcore.RunQuery(
- "INSERT INTO [format_table_name("admin_log")] (id, datetime, adminckey, adminip, log) VALUES (NULL, Now(), :ckey, :addr, :log)",
+ "INSERT INTO [DB_PREFIX_TABLE_NAME("admin_log")] (id, datetime, adminckey, adminip, log) VALUES (NULL, Now(), :ckey, :addr, :log)",
list(
"ckey" = usr.ckey,
"addr" = usr.client.address,
@@ -155,7 +155,7 @@
return
var/datum/db_query/select_query = SSdbcore.RunQuery(
- "SELECT id, flags FROM [format_table_name("admin")] WHERE ckey = :ckey",
+ "SELECT id, flags FROM [DB_PREFIX_TABLE_NAME("admin")] WHERE ckey = :ckey",
list(
"ckey" = adm_ckey
)
@@ -172,14 +172,14 @@
if(admin_rights & new_permission) //This admin already has this permission, so we are removing it.
SSdbcore.RunQuery(
- "UPDATE [format_table_name("admin")] SET flags = :flags WHERE id = :id",
+ "UPDATE [DB_PREFIX_TABLE_NAME("admin")] SET flags = :flags WHERE id = :id",
list(
"flags" = admin_rights & ~new_permission,
"id" = admin_id
)
)
SSdbcore.RunQuery(
- "INSERT INTO [format_table_name("admin_log")] (id, datetime, adminckey, adminip, log) VALUES (NULL, Now(), :ckey, :addr, :log)",
+ "INSERT INTO [DB_PREFIX_TABLE_NAME("admin_log")] (id, datetime, adminckey, adminip, log) VALUES (NULL, Now(), :ckey, :addr, :log)",
list(
"ckey" = usr.ckey,
"addr" = usr.client.address,
@@ -189,14 +189,14 @@
to_chat(usr, "Permission removed.")
else //This admin doesn't have this permission, so we are adding it.
SSdbcore.RunQuery(
- "UPDATE [format_table_name("admin")] SET flags = :flags WHERE id = :id",
+ "UPDATE [DB_PREFIX_TABLE_NAME("admin")] SET flags = :flags WHERE id = :id",
list(
"flags" = admin_rights | new_permission,
"id" = admin_id
)
)
SSdbcore.RunQuery(
- "INSERT INTO [format_table_name("admin_log")] (id, datetime, adminckey, adminip, log) VALUES (NULL, Now(), :ckey, :addr, :log)",
+ "INSERT INTO [DB_PREFIX_TABLE_NAME("admin_log")] (id, datetime, adminckey, adminip, log) VALUES (NULL, Now(), :ckey, :addr, :log)",
list(
"ckey" = usr.ckey,
"addr" = usr.client.address,
diff --git a/code/modules/admin/verbs/check_customitem_activity.dm b/code/modules/admin/verbs/check_customitem_activity.dm
index 02e577d13e4..6b329a5fadb 100644
--- a/code/modules/admin/verbs/check_customitem_activity.dm
+++ b/code/modules/admin/verbs/check_customitem_activity.dm
@@ -55,7 +55,7 @@ var/inactive_keys = "None
"
var/list/inactive_ckeys = list()
if(ckeys_with_customitems.len)
var/datum/db_query/query_inactive = SSdbcore.RunQuery(
- "SELECT ckey, lastseen FROM [format_table_name("player_lookup")] WHERE datediff(Now(), lastseen) > 60",
+ "SELECT ckey, lastseen FROM [DB_PREFIX_TABLE_NAME("player_lookup")] WHERE datediff(Now(), lastseen) > 60",
list()
)
while(query_inactive.NextRow())
@@ -69,7 +69,7 @@ var/inactive_keys = "None
"
if(ckeys_with_customitems.len)
for(var/cur_ckey in ckeys_with_customitems)
var/datum/db_query/query_inactive = SSdbcore.RunQuery(
- "SELECT ckey FROM [format_table_name("player_lookup")] WHERE ckey = :ckey",
+ "SELECT ckey FROM [DB_PREFIX_TABLE_NAME("player_lookup")] WHERE ckey = :ckey",
list(
"ckey" = cur_ckey
)
diff --git a/code/modules/admin/verbs/debug.dm b/code/modules/admin/verbs/debug.dm
index fa96e39a4c4..5b40ba3bc97 100644
--- a/code/modules/admin/verbs/debug.dm
+++ b/code/modules/admin/verbs/debug.dm
@@ -687,16 +687,6 @@
message_admins(log)
log_admin(log)
-/client/proc/reload_configuration()
- set category = "Debug"
- set name = "Reload Configuration"
- set desc = "Force config reload to world default"
- if(!check_rights(R_DEBUG))
- return
- if(alert(usr, "Are you absolutely sure you want to reload the configuration from the default path on the disk, wiping any in-round modificatoins?", "Really reset?", "No", "Yes") == "Yes")
- config.admin_reload()
- load_configuration() //for legacy
-
/datum/admins/proc/quick_nif()
set category = "Fun"
set name = "Quick NIF"
diff --git a/code/modules/admin/verbs/debug/reload_configuration.dm b/code/modules/admin/verbs/debug/reload_configuration.dm
new file mode 100644
index 00000000000..fd80f16133f
--- /dev/null
+++ b/code/modules/admin/verbs/debug/reload_configuration.dm
@@ -0,0 +1,12 @@
+
+/client/proc/reload_configuration()
+ set category = "Debug"
+ set name = "Reload Configuration"
+ set desc = "Force config reload to world default"
+ if(!check_rights(R_DEBUG))
+ return
+ if(alert(usr, "Are you absolutely sure you want to reload the configuration from the default path on the disk, wiping any in-round modificatoins?", "Really reset?", "No", "Yes") == "Yes")
+ log_and_message_admins("[key_name(usr)] reloaded server configuration.")
+ config.admin_reload()
+ Configuration.admin_reload()
+ load_configuration() //for legacy
diff --git a/code/modules/admin/view_variables/admin_delete.dm b/code/modules/admin/view_variables/admin_delete.dm
index 7157a1cce2b..16c84012c99 100644
--- a/code/modules/admin/view_variables/admin_delete.dm
+++ b/code/modules/admin/view_variables/admin_delete.dm
@@ -16,9 +16,9 @@
//SSblackbox.record_feedback("tally", "admin_verb", 1, "Delete") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
if(isturf(D))
var/turf/T = D
- T.ScrapeAway()
+ T.vv_delete()
else
vv_update_display(D, "deleted", VV_MSG_DELETED)
- qdel(D)
+ D.vv_delete()
if(!QDELETED(D))
vv_update_display(D, "deleted", "")
diff --git a/code/modules/artwork/items/poster.dm b/code/modules/artwork/items/poster.dm
index be689b6a4f9..d1be0da56d4 100644
--- a/code/modules/artwork/items/poster.dm
+++ b/code/modules/artwork/items/poster.dm
@@ -26,7 +26,7 @@
poster_design_id = pick(RSposter_designs.fetch_by_tag_mutable(poster_random_tag))
if(poster_design_id != src.poster_design_id)
src.poster_design_id = poster_design_id
- set_poster_design(RSposter_designs.fetch(poster_design_id))
+ set_poster_design(RSposter_designs.fetch_local_or_throw(poster_design_id))
/obj/item/poster/proc/set_poster_design(datum/prototype/poster_design/design)
src.name = "rolled-up-poster - [design.name]"
diff --git a/code/modules/artwork/structures/poster.dm b/code/modules/artwork/structures/poster.dm
index 4b707581a18..0c2f3147a1e 100644
--- a/code/modules/artwork/structures/poster.dm
+++ b/code/modules/artwork/structures/poster.dm
@@ -41,7 +41,7 @@
poster_design_id = pick(RSposter_designs.fetch_by_tag_mutable(poster_random_tag))
if(poster_design_id != src.poster_design_id)
src.poster_design_id = poster_design_id
- set_poster_design(RSposter_designs.fetch(poster_design_id))
+ set_poster_design(RSposter_designs.fetch_local_or_throw(poster_design_id))
/obj/structure/poster/proc/set_poster_design(datum/prototype/poster_design/design)
src.name = "rolled-up-poster - [design.name]"
diff --git a/code/modules/artwork/structures/sculpting_block.dm b/code/modules/artwork/structures/sculpting_block.dm
index d9e53ef0ced..b8598d4cbbd 100644
--- a/code/modules/artwork/structures/sculpting_block.dm
+++ b/code/modules/artwork/structures/sculpting_block.dm
@@ -78,9 +78,15 @@
/// sculpting mask for our block
var/icon/sculpting_rolldown_mask
-/obj/structure/sculpting_block/Initialize(mapload, material)
+/obj/structure/sculpting_block/Initialize(mapload, datum/prototype/material/material_like)
// todo: materials system
- src.material = RSmaterials.fetch(material || src.material)
+ if(!isnull(material_like))
+ var/resolved_material = RSmaterials.fetch_or_defer(material_like)
+ switch(resolved_material)
+ if(REPOSITORY_FETCH_DEFER)
+ // todo: handle
+ else
+ src.material = resolved_material || RSmaterials.fetch_local_or_throw(/datum/prototype/material/steel)
// todo: if it autoinit'd, don't do this
reset_sculpting()
return ..()
diff --git a/code/modules/client/client_procs.dm b/code/modules/client/client_procs.dm
index bb1edf8d647..8d20b0cbcad 100644
--- a/code/modules/client/client_procs.dm
+++ b/code/modules/client/client_procs.dm
@@ -467,7 +467,7 @@
var/sql_system_ckey = sanitizeSQL(system_ckey)
var/sql_ckey = sanitizeSQL(ckey)
//check to see if we noted them in the last day.
- var/datum/DBQuery/query_get_notes = SSdbcore.NewQuery("SELECT id FROM [format_table_name("messages")] WHERE type = 'note' AND targetckey = '[sql_ckey]' AND adminckey = '[sql_system_ckey]' AND timestamp + INTERVAL 1 DAY < NOW() AND deleted = 0 AND expire_timestamp > NOW()")
+ var/datum/DBQuery/query_get_notes = SSdbcore.NewQuery("SELECT id FROM [DB_PREFIX_TABLE_NAME("messages")] WHERE type = 'note' AND targetckey = '[sql_ckey]' AND adminckey = '[sql_system_ckey]' AND timestamp + INTERVAL 1 DAY < NOW() AND deleted = 0 AND expire_timestamp > NOW()")
if(!query_get_notes.Execute())
qdel(query_get_notes)
return
@@ -476,7 +476,7 @@
return
qdel(query_get_notes)
//regardless of above, make sure their last note is not from us, as no point in repeating the same note over and over.
- query_get_notes = SSdbcore.NewQuery("SELECT adminckey FROM [format_table_name("messages")] WHERE targetckey = '[sql_ckey]' AND deleted = 0 AND expire_timestamp > NOW() ORDER BY timestamp DESC LIMIT 1")
+ query_get_notes = SSdbcore.NewQuery("SELECT adminckey FROM [DB_PREFIX_TABLE_NAME("messages")] WHERE targetckey = '[sql_ckey]' AND deleted = 0 AND expire_timestamp > NOW() ORDER BY timestamp DESC LIMIT 1")
if(!query_get_notes.Execute())
qdel(query_get_notes)
return
diff --git a/code/modules/client/connection.dm b/code/modules/client/connection.dm
index 5e45f624d36..8f52aebf6ec 100644
--- a/code/modules/client/connection.dm
+++ b/code/modules/client/connection.dm
@@ -7,7 +7,7 @@
return
var/datum/db_query/lookup = SSdbcore.NewQuery(
- "SELECT id FROM [format_table_name("player_lookup")] WHERE ckey = :ckey",
+ "SELECT id FROM [DB_PREFIX_TABLE_NAME("player_lookup")] WHERE ckey = :ckey",
list(
"ckey" = ckey,
)
@@ -20,7 +20,7 @@
if(sql_id)
var/datum/db_query/update = SSdbcore.NewQuery(
- "UPDATE [format_table_name("player_lookup")] SET lastseen = Now(), ip = :ip, computerid = :computerid, lastadminrank = :lastadminrank WHERE id = :id",
+ "UPDATE [DB_PREFIX_TABLE_NAME("player_lookup")] SET lastseen = Now(), ip = :ip, computerid = :computerid, lastadminrank = :lastadminrank WHERE id = :id",
list(
"ip" = address,
"computerid" = computer_id,
@@ -33,7 +33,7 @@
else
//New player!! Need to insert all the stuff
var/datum/db_query/insert = SSdbcore.NewQuery(
- "INSERT INTO [format_table_name("player_lookup")] (id, ckey, firstseen, lastseen, ip, computerid, lastadminrank) VALUES (null, :ckey, Now(), Now(), :ip, :cid, :rank)",
+ "INSERT INTO [DB_PREFIX_TABLE_NAME("player_lookup")] (id, ckey, firstseen, lastseen, ip, computerid, lastadminrank) VALUES (null, :ckey, Now(), Now(), :ip, :cid, :rank)",
list(
"ckey" = ckey,
"ip" = address,
@@ -55,7 +55,7 @@
return
SSdbcore.RunQuery(
- "INSERT INTO [format_table_name("connection_log")] (id, datetime, serverip, ckey, ip, computerid) VALUES (null, Now(), :server, :ckey, :ip, :cid)",
+ "INSERT INTO [DB_PREFIX_TABLE_NAME("connection_log")] (id, datetime, serverip, ckey, ip, computerid) VALUES (null, Now(), :server, :ckey, :ip, :cid)",
list(
"server" = "[world.internet_address]:[world.port]",
"ckey" = ckey,
diff --git a/code/modules/client/data/client_data.dm b/code/modules/client/data/client_data.dm
index 8b74a28b368..b1f70aec30e 100644
--- a/code/modules/client/data/client_data.dm
+++ b/code/modules/client/data/client_data.dm
@@ -136,7 +136,7 @@ GLOBAL_LIST_EMPTY(client_data)
playtime_mutex = FALSE
return
var/datum/db_query/query = SSdbcore.NewQuery(
- "SELECT `roleid`, `minutes` FROM [format_table_name("playtime")] WHERE player = :player",
+ "SELECT `roleid`, `minutes` FROM [DB_PREFIX_TABLE_NAME("playtime")] WHERE player = :player",
list(
"player" = player_id,
)
diff --git a/code/modules/client/data/player_data.dm b/code/modules/client/data/player_data.dm
index dfbc4c6faa9..591ed3bb33b 100644
--- a/code/modules/client/data/player_data.dm
+++ b/code/modules/client/data/player_data.dm
@@ -94,7 +94,7 @@ GLOBAL_LIST_EMPTY(player_data)
return
var/datum/db_query/lookup
lookup = SSdbcore.ExecuteQuery(
- "SELECT id, playerid, firstseen FROM [format_table_name("player_lookup")] WHERE ckey = :ckey",
+ "SELECT id, playerid, firstseen FROM [DB_PREFIX_TABLE_NAME("player_lookup")] WHERE ckey = :ckey",
list(
"ckey" = ckey
)
@@ -111,7 +111,7 @@ GLOBAL_LIST_EMPTY(player_data)
lookup_pid = text2num(lookup_pid)
qdel(lookup)
lookup = SSdbcore.ExecuteQuery(
- "SELECT id, flags, datediff(Now(), firstseen), firstseen, misc FROM [format_table_name("player")] WHERE id = :id",
+ "SELECT id, flags, datediff(Now(), firstseen), firstseen, misc FROM [DB_PREFIX_TABLE_NAME("player")] WHERE id = :id",
list(
"id" = lookup_pid
)
@@ -147,7 +147,7 @@ GLOBAL_LIST_EMPTY(player_data)
var/datum/db_query/insert
if(migrate_firstseen)
insert = SSdbcore.ExecuteQuery(
- "INSERT INTO [format_table_name("player")] (flags, firstseen, lastseen, misc) VALUES (:flags, :fs, Now(), :misc)",
+ "INSERT INTO [DB_PREFIX_TABLE_NAME("player")] (flags, firstseen, lastseen, misc) VALUES (:flags, :fs, Now(), :misc)",
list(
"flags" = player_flags,
"fs" = migrate_firstseen,
@@ -157,7 +157,7 @@ GLOBAL_LIST_EMPTY(player_data)
player_first_seen = migrate_firstseen
else
insert = SSdbcore.ExecuteQuery(
- "INSERT INTO [format_table_name("player")] (flags, firstseen, lastseen, misc) VALUES (:flags, Now(), Now(), :misc)",
+ "INSERT INTO [DB_PREFIX_TABLE_NAME("player")] (flags, firstseen, lastseen, misc) VALUES (:flags, Now(), Now(), :misc)",
list(
"flags" = player_flags,
"misc" = safe_json_encode(player_misc),
@@ -173,7 +173,7 @@ GLOBAL_LIST_EMPTY(player_data)
qdel(insert)
// now update lookup
insert = SSdbcore.ExecuteQuery(
- "UPDATE [format_table_name("player_lookup")] SET playerid = :pid WHERE id = :id",
+ "UPDATE [DB_PREFIX_TABLE_NAME("player_lookup")] SET playerid = :pid WHERE id = :id",
list(
"id" = lookup_id,
"pid" = insert_id
@@ -211,7 +211,7 @@ GLOBAL_LIST_EMPTY(player_data)
/datum/player_data/proc/_save()
qdel(SSdbcore.ExecuteQuery(
- "UPDATE [format_table_name("player")] SET flags = :flags, misc = :misc WHERE id = :id",
+ "UPDATE [DB_PREFIX_TABLE_NAME("player")] SET flags = :flags, misc = :misc WHERE id = :id",
list(
"flags" = player_flags,
"id" = player_id,
@@ -232,7 +232,7 @@ GLOBAL_LIST_EMPTY(player_data)
if(!block_on_available())
return FALSE
qdel(SSdbcore.ExecuteQuery(
- "UPDATE [format_table_name("player")] SET lastseen = Now() WHERE id = :id",
+ "UPDATE [DB_PREFIX_TABLE_NAME("player")] SET lastseen = Now() WHERE id = :id",
list(
"id" = player_id,
)
diff --git a/code/modules/client/game_preferences/game_preferences.dm b/code/modules/client/game_preferences/game_preferences.dm
index c54d71592dc..667a98c8d4e 100644
--- a/code/modules/client/game_preferences/game_preferences.dm
+++ b/code/modules/client/game_preferences/game_preferences.dm
@@ -369,7 +369,7 @@
usr = null
var/datum/db_query/query = SSdbcore.NewQuery(
- "SELECT `toggles`, `entries`, `misc`, `keybinds`, `version` FROM [format_table_name("game_preferences")] \
+ "SELECT `toggles`, `entries`, `misc`, `keybinds`, `version` FROM [DB_PREFIX_TABLE_NAME("game_preferences")] \
WHERE `player` = :player",
list(
"player" = authoritative_player_id,
@@ -413,7 +413,7 @@
usr = null
var/datum/db_query/query = SSdbcore.NewQuery(
- "INSERT INTO [format_table_name("game_preferences")] \
+ "INSERT INTO [DB_PREFIX_TABLE_NAME("game_preferences")] \
(`player`, `toggles`, `entries`, `misc`, `keybinds`, `version`, `modified`) VALUES \
(:player, :toggles, :entries, :misc, :keybinds, :version, Now()) ON DUPLICATE KEY UPDATE \
`player` = VALUES(player), `toggles` = VALUES(toggles), `entries` = VALUES(entries), `misc` = VALUES(misc), \
diff --git a/code/modules/language/language.dm b/code/modules/language/language.dm
index be809af403a..ecb4d2eada4 100644
--- a/code/modules/language/language.dm
+++ b/code/modules/language/language.dm
@@ -232,7 +232,7 @@
// Language handling.
/mob/proc/add_language(var/language)
- var/datum/prototype/language/new_language = RSlanguages.fetch(language) || RSlanguages.legacy_resolve_language_name(language)
+ var/datum/prototype/language/new_language = RSlanguages.fetch_or_defer(language) || RSlanguages.legacy_resolve_language_name(language)
if(!istype(new_language) || (new_language in languages))
return 0
@@ -241,12 +241,12 @@
return 1
/mob/proc/remove_language(var/rem_language)
- var/datum/prototype/language/L = RSlanguages.fetch(rem_language)
+ var/datum/prototype/language/L = RSlanguages.fetch_or_defer(rem_language)
. = (L in languages)
languages.Remove(L)
/mob/living/remove_language(rem_language)
- var/datum/prototype/language/L = RSlanguages.fetch(rem_language)
+ var/datum/prototype/language/L = RSlanguages.fetch_or_defer(rem_language)
if(default_language == L)
default_language = null
return ..()
diff --git a/code/modules/library/lib_machines.dm b/code/modules/library/lib_machines.dm
index 3980cecb08d..c9b60e2e4b9 100644
--- a/code/modules/library/lib_machines.dm
+++ b/code/modules/library/lib_machines.dm
@@ -49,7 +49,7 @@