diff --git a/code/__DEFINES/rust.dm b/code/__DEFINES/rust.dm index 2e03bd4f1ee..19f0bdb9b1a 100644 --- a/code/__DEFINES/rust.dm +++ b/code/__DEFINES/rust.dm @@ -131,6 +131,47 @@ /proc/mapmanip_read_dmm(mapname) return RUSTLIB_CALL(mapmanip_read_dmm_file, mapname) +// MARK: TOML +/proc/rustlibs_read_toml_file(path) + var/list/output = json_decode(RUSTLIB_CALL(toml_file_to_json, path) || "null") + if(output["success"]) + return json_decode(output["content"]) + else + CRASH(output["content"]) + +// MARK: Logging +/proc/rustlibs_log_write(fname, text) + return RUSTLIB_CALL(log_write, fname, text) + +/proc/rustlibs_log_close_all() + return RUSTLIB_CALL(log_close_all) + +// MARK: DMI +/proc/rustlibs_dmi_strip_metadata(fname) + return RUSTLIB_CALL(dmi_strip_metadata, fname) + +// MARK: JSON +/proc/rustlibs_json_is_valid(text) + return (RUSTLIB_CALL(json_is_valid, text) == "true") + + +// MARK: Grid Perlin Noise +/** + * This proc generates a grid of perlin-like noise + * + * Returns a single string that goes row by row, with values of 1 representing an turned on cell, and a value of 0 representing a turned off cell. + * + * Arguments: + * * seed: seed for the function + * * accuracy: how close this is to the original perlin noise, as accuracy approaches infinity, the noise becomes more and more perlin-like + * * stamp_size: Size of a singular stamp used by the algorithm, think of this as the same stuff as frequency in perlin noise + * * world_size: size of the returned grid. + * * lower_range: lower bound of values selected for. (inclusive) + * * upper_range: upper bound of values selected for. (exclusive) + */ +/proc/rustlibs_dbp_generate(seed, accuracy, stamp_size, world_size, lower_range, upper_range) + return RUSTLIB_CALL(dbp_generate, seed, accuracy, stamp_size, world_size, lower_range, upper_range) + // MARK: Redis #define RUSTLIBS_REDIS_ERROR_CHANNEL "RUSTG_REDIS_ERROR_CHANNEL" diff --git a/code/__DEFINES/rust_g.dm b/code/__DEFINES/rust_g.dm index 1e977b8b41b..e44c53894b2 100644 --- a/code/__DEFINES/rust_g.dm +++ b/code/__DEFINES/rust_g.dm @@ -48,29 +48,6 @@ /// Gets the version of rust_g /proc/rustg_get_version() return RUSTG_CALL(RUST_G, "get_version")() -// Grid Perlin Noise // - -/** - * This proc generates a grid of perlin-like noise - * - * Returns a single string that goes row by row, with values of 1 representing an turned on cell, and a value of 0 representing a turned off cell. - * - * Arguments: - * * seed: seed for the function - * * accuracy: how close this is to the original perlin noise, as accuracy approaches infinity, the noise becomes more and more perlin-like - * * stamp_size: Size of a singular stamp used by the algorithm, think of this as the same stuff as frequency in perlin noise - * * world_size: size of the returned grid. - * * lower_range: lower bound of values selected for. (inclusive) - * * upper_range: upper bound of values selected for. (exclusive) - */ -#define rustg_dbp_generate(seed, accuracy, stamp_size, world_size, lower_range, upper_range) \ - RUSTG_CALL(RUST_G, "dbp_generate")(seed, accuracy, stamp_size, world_size, lower_range, upper_range) - -// DMI Operations // - -#define rustg_dmi_strip_metadata(fname) RUSTG_CALL(RUST_G, "dmi_strip_metadata")(fname) - - // Git Operations // /// Returns the git hash of the given revision, ex. "HEAD". @@ -111,15 +88,6 @@ #define RUSTG_JOB_NO_SUCH_JOB "NO SUCH JOB" #define RUSTG_JOB_ERROR "JOB PANICKED" -// JSON Operations // - -#define rustg_json_is_valid(text) (RUSTG_CALL(RUST_G, "json_is_valid")(text) == "true") - -// Logging Operations // - -#define rustg_log_write(fname, text) RUSTG_CALL(RUST_G, "log_write")(fname, text) -/proc/rustg_log_close_all() return RUSTG_CALL(RUST_G, "log_close_all")() - // SQL Operations // #define rustg_sql_connect_pool(options) RUSTG_CALL(RUST_G, "sql_connect_pool")(options) @@ -132,14 +100,3 @@ // Toast Operations // #define rustg_create_toast(title, body) RUSTG_CALL(RUST_G, "create_toast")(title, body) - -// TOML Operations // - -#define rustg_raw_read_toml_file(path) json_decode(RUSTG_CALL(RUST_G, "toml_file_to_json")(path) || "null") - -/proc/rustg_read_toml_file(path) - var/list/output = rustg_raw_read_toml_file(path) - if(output["success"]) - return json_decode(output["content"]) - else - CRASH(output["content"]) diff --git a/code/__HELPERS/_logging.dm b/code/__HELPERS/_logging.dm index 8cef0495e8e..be678774055 100644 --- a/code/__HELPERS/_logging.dm +++ b/code/__HELPERS/_logging.dm @@ -32,12 +32,12 @@ GLOBAL_PROTECT(log_end) if(!skip_glob) GLOB.admin_log.Add(text) if(GLOB.configuration.logging.admin_logging) - rustg_log_write(GLOB.world_game_log, "ADMIN: [text][GLOB.log_end]") + rustlibs_log_write(GLOB.world_game_log, "ADMIN: [text][GLOB.log_end]") /proc/log_debug(text) // This has presence checks as this may be called before GLOB has loaded if(GLOB?.configuration?.logging.debug_logging) - rustg_log_write(GLOB.world_game_log, "DEBUG: [text][GLOB.log_end]") + rustlibs_log_write(GLOB.world_game_log, "DEBUG: [text][GLOB.log_end]") for(var/client/C in GLOB.admins) if(check_rights(R_DEBUG | R_VIEWRUNTIMES, FALSE, C.mob) && (C.prefs.toggles & PREFTOGGLE_CHAT_DEBUGLOGS)) @@ -45,65 +45,65 @@ GLOBAL_PROTECT(log_end) /proc/log_game(text) if(GLOB.configuration.logging.game_logging) - rustg_log_write(GLOB.world_game_log, "GAME: [text][GLOB.log_end]") + rustlibs_log_write(GLOB.world_game_log, "GAME: [text][GLOB.log_end]") /proc/log_vote(text) if(GLOB.configuration.logging.vote_logging) - rustg_log_write(GLOB.world_game_log, "VOTE: [text][GLOB.log_end]") + rustlibs_log_write(GLOB.world_game_log, "VOTE: [text][GLOB.log_end]") /proc/log_if_mismatch(mob/who, message, automatic = FALSE) if(istype(usr, /mob) && istype(who) && usr.last_known_ckey != who.last_known_ckey) if(automatic) - rustg_log_write(GLOB.world_game_log, "AUTOMATIC ([usr.last_known_ckey]): [message][GLOB.log_end]") + rustlibs_log_write(GLOB.world_game_log, "AUTOMATIC ([usr.last_known_ckey]): [message][GLOB.log_end]") else - rustg_log_write(GLOB.world_game_log, "LOG USER MISMATCH: [usr.simple_info_line()] was usr for [message][GLOB.log_end]") + rustlibs_log_write(GLOB.world_game_log, "LOG USER MISMATCH: [usr.simple_info_line()] was usr for [message][GLOB.log_end]") /proc/log_access_in(client/new_client) if(GLOB.configuration.logging.access_logging) var/message = "ACCESS IN: [key_name(new_client)] - IP:[new_client.address] - CID:[new_client.computer_id] - BYOND v[new_client.byond_version].[new_client.byond_build]" - rustg_log_write(GLOB.world_game_log, "[message][GLOB.log_end]") + rustlibs_log_write(GLOB.world_game_log, "[message][GLOB.log_end]") log_if_mismatch(new_client.mob, message) /proc/log_access_out(mob/last_mob) if(GLOB.configuration.logging.access_logging) var/message = "ACCESS OUT: [key_name(last_mob)] - IP:[last_mob.lastKnownIP] - CID:[last_mob.computer_id] - BYOND Logged Out" - rustg_log_write(GLOB.world_game_log, "[message][GLOB.log_end]") + rustlibs_log_write(GLOB.world_game_log, "[message][GLOB.log_end]") log_if_mismatch(last_mob, message) /proc/log_say(text, mob/speaker, automatic = FALSE) if(GLOB.configuration.logging.say_logging) var/message = "SAY: [speaker.simple_info_line()]: [html_decode(text)]" - rustg_log_write(GLOB.world_game_log, "[message][GLOB.log_end]") + rustlibs_log_write(GLOB.world_game_log, "[message][GLOB.log_end]") log_if_mismatch(speaker, message, automatic) /proc/log_whisper(text, mob/speaker) if(GLOB.configuration.logging.whisper_logging) var/message = "WHISPER: [speaker.simple_info_line()]: [html_decode(text)]" - rustg_log_write(GLOB.world_game_log, "[message][GLOB.log_end]") + rustlibs_log_write(GLOB.world_game_log, "[message][GLOB.log_end]") log_if_mismatch(speaker, message) /proc/log_ooc(text, client/user) if(GLOB.configuration.logging.ooc_logging) var/message = "OOC: [user.simple_info_line()]: [html_decode(text)]" - rustg_log_write(GLOB.world_game_log, "[message][GLOB.log_end]") + rustlibs_log_write(GLOB.world_game_log, "[message][GLOB.log_end]") log_if_mismatch(user, message) /proc/log_aooc(text, client/user) if(GLOB.configuration.logging.ooc_logging) var/message = "AOOC: [user.simple_info_line()]: [html_decode(text)]" - rustg_log_write(GLOB.world_game_log, "[message][GLOB.log_end]") + rustlibs_log_write(GLOB.world_game_log, "[message][GLOB.log_end]") log_if_mismatch(user, message) /proc/log_looc(text, client/user) if(GLOB.configuration.logging.ooc_logging) var/message = "LOOC: [user.simple_info_line()]: [html_decode(text)]" - rustg_log_write(GLOB.world_game_log, "[message][GLOB.log_end]") + rustlibs_log_write(GLOB.world_game_log, "[message][GLOB.log_end]") log_if_mismatch(user, message) /proc/log_emote(text, mob/speaker) if(GLOB.configuration.logging.emote_logging) var/message = "EMOTE: [speaker.simple_info_line()]: [html_decode(text)]" - rustg_log_write(GLOB.world_game_log, "[message][GLOB.log_end]") + rustlibs_log_write(GLOB.world_game_log, "[message][GLOB.log_end]") log_if_mismatch(speaker, message) /proc/log_attack(mob/attacker, defender_str, attack_message) @@ -112,89 +112,89 @@ GLOBAL_PROTECT(log_end) if(istype(attacker)) attacker_str = attacker.simple_info_line() var/message = "ATTACK: [attacker_str] against [defender_str]: [attack_message]" - rustg_log_write(GLOB.world_game_log, "[message][GLOB.log_end]") + rustlibs_log_write(GLOB.world_game_log, "[message][GLOB.log_end]") log_if_mismatch(attacker, message) /proc/log_adminsay(text, mob/speaker) if(GLOB.configuration.logging.adminchat_logging) var/message = "ADMINSAY: [speaker.simple_info_line()]: [html_decode(text)]" - rustg_log_write(GLOB.world_game_log, "[message][GLOB.log_end]") + rustlibs_log_write(GLOB.world_game_log, "[message][GLOB.log_end]") log_if_mismatch(speaker, message) /proc/log_ping_all_admins(text, mob/speaker) if(GLOB.configuration.logging.adminchat_logging) var/message = "ALL ADMIN PING: [speaker.simple_info_line()]: [html_decode(text)]" - rustg_log_write(GLOB.world_game_log, "[message][GLOB.log_end]") + rustlibs_log_write(GLOB.world_game_log, "[message][GLOB.log_end]") log_if_mismatch(speaker, message) /proc/log_qdel(text) - rustg_log_write(GLOB.world_qdel_log, "QDEL: [text][GLOB.log_end]") + rustlibs_log_write(GLOB.world_qdel_log, "QDEL: [text][GLOB.log_end]") /proc/log_mentorsay(text, mob/speaker) if(GLOB.configuration.logging.adminchat_logging) var/message = "MENTORSAY: [speaker.simple_info_line()]: [html_decode(text)]" - rustg_log_write(GLOB.world_game_log, "[message][GLOB.log_end]") + rustlibs_log_write(GLOB.world_game_log, "[message][GLOB.log_end]") log_if_mismatch(speaker, message) /proc/log_devsay(text, mob/speaker) if(GLOB.configuration.logging.adminchat_logging) var/message = "DEVSAY: [speaker.simple_info_line()]: [html_decode(text)]" - rustg_log_write(GLOB.world_game_log, "[message][GLOB.log_end]") + rustlibs_log_write(GLOB.world_game_log, "[message][GLOB.log_end]") log_if_mismatch(speaker, message) /proc/log_ghostsay(text, mob/speaker) if(GLOB.configuration.logging.say_logging) var/message = "DEADCHAT: [speaker.simple_info_line()]: [html_decode(text)]" - rustg_log_write(GLOB.world_game_log, "[message][GLOB.log_end]") + rustlibs_log_write(GLOB.world_game_log, "[message][GLOB.log_end]") log_if_mismatch(speaker, message) /proc/log_ghostemote(text, mob/speaker) if(GLOB.configuration.logging.emote_logging) var/message = "DEADEMOTE: [speaker.simple_info_line()]: [html_decode(text)]" - rustg_log_write(GLOB.world_game_log, "[message][GLOB.log_end]") + rustlibs_log_write(GLOB.world_game_log, "[message][GLOB.log_end]") log_if_mismatch(speaker, message) /proc/log_adminwarn(text) if(GLOB.configuration.logging.admin_warning_logging) - rustg_log_write(GLOB.world_game_log, "ADMINWARN: [html_decode(text)][GLOB.log_end]") + rustlibs_log_write(GLOB.world_game_log, "ADMINWARN: [html_decode(text)][GLOB.log_end]") /proc/log_pda(text, mob/speaker) if(GLOB.configuration.logging.pda_logging) var/message = "PDA: [speaker.simple_info_line()]: [html_decode(text)]" - rustg_log_write(GLOB.world_game_log, "[message][GLOB.log_end]") + rustlibs_log_write(GLOB.world_game_log, "[message][GLOB.log_end]") log_if_mismatch(speaker, message) /proc/log_chat(text, mob/speaker) if(GLOB.configuration.logging.pda_logging) var/message = "CHAT: [speaker.simple_info_line()] [html_decode(text)]" - rustg_log_write(GLOB.world_game_log, "[message][GLOB.log_end]") + rustlibs_log_write(GLOB.world_game_log, "[message][GLOB.log_end]") log_if_mismatch(speaker, message) /proc/log_tgs(text, level) GLOB.tgs_log += "\[[time_stamp()]] \[[level]] [text]" - rustg_log_write(GLOB.world_game_log, "TGS: [level]: [text][GLOB.log_end]") + rustlibs_log_write(GLOB.world_game_log, "TGS: [level]: [text][GLOB.log_end]") /proc/log_misc(text) - rustg_log_write(GLOB.world_game_log, "MISC: [text][GLOB.log_end]") + rustlibs_log_write(GLOB.world_game_log, "MISC: [text][GLOB.log_end]") /proc/log_world(text) SEND_TEXT(world.log, text) // This has to be presence checked as log_world() is used before world/New(). if(GLOB?.configuration?.logging.world_logging) - rustg_log_write(GLOB.world_game_log, "WORLD: [html_decode(text)][GLOB.log_end]") + rustlibs_log_write(GLOB.world_game_log, "WORLD: [html_decode(text)][GLOB.log_end]") /proc/log_runtime_txt(text) // different from /tg/'s log_runtime because our error handler has a log_runtime proc already that does other stuff - rustg_log_write(GLOB.world_runtime_log, "[text][GLOB.log_end]") + rustlibs_log_write(GLOB.world_runtime_log, "[text][GLOB.log_end]") /proc/log_config(text) - rustg_log_write(GLOB.config_error_log, "[text][GLOB.log_end]") + rustlibs_log_write(GLOB.config_error_log, "[text][GLOB.log_end]") SEND_TEXT(world.log, text) /proc/log_href(text) - rustg_log_write(GLOB.world_href_log, "HREF: [html_decode(text)][GLOB.log_end]") + rustlibs_log_write(GLOB.world_href_log, "HREF: [html_decode(text)][GLOB.log_end]") /proc/log_runtime_summary(text) - rustg_log_write(GLOB.runtime_summary_log, "[text][GLOB.log_end]") + rustlibs_log_write(GLOB.runtime_summary_log, "[text][GLOB.log_end]") /proc/log_tgui(user_or_client, text) var/list/messages = list() @@ -208,22 +208,22 @@ GLOBAL_PROTECT(log_end) messages.Add("[client.ckey]") messages.Add(": [text]") messages.Add("[GLOB.log_end]") - rustg_log_write(GLOB.tgui_log, messages.Join()) + rustlibs_log_write(GLOB.tgui_log, messages.Join()) #ifdef REFERENCE_TRACKING /proc/log_gc(text) - rustg_log_write(GLOB.gc_log, "[text][GLOB.log_end]") + rustlibs_log_write(GLOB.gc_log, "[text][GLOB.log_end]") for(var/client/C in GLOB.admins) if(check_rights(R_DEBUG | R_VIEWRUNTIMES, FALSE, C.mob) && (C.prefs.toggles & PREFTOGGLE_CHAT_DEBUGLOGS)) to_chat(C, "GC DEBUG: [text]") #endif /proc/log_sql(text) - rustg_log_write(GLOB.sql_log, "[text][GLOB.log_end]") + rustlibs_log_write(GLOB.sql_log, "[text][GLOB.log_end]") SEND_TEXT(world.log, text) // Redirect it to DD too /proc/log_chat_debug(text) - rustg_log_write(GLOB.chat_debug_log, "[text][GLOB.log_end]") + rustlibs_log_write(GLOB.chat_debug_log, "[text][GLOB.log_end]") // A logging proc that only outputs after setup is done, to // help devs test initialization stuff that happens a lot @@ -234,7 +234,7 @@ GLOBAL_PROTECT(log_end) /* For logging round startup. */ /proc/start_log(log) - rustg_log_write(log, "Starting up. Round ID is [GLOB.round_id ? GLOB.round_id : "NULL"]\n-------------------------[GLOB.log_end]") + rustlibs_log_write(log, "Starting up. Round ID is [GLOB.round_id ? GLOB.round_id : "NULL"]\n-------------------------[GLOB.log_end]") // Helper procs for building detailed log lines diff --git a/code/controllers/configuration/configuration_core.dm b/code/controllers/configuration/configuration_core.dm index 1d11623e959..ead3006f353 100644 --- a/code/controllers/configuration/configuration_core.dm +++ b/code/controllers/configuration/configuration_core.dm @@ -103,7 +103,7 @@ GLOBAL_DATUM_INIT(configuration, /datum/server_configuration, new()) var/config_file = "config/config.toml" if(!fexists(config_file)) config_file = "config/example/config.toml" // Fallback to example if user hasnt setup config properly - raw_data = rustg_read_toml_file(config_file) + raw_data = rustlibs_read_toml_file(config_file) // Now pass through all our stuff load_all_sections() @@ -147,7 +147,7 @@ GLOBAL_DATUM_INIT(configuration, /datum/server_configuration, new()) DIRECT_OUTPUT(world.log, "Override file [override_file] found. Loading.") var/start = start_watch() // Time tracking - raw_data = rustg_read_toml_file(override_file) + raw_data = rustlibs_read_toml_file(override_file) // Now safely load our overrides. // Due to the nature of config wrappers, only vars that exist in the config file are applied to the config datums. diff --git a/code/controllers/subsystem/SShttp.dm b/code/controllers/subsystem/SShttp.dm index c0e4fb6ca09..061dbd35479 100644 --- a/code/controllers/subsystem/SShttp.dm +++ b/code/controllers/subsystem/SShttp.dm @@ -45,7 +45,7 @@ SUBSYSTEM_DEF(http) log_data += "\tResponse body: [res.body]" log_data += "\tResponse headers: [json_encode(res.headers)]" log_data += "END ASYNC RESPONSE (ID: [req.id])" - rustg_log_write(GLOB.http_log, log_data.Join("\n[GLOB.log_end]")) + rustlibs_log_write(GLOB.http_log, log_data.Join("\n[GLOB.log_end]")) /** * Async request creator @@ -74,7 +74,7 @@ SUBSYSTEM_DEF(http) log_data += "END ASYNC REQUEST (ID: [req.id])" // Write the log data - rustg_log_write(GLOB.http_log, log_data.Join("\n[GLOB.log_end]")) + rustlibs_log_write(GLOB.http_log, log_data.Join("\n[GLOB.log_end]")) /** * Blocking request creator @@ -106,7 +106,7 @@ SUBSYSTEM_DEF(http) log_data += "END BLOCKING REQUEST" // Write the log data - rustg_log_write(GLOB.http_log, log_data.Join("\n[GLOB.log_end]")) + rustlibs_log_write(GLOB.http_log, log_data.Join("\n[GLOB.log_end]")) return res */ diff --git a/code/game/world.dm b/code/game/world.dm index a816a51e53d..733eee0ce5a 100644 --- a/code/game/world.dm +++ b/code/game/world.dm @@ -131,7 +131,7 @@ GLOBAL_LIST_EMPTY(world_topic_handlers) message_admins("[key_name_admin(usr)] has requested an immediate world restart via client side debugging tools") log_admin("[key_name(usr)] has requested an immediate world restart via client side debugging tools") to_chat(world, "Rebooting world immediately due to host request") - rustg_log_close_all() // Past this point, no logging procs can be used, at risk of data loss. + rustlibs_log_close_all() // Past this point, no logging procs can be used, at risk of data loss. // Now handle a reboot if(GLOB.configuration.system.shutdown_on_reboot) sleep(0) @@ -174,12 +174,12 @@ GLOBAL_LIST_EMPTY(world_topic_handlers) C << link("byond://[GLOB.configuration.url.server_url]") // And begin the real shutdown - rustg_log_close_all() // Past this point, no logging procs can be used, at risk of data loss. + rustlibs_log_close_all() // Past this point, no logging procs can be used, at risk of data loss. if(GLOB.configuration.system.shutdown_on_reboot) sleep(0) if(GLOB.configuration.system.shutdown_shell_command) shell(GLOB.configuration.system.shutdown_shell_command) - rustg_log_close_all() // Past this point, no logging procs can be used, at risk of data loss. + rustlibs_log_close_all() // Past this point, no logging procs can be used, at risk of data loss. del(world) TgsEndProcess() // We want to shutdown on reboot. That means kill our TGS process "gracefully", instead of the watchdog crying return diff --git a/code/modules/asset_cache/asset_list.dm b/code/modules/asset_cache/asset_list.dm index cfee41c7ef3..c1e9f5b17be 100644 --- a/code/modules/asset_cache/asset_list.dm +++ b/code/modules/asset_cache/asset_list.dm @@ -165,7 +165,7 @@ GLOBAL_LIST_EMPTY(asset_datums) var/png_name = "[name]_[size_id].png" var/file_directory = "data/spritesheets/[png_name]" fcopy(size[SPRSZ_ICON], file_directory) - var/error = rustg_dmi_strip_metadata(file_directory) + var/error = rustlibs_dmi_strip_metadata(file_directory) if(length(error)) stack_trace("Failed to strip [png_name]: [error]") size[SPRSZ_STRIPPED] = icon(file_directory) diff --git a/code/modules/lavaland/caves_theme.dm b/code/modules/lavaland/caves_theme.dm index 733b2fba856..ef323ab6b25 100644 --- a/code/modules/lavaland/caves_theme.dm +++ b/code/modules/lavaland/caves_theme.dm @@ -92,7 +92,7 @@ GLOBAL_LIST_INIT(caves_default_flora_spawns, list( seed = rand(1, 999999) /datum/caves_theme/proc/setup() - var/result = rustg_dbp_generate("[seed]", "[perlin_accuracy]", "[perlin_stamp_size]", "[world.maxx]", "[perlin_lower_range]", "[perlin_upper_range]") + var/result = rustlibs_dbp_generate("[seed]", "[perlin_accuracy]", "[perlin_stamp_size]", "[world.maxx]", "[perlin_lower_range]", "[perlin_upper_range]") for(var/zlvl in levels_by_trait(ORE_LEVEL)) for(var/turf/T in block(1, 1, zlvl, world.maxx, world.maxy, zlvl)) if(!istype(get_area(T), /area/lavaland/surface/outdoors/unexplored)) diff --git a/code/modules/tgui/external.dm b/code/modules/tgui/external.dm index 53937b57bb6..8052eeacfb6 100644 --- a/code/modules/tgui/external.dm +++ b/code/modules/tgui/external.dm @@ -208,7 +208,7 @@ var/payload if(href_list["payload"]) var/payload_text = href_list["payload"] - if(!rustg_json_is_valid(payload_text)) + if(!rustlibs_json_is_valid(payload_text)) log_tgui(usr, "Error: Invalid JSON") return TRUE diff --git a/code/tests/test_log_format.dm b/code/tests/test_log_format.dm index d3a6f67ca49..51d5e7ffca3 100644 --- a/code/tests/test_log_format.dm +++ b/code/tests/test_log_format.dm @@ -16,11 +16,11 @@ "[generate_test_log_message(world.timeofday + 20)]", ) - rustg_log_write(TEST_LOG_FILE, TEST_MESSAGE) + rustlibs_log_write(TEST_LOG_FILE, TEST_MESSAGE) var/list/lines = file2list(TEST_LOG_FILE) TEST_ASSERT(lines[1] in valid_lines, \ - "RUSTG log format is not valid 8601 format. Expected '[generate_test_log_message(world.timeofday)]', got '[lines[1]]'") + "Rustlibs log format is not valid 8601 format. Expected '[generate_test_log_message(world.timeofday)]', got '[lines[1]]'") #undef TEST_MESSAGE #undef TEST_LOG_FILE diff --git a/rust/Cargo.lock b/rust/Cargo.lock index ec4996d21e0..bcf3f0d577b 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "adler2" @@ -300,6 +300,44 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "crossbeam-deque" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" + +[[package]] +name = "dbpnoise" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2a92e2d3660e5513454071018433d22bbdfc8a79b9bcf1b6399aa72e96b8586" +dependencies = [ + "lerp", + "rand", + "rand_pcg", + "rand_seeder", + "rayon", +] + [[package]] name = "derivative" version = "2.2.0" @@ -385,7 +423,7 @@ dependencies = [ "serde", "serde_derive", "termcolor", - "toml", + "toml 0.5.11", ] [[package]] @@ -516,9 +554,9 @@ checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" [[package]] name = "hashbrown" -version = "0.14.5" +version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" [[package]] name = "iana-time-zone" @@ -700,12 +738,12 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.2.6" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" +checksum = "3954d50fe15b02142bf25d3b8bdadb634ec3948f103d04ffe3031bc8fe9d7058" dependencies = [ "equivalent", - "hashbrown 0.14.5", + "hashbrown 0.15.2", ] [[package]] @@ -762,6 +800,15 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "lerp" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b19ac50d419bff1a024a8eb8034bfbee6c1cf8fa3472502f6bd3def327b09e4c" +dependencies = [ + "num-traits", +] + [[package]] name = "libc" version = "0.2.154" @@ -1042,7 +1089,7 @@ version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6d37c51ca738a55da99dc0c4a34860fd675453b8b36209178c2249bb13651284" dependencies = [ - "toml_edit", + "toml_edit 0.21.1", ] [[package]] @@ -1151,12 +1198,50 @@ dependencies = [ "getrandom", ] +[[package]] +name = "rand_pcg" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59cad018caf63deb318e5a4586d99a24424a364f40f1e5778c29aca23f4fc73e" +dependencies = [ + "rand_core", +] + +[[package]] +name = "rand_seeder" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf2890aaef0aa82719a50e808de264f9484b74b442e1a3a0e5ee38243ac40bdb" +dependencies = [ + "rand_core", +] + [[package]] name = "rawpointer" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3" +[[package]] +name = "rayon" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + [[package]] name = "redis" version = "0.21.7" @@ -1224,6 +1309,7 @@ dependencies = [ "bitflags 2.5.0", "byondapi", "chrono", + "dbpnoise", "diff", "dmm-tools", "dreammaker", @@ -1239,6 +1325,7 @@ dependencies = [ "serde", "serde_json", "thread-priority", + "toml 0.8.20", "walkdir", ] @@ -1316,6 +1403,15 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_spanned" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" +dependencies = [ + "serde", +] + [[package]] name = "sha1" version = "0.6.1" @@ -1446,10 +1542,25 @@ dependencies = [ ] [[package]] -name = "toml_datetime" -version = "0.6.5" +name = "toml" +version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" +checksum = "cd87a5cdd6ffab733b2f74bc4fd7ee5fff6634124999ac278c35fc78c6120148" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit 0.22.24", +] + +[[package]] +name = "toml_datetime" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" +dependencies = [ + "serde", +] [[package]] name = "toml_edit" @@ -1457,9 +1568,22 @@ version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1" dependencies = [ - "indexmap 2.2.6", + "indexmap 2.8.0", "toml_datetime", - "winnow", + "winnow 0.5.40", +] + +[[package]] +name = "toml_edit" +version = "0.22.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17b4795ff5edd201c7cd6dca065ae59972ce77d1b80fa0a84d94950ece7d1474" +dependencies = [ + "indexmap 2.8.0", + "serde", + "serde_spanned", + "toml_datetime", + "winnow 0.7.4", ] [[package]] @@ -1689,6 +1813,15 @@ dependencies = [ "memchr", ] +[[package]] +name = "winnow" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e97b544156e9bebe1a0ffbc03484fc1ffe3100cbce3ffb17eac35f7cdd7ab36" +dependencies = [ + "memchr", +] + [[package]] name = "write16" version = "1.0.0" diff --git a/rust/Cargo.toml b/rust/Cargo.toml index 7c172bb9baf..e1029d47aa7 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -36,6 +36,8 @@ walkdir = "2.5.0" regex = "1.10.5" png = "0.17.16" chrono = "0.4.39" +toml = "0.8.20" +dbpnoise = "0.1.2" # redis - DO NOT CHANGE FROM 0.21.4 - also dont touch flume either please k thx. if you mess with these you make redis unstable redis = { version = "0.21.4" } flume = { version = "0.10" } diff --git a/rust/src/lib.rs b/rust/src/lib.rs index fac8cc82eea..3355dcfcfd9 100644 --- a/rust/src/lib.rs +++ b/rust/src/lib.rs @@ -2,6 +2,12 @@ mod logging; mod mapmanip; mod milla; mod redis_pubsub; +mod rustlibs_dmi; +mod rustlibs_file; +mod rustlibs_json; +mod rustlibs_logging; +mod rustlibs_noisegen; +mod rustlibs_toml; #[cfg(all(not(feature = "byond-515"), not(feature = "byond-516")))] compile_error!("Please specify byond-515 or byond-516 as a feature to specify BYOND version."); diff --git a/rust/src/rustlibs_dmi/mod.rs b/rust/src/rustlibs_dmi/mod.rs new file mode 100644 index 00000000000..1f91828feff --- /dev/null +++ b/rust/src/rustlibs_dmi/mod.rs @@ -0,0 +1,30 @@ +use byondapi::value::ByondValue; +use png::{Decoder, Encoder}; +use std::fs::File; + +#[byondapi::bind] +fn dmi_strip_metadata(path: ByondValue) -> eyre::Result { + strip_metadata(&path.get_string()?)?; + Ok(ByondValue::null()) +} + +fn strip_metadata(path: &str) -> eyre::Result<()> { + let mut reader = Decoder::new(File::open(path)?).read_info()?; + let mut buf = vec![0; reader.output_buffer_size()]; + let frame_info = reader.next_frame(&mut buf)?; + + let mut encoder = Encoder::new(File::create(path)?, frame_info.width, frame_info.height); + encoder.set_color(frame_info.color_type); + encoder.set_depth(frame_info.bit_depth); + let reader_info = reader.info(); + + if let Some(palette) = reader_info.palette.clone() { + encoder.set_palette(palette); + } + if let Some(trns_chunk) = reader_info.trns.clone() { + encoder.set_palette(trns_chunk); + } + + let mut writer = encoder.write_header()?; + Ok(writer.write_image_data(&buf)?) +} diff --git a/rust/src/rustlibs_file/mod.rs b/rust/src/rustlibs_file/mod.rs new file mode 100644 index 00000000000..fae07c4004c --- /dev/null +++ b/rust/src/rustlibs_file/mod.rs @@ -0,0 +1,46 @@ +use byondapi::value::ByondValue; +use std::{ + fs::File, + io::{BufReader, BufWriter, Read, Write}, +}; + +#[byondapi::bind] +fn file_read(path: ByondValue) -> eyre::Result { + read(&path.get_string()?) +} + +fn read(path: &str) -> eyre::Result { + let file = File::open(path)?; + let metadata = file.metadata()?; + let mut file = BufReader::new(file); + + let mut content = String::with_capacity(metadata.len() as usize); + file.read_to_string(&mut content)?; + let content = content.replace('\r', ""); + + Ok(content.try_into()?) +} + +#[byondapi::bind] +fn file_write(data: ByondValue, path: ByondValue) -> eyre::Result { + let data: String = data.get_string()?; + let path: String = path.get_string()?; + write(&data, &path) +} + +fn write(data: &str, path: &str) -> eyre::Result { + let path: &std::path::Path = path.as_ref(); + if let Some(parent) = path.parent() { + std::fs::create_dir_all(parent)?; + } + + let mut file = BufWriter::new(File::create(path)?); + let written = file.write(data.as_bytes())? as f32; + + file.flush()?; + file.into_inner() + .map_err(|e| std::io::Error::new(e.error().kind(), e.error().to_string()))? + .sync_all()?; + + Ok(written.into()) +} diff --git a/rust/src/rustlibs_json/mod.rs b/rust/src/rustlibs_json/mod.rs new file mode 100644 index 00000000000..58a165d1a69 --- /dev/null +++ b/rust/src/rustlibs_json/mod.rs @@ -0,0 +1,77 @@ +use byondapi::value::ByondValue; +use serde_json::Value; +use std::cmp; + +const VALID_JSON_MAX_RECURSION_DEPTH: usize = 8; + +#[byondapi::bind] +fn json_is_valid(text: ByondValue) -> eyre::Result { + let value = match serde_json::from_str::(&text.get_string()?) { + Ok(value) => value, + Err(_) => return Ok("false".try_into()?), + }; + + Ok(get_recursion_level(&value).is_ok().to_string().try_into()?) +} + +/// Gets the recursion level of the given value +/// If it is above `VALID_JSON_MAX_RECURSION_DEPTH`, returns Err(()) +fn get_recursion_level(value: &Value) -> Result { + let values: Vec<&Value> = match value { + Value::Array(array) => array.iter().collect(), + + Value::Object(map) => map.values().collect(), + + _ => return Ok(0), + }; + + let mut max_recursion_level = 0; + + for value in values { + max_recursion_level = cmp::max(max_recursion_level, get_recursion_level(value)?); + } + + max_recursion_level += 1; + + if max_recursion_level >= VALID_JSON_MAX_RECURSION_DEPTH { + Err(()) + } else { + Ok(max_recursion_level) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_get_recursion_level() { + assert_eq!( + get_recursion_level(&serde_json::from_str("[]").unwrap()), + Ok(1) + ); + assert_eq!( + get_recursion_level(&serde_json::from_str("[[]]").unwrap()), + Ok(2) + ); + assert_eq!( + get_recursion_level(&serde_json::from_str("[[[]]]").unwrap()), + Ok(3) + ); + } + + #[test] + fn test_get_recursion_level_max_depth() { + assert_eq!( + get_recursion_level( + &serde_json::from_str(&format!( + "{}{}", + "[".repeat(VALID_JSON_MAX_RECURSION_DEPTH), + "]".repeat(VALID_JSON_MAX_RECURSION_DEPTH) + )) + .unwrap() + ), + Err(()) + ); + } +} diff --git a/rust/src/rustlibs_logging/mod.rs b/rust/src/rustlibs_logging/mod.rs new file mode 100644 index 00000000000..3cb75ea4f33 --- /dev/null +++ b/rust/src/rustlibs_logging/mod.rs @@ -0,0 +1,58 @@ +use byondapi::value::ByondValue; +use chrono::Utc; +use eyre::Context; +use std::{ + cell::RefCell, + collections::hash_map::{Entry, HashMap}, + ffi::OsString, + fs, + fs::{File, OpenOptions}, + io::Write, + path::Path, +}; + +thread_local! { + static FILE_MAP: RefCell> = RefCell::new(HashMap::new()); +} + +#[byondapi::bind] +fn log_write(path: ByondValue, data: ByondValue) -> eyre::Result { + FILE_MAP.with(|cell| -> eyre::Result { + let mut map = cell.borrow_mut(); + let path = path.get_string()?; + let path = Path::new(&path as &str); + let file = match map.entry(path.into()) { + Entry::Occupied(e) => e.into_mut(), + Entry::Vacant(e) => e.insert(open(path)?), + }; + // Byond will happily send over invalid bytes from unpurged text macros, which Rust does not like + // This circumvents ByondValue::get_string() to strip utf-8 before it can cause a panic + let data = data + .get_cstring() + .map(|cstring| cstring.to_string_lossy().into_owned()) + .wrap_err(format!("UTF-8 decode error: {:#?}", data))?; + let iter = data.split('\n'); + + for line in iter { + writeln!(file, "[{}] {}", Utc::now().format("%FT%T"), line)?; + } + + Ok(ByondValue::null()) + }) +} + +#[byondapi::bind] +fn log_close_all() -> eyre::Result { + FILE_MAP.with(|cell| { + let mut map = cell.borrow_mut(); + map.clear(); + }); + Ok(ByondValue::null()) +} + +fn open(path: &Path) -> eyre::Result { + if let Some(parent) = path.parent() { + fs::create_dir_all(parent)?; + } + Ok(OpenOptions::new().append(true).create(true).open(path)?) +} diff --git a/rust/src/rustlibs_noisegen/mod.rs b/rust/src/rustlibs_noisegen/mod.rs new file mode 100644 index 00000000000..50772877476 --- /dev/null +++ b/rust/src/rustlibs_noisegen/mod.rs @@ -0,0 +1,61 @@ +use byondapi::value::ByondValue; +use dbpnoise::gen_noise; + +#[byondapi::bind] +fn dbp_generate( + seed: ByondValue, + accuracy: ByondValue, + stamp_size: ByondValue, + world_size: ByondValue, + lower_range: ByondValue, + upper_range: ByondValue, +) -> eyre::Result { + Ok(gen_dbp_noise( + &seed.get_string()?, + &accuracy.get_string()?, + &stamp_size.get_string()?, + &world_size.get_string()?, + &lower_range.get_string()?, + &upper_range.get_string()?, + )? + .try_into()?) +} + +fn gen_dbp_noise( + seed: &str, + accuracy: &str, + stamp_size: &str, + world_size: &str, + lower_range: &str, + upper_range: &str, +) -> eyre::Result { + let map: Vec> = gen_noise( + seed, + accuracy.parse::()?, + stamp_size.parse::()?, + world_size.parse::()?, + lower_range.parse::()?, + upper_range.parse::()?, + ); + let mut result = String::new(); + for row in map { + for cell in row { + result.push(if cell { '1' } else { '0' }); + } + } + Ok(result) +} + +#[cfg(test)] +mod tests { + use super::gen_dbp_noise; + + const TEST_SEED: &str = "meowrrpmraoooow~"; + #[test] + fn test_gen_dbp_noise() { + let value = gen_dbp_noise(TEST_SEED, "360", "4", "25", "0.1", "1.1").unwrap(); + println!("(length: {})", value.len()); + println!("{}", value); + assert_eq!(value.len(), 625); + } +} diff --git a/rust/src/rustlibs_toml/mod.rs b/rust/src/rustlibs_toml/mod.rs new file mode 100644 index 00000000000..4c124da1314 --- /dev/null +++ b/rust/src/rustlibs_toml/mod.rs @@ -0,0 +1,41 @@ +use byondapi::value::ByondValue; + +#[byondapi::bind] +fn toml_file_to_json(path: ByondValue) -> eyre::Result { + let path: String = path.get_string()?; + Ok(serde_json::to_string(&match toml_file_to_json_impl(&path) { + Ok(value) => serde_json::json!({ + "success": true, "content": value + }), + Err(error) => serde_json::json!({ + "success": false, "content": error.to_string() + }), + })? + .try_into()?) +} + +fn toml_file_to_json_impl(path: &str) -> eyre::Result { + Ok(serde_json::to_string(&toml::from_str::( + &std::fs::read_to_string(path)?, + )?)?) +} + +#[byondapi::bind] +fn toml_encode(value: ByondValue) -> eyre::Result { + let path: String = value.get_string()?; + Ok(serde_json::to_string(&match toml_encode_impl(&path) { + Ok(value) => serde_json::json!({ + "success": true, "content": value + }), + Err(error) => serde_json::json!({ + "success": false, "content": error.to_string() + }), + })? + .try_into()?) +} + +fn toml_encode_impl(value: &str) -> eyre::Result { + Ok(toml::to_string_pretty( + &serde_json::from_str::(value)?, + )?) +} diff --git a/rustlibs_515.dll b/rustlibs_515.dll index a4fbe8dc5b4..4ab1aade6a8 100644 Binary files a/rustlibs_515.dll and b/rustlibs_515.dll differ diff --git a/rustlibs_515_prod.dll b/rustlibs_515_prod.dll index 865dba9cb08..38101a1497e 100644 Binary files a/rustlibs_515_prod.dll and b/rustlibs_515_prod.dll differ diff --git a/rustlibs_516.dll b/rustlibs_516.dll index 68cba82245e..4cfaa50d943 100644 Binary files a/rustlibs_516.dll and b/rustlibs_516.dll differ diff --git a/rustlibs_516_prod.dll b/rustlibs_516_prod.dll index 2b6955c58ba..39f1011f2de 100644 Binary files a/rustlibs_516_prod.dll and b/rustlibs_516_prod.dll differ diff --git a/tools/ci/librustlibs_ci_515.so b/tools/ci/librustlibs_ci_515.so index cfce5816183..68365a350ed 100644 Binary files a/tools/ci/librustlibs_ci_515.so and b/tools/ci/librustlibs_ci_515.so differ diff --git a/tools/ci/librustlibs_ci_516.so b/tools/ci/librustlibs_ci_516.so index 5d6752530e2..2b8ed1323e8 100644 Binary files a/tools/ci/librustlibs_ci_516.so and b/tools/ci/librustlibs_ci_516.so differ