From 5a62077f2c86d7b6a54b3d128dd7e62a96adf0bd Mon Sep 17 00:00:00 2001
From: CHOMPStation2StaffMirrorBot
<94713762+CHOMPStation2StaffMirrorBot@users.noreply.github.com>
Date: Sun, 14 Sep 2025 11:05:26 -0700
Subject: [PATCH] [MIRROR] JSON Logging Refactor (#11623)
Co-authored-by: Selis <12716288+ItsSelis@users.noreply.github.com>
Co-authored-by: Kashargul <144968721+Kashargul@users.noreply.github.com>
---
SQL/DBSchema.sql | 25 -
archive/maps/gateway_archive_vr/labyrinth.dm | 2 +-
.../events/wildlife_encounter.dm | 10 +-
code/ZAS/Fire.dm | 22 +-
code/ZAS/Variable Settings.dm | 4 +-
code/__defines/_flags.dm | 2 +
code/__defines/_helpers.dm | 14 +
code/__defines/_tick.dm | 2 -
code/__defines/logging.dm | 132 ++-
code/__defines/shuttle.dm | 2 +-
code/__defines/stack_trace.dm | 4 +
code/__defines/tgs.config.dm | 6 +-
code/_compile_options.dm | 7 +
code/_global_vars/logging.dm | 43 +
code/_helpers/_lists.dm | 2 +-
code/_helpers/files.dm | 14 -
code/_helpers/global_lists.dm | 2 -
code/_helpers/guid.dm | 19 +
code/_helpers/logging.dm | 423 ---------
code/_helpers/logging/_logging.dm | 274 ++++++
code/_helpers/logging/admin.dm | 42 +
code/_helpers/logging/attack.dm | 40 +
code/_helpers/logging/debug.dm | 53 +-
code/_helpers/logging/game.dm | 27 +
code/_helpers/logging/mob.dm | 54 ++
code/_helpers/logging/pda.dm | 3 +
code/_helpers/logging/research.dm | 6 +
code/_helpers/logging/talk.dm | 25 +
code/_helpers/logging/ui.dm | 19 +-
code/_helpers/logging_vr.dm | 53 --
code/_helpers/mobs.dm | 26 +-
code/_helpers/stack_trace.dm | 4 +
code/_helpers/text.dm | 12 +
code/_helpers/time.dm | 9 +-
code/_helpers/turfs.dm | 4 +-
code/_helpers/type2type.dm | 64 +-
code/_helpers/unsorted.dm | 42 +-
code/_macros.dm | 16 -
code/_onclick/hud/ability_screen_objects.dm | 4 +-
code/_onclick/telekinesis.dm | 2 +-
code/controllers/autotransfer.dm | 2 +-
.../configuration/configuration.dm | 2 +-
.../configuration/entries/general.dm | 46 +-
code/controllers/globals.dm | 4 +-
code/controllers/hooks.dm | 4 +-
code/controllers/master.dm | 4 +-
code/controllers/master_controller.dm | 2 +-
code/controllers/subsystems/air.dm | 2 +-
code/controllers/subsystems/chemistry.dm | 1 -
code/controllers/subsystems/dbcore.dm | 22 +-
code/controllers/subsystems/events.dm | 4 +-
code/controllers/subsystems/events2.dm | 4 +-
code/controllers/subsystems/game_master.dm | 6 +-
code/controllers/subsystems/garbage.dm | 2 +-
code/controllers/subsystems/job.dm | 6 +-
code/controllers/subsystems/machines.dm | 8 +-
code/controllers/subsystems/mapping.dm | 22 +-
code/controllers/subsystems/media_tracks.dm | 14 +-
.../subsystems/overmap_renamer_vr.dm | 4 +-
code/controllers/subsystems/pathfinder_ch.dm | 6 +-
code/controllers/subsystems/pois.dm | 4 +-
.../subsystems/processing/bellies_vr.dm | 6 +-
.../subsystems/processing/fastprocess.dm | 4 +-
code/controllers/subsystems/processing/obj.dm | 6 +-
.../subsystems/processing/processing.dm | 6 +-
.../subsystems/processing/projectiles.dm | 4 +-
.../subsystems/processing/turfs.dm | 6 +-
code/controllers/subsystems/reflect_ch.dm | 4 +-
code/controllers/subsystems/shuttles.dm | 6 +-
code/controllers/subsystems/sqlite.dm | 10 +-
code/controllers/subsystems/supply.dm | 2 +-
code/controllers/subsystems/ticker.dm | 16 +-
code/controllers/subsystems/time_track.dm | 126 ++-
code/controllers/subsystems/transcore_vr.dm | 16 +-
code/controllers/subsystems/vote.dm | 8 +-
code/controllers/subsystems/webhooks.dm | 20 +-
code/datums/api.dm | 6 +-
code/datums/autolathe/autolathe.dm | 2 +-
.../antags/changeling/changeling.dm | 2 +-
code/datums/components/recursive_move.dm | 12 +-
.../species/shadekin/powers/phase_shift.dm | 2 +-
code/datums/datacore.dm | 4 +-
code/datums/datum.dm | 10 +
code/datums/elements/turf_transparency.dm | 2 +-
code/datums/helper_datums/getrev.dm | 2 +-
code/datums/mind.dm | 4 +-
code/datums/repositories/unique.dm | 2 +-
code/defines/procs/announce.dm | 10 +-
code/game/antagonist/antagonist.dm | 20 +-
code/game/antagonist/antagonist_objectives.dm | 4 +-
code/game/antagonist/antagonist_print.dm | 2 +-
code/game/antagonist/outsider/raider.dm | 4 +-
code/game/antagonist/outsider/technomancer.dm | 4 +-
code/game/antagonist/outsider/wizard.dm | 2 +-
code/game/antagonist/station/rogue_ai.dm | 4 +-
code/game/area/Away Mission areas.dm | 4 +-
code/game/area/Space Station 13 areas_vr.dm | 2 +-
code/game/gamemodes/calamity/calamity.dm | 2 +-
code/game/gamemodes/cult/narsie.dm | 4 +-
code/game/gamemodes/cult/runes.dm | 4 +-
.../endgame/supermatter_cascade/universe.dm | 2 +-
code/game/gamemodes/events.dm | 2 +-
.../gamemodes/events/holidays/Holidays.dm | 6 +-
code/game/gamemodes/game_mode.dm | 16 +-
.../newmalf_ability_trees/HELPERS.dm | 2 +-
code/game/gamemodes/meteor/meteor.dm | 4 +-
code/game/gamemodes/meteor/meteors.dm | 2 +-
code/game/gamemodes/nuclear/nuclear.dm | 36 +-
code/game/gamemodes/setupgame.dm | 2 +-
code/game/jobs/job_controller.dm | 4 +-
code/game/jobs/whitelist.dm | 8 +-
code/game/jobs/whitelist_vr.dm | 2 +-
code/game/machinery/atm_ret_field.dm | 2 +-
code/game/machinery/camera/camera.dm | 4 +-
code/game/machinery/camera/motion.dm | 2 +-
code/game/machinery/computer/guestpass.dm | 2 +-
code/game/machinery/computer/shuttle.dm | 10 +-
code/game/machinery/doors/firedoor.dm | 2 +-
.../embedded_controller/docking_program.dm | 2 +-
.../embedded_controller/mapping_helpers.dm | 9 +-
code/game/machinery/flasher.dm | 2 +-
code/game/machinery/gear_dispenser.dm | 14 +-
code/game/machinery/machinery.dm | 2 +-
code/game/machinery/navbeacon.dm | 4 +-
code/game/machinery/nuclear_bomb.dm | 4 +-
code/game/machinery/pointdefense.dm | 2 +-
.../machinery/telecomms/telecomunications.dm | 2 +-
.../machinery/virtual_reality/vr_procs.dm | 4 +-
code/game/mecha/equipment/mecha_equipment.dm | 10 +-
.../game/mecha/equipment/tools/cable_layer.dm | 4 +-
code/game/mecha/equipment/tools/clamp.dm | 4 +-
code/game/mecha/equipment/tools/cloak.dm | 4 +-
code/game/mecha/equipment/tools/drill.dm | 16 +-
.../mecha/equipment/tools/energy_relay.dm | 4 +-
code/game/mecha/equipment/tools/generator.dm | 10 +-
code/game/mecha/equipment/tools/jetpack.dm | 6 +-
code/game/mecha/equipment/tools/passenger.dm | 4 +-
.../mecha/equipment/tools/repair_droid.dm | 4 +-
code/game/mecha/equipment/tools/shield.dm | 4 +-
.../game/mecha/equipment/tools/shield_omni.dm | 4 +-
code/game/mecha/equipment/tools/sleeper.dm | 8 +-
.../game/mecha/equipment/tools/syringe_gun.dm | 12 +-
.../equipment/weapons/ballistic/ballistic.dm | 2 +-
code/game/mecha/equipment/weapons/honk.dm | 2 +-
code/game/mecha/equipment/weapons/weapons.dm | 2 +-
code/game/mecha/mecha.dm | 71 +-
code/game/mecha/micro/micro_equipment.dm | 6 +-
code/game/memory_profiler_ch.dm | 2 +-
code/game/objects/effects/chem/chemsmoke.dm | 6 +-
code/game/objects/effects/gibs.dm | 3 +-
code/game/objects/effects/landmarks.dm | 4 +-
.../objects/effects/map_effects/beam_point.dm | 6 +-
code/game/objects/effects/prop/columnblast.dm | 2 +-
code/game/objects/effects/prop/snake.dm | 8 +-
code/game/objects/items/blueprints_vr.dm | 2 +-
.../items/devices/communicator/UI_tgui.dm | 2 +-
.../items/devices/communicator/messaging.dm | 4 +-
.../items/devices/radio/encryptionkey.dm | 55 ++
.../objects/items/devices/radio/jammer.dm | 15 +
.../objects/items/devices/radio/jammer_vr.dm | 14 -
.../game/objects/items/devices/radio/radio.dm | 36 +-
.../objects/items/devices/radio/radio_vr.dm | 33 -
.../objects/items/devices/transfer_valve.dm | 2 +-
.../items/devices/uplink_random_lists.dm | 2 +-
.../weapons/grenades/anti_photon_grenade.dm | 2 +-
.../game/objects/items/weapons/tanks/tanks.dm | 6 +-
code/game/objects/structures/artstuff.dm | 8 +-
code/game/objects/structures/catwalk.dm | 2 +-
code/game/objects/structures/droppod.dm | 2 +-
code/game/objects/structures/lattice.dm | 2 +-
code/game/objects/structures/low_wall.dm | 4 +-
code/game/turfs/simulated/fancy_shuttles.dm | 8 +-
code/game/turfs/simulated/wall_types.dm | 2 +-
code/game/turfs/unsimulated/sky_vr.dm | 2 +-
code/game/vehicles/vehicle.dm | 4 +-
code/game/world.dm | 115 +--
code/js/view_variables.js | 22 +-
code/modules/admin/IsBanned.dm | 21 +-
code/modules/admin/ToRban.dm | 8 +-
code/modules/admin/admin.dm | 48 +-
code/modules/admin/admin_tools.dm | 54 +-
code/modules/admin/admin_verb_lists_vr.dm | 1 -
code/modules/admin/admin_verbs.dm | 4 +
code/modules/admin/banjob.dm | 3 +-
code/modules/admin/holder2.dm | 2 +-
code/modules/admin/player_panel.dm | 2 +-
code/modules/admin/topic.dm | 4 +-
code/modules/admin/verbs/BrokenInhands.dm | 2 +-
code/modules/admin/verbs/adminsay.dm | 6 +-
code/modules/admin/verbs/antag-ooc.dm | 2 +-
code/modules/admin/verbs/cinematic.dm | 2 +-
code/modules/admin/verbs/custom_event.dm | 8 +-
code/modules/admin/verbs/debug.dm | 46 +-
code/modules/admin/verbs/dice.dm | 4 +-
code/modules/admin/verbs/grief_fixers.dm | 4 +-
code/modules/admin/verbs/mapping.dm | 8 +-
code/modules/admin/verbs/playsound.dm | 2 +-
code/modules/admin/verbs/pray.dm | 2 +-
code/modules/admin/verbs/randomverbs.dm | 6 +-
code/modules/admin/verbs/striketeam.dm | 2 +-
code/modules/admin/verbs/trader.dm | 2 +-
code/modules/ai/ai_holder.dm | 2 +-
code/modules/ai/ai_holder_debug.dm | 4 +-
code/modules/assembly/holder.dm | 2 +-
code/modules/assembly/proximity.dm | 2 +-
code/modules/asset_cache/asset_cache_item.dm | 2 +-
code/modules/awaymissions/gateway.dm | 4 +-
code/modules/awaymissions/gateway_vr.dm | 2 +-
.../overmap_renamer/overmap_renamer.dm | 8 +-
code/modules/awaymissions/zlevel.dm | 6 +-
code/modules/blob2/overmind/overmind.dm | 2 +-
code/modules/client/client defines.dm | 3 +
code/modules/client/client procs.dm | 83 +-
code/modules/client/persistent_client.dm | 107 +++
.../preference_setup/general/12_traits.dm | 6 +-
.../preference_setup/loadout/02_loadout.dm | 6 +-
code/modules/client/preferences.dm | 4 +-
code/modules/client/preferences_savefile.dm | 28 +-
code/modules/client/shock.dm | 2 +-
code/modules/client/verbs/ooc.dm | 4 +-
code/modules/clothing/clothing.dm | 2 +-
code/modules/customitems/item_spawning.dm | 6 +-
code/modules/emotes/custom_emote.dm | 2 +-
code/modules/error_handler/_defines.dm | 9 -
code/modules/error_handler/error_handler.dm | 195 ++--
code/modules/error_handler/error_viewer.dm | 270 +++---
code/modules/error_handler/~defines.dm | 6 -
code/modules/events/atmos_leak.dm | 6 +-
code/modules/events/canister_leak.dm | 6 +-
code/modules/events/carp_migration.dm | 2 +-
code/modules/events/electrical_storm.dm | 2 +-
code/modules/events/event_container.dm | 4 +-
code/modules/events/event_dynamic.dm | 2 +-
code/modules/events/prison_break.dm | 2 +-
code/modules/events/spacefish_migration.dm | 2 +-
code/modules/events/supply_demand_vr.dm | 8 +-
code/modules/food/kitchen/gibber.dm | 2 +-
.../events/command/manifest_malfunction.dm | 2 +-
.../event2/events/command/money_hacker.dm | 6 +-
.../event2/events/command/raise_funds.dm | 14 +-
.../events/engineering/airlock_failure.dm | 4 +-
.../event2/events/engineering/blob.dm | 4 +-
.../events/engineering/brand_intelligence.dm | 2 +-
.../events/engineering/canister_leak.dm | 2 +-
.../event2/events/engineering/gas_leak.dm | 2 +-
.../event2/events/engineering/wallrot.dm | 4 +-
.../event2/events/engineering/window_break.dm | 10 +-
.../event2/events/everyone/comms_blackout.dm | 4 +-
.../events/everyone/electrical_fault.dm | 10 +-
.../event2/events/everyone/infestation.dm | 2 +-
.../event2/events/everyone/pda_spam.dm | 6 +-
.../events/everyone/sudden_weather_shift.dm | 4 +-
.../event2/events/ghost_pod_spawner.dm | 2 +-
.../event2/events/medical/appendicitis.dm | 4 +-
.../event2/events/security/prison_break.dm | 2 +-
.../events/security/security_advisement.dm | 2 +-
.../events/security/spider_infestation.dm | 2 +-
.../event2/events/security/surprise_carp.dm | 6 +-
code/modules/holodeck/HolodeckControl.dm | 2 +-
code/modules/holomap/mapper.dm | 2 +-
code/modules/hydroponics/grown.dm | 4 +-
code/modules/hydroponics/seed_gene_mut.dm | 2 +-
.../hydroponics/spreading/spreading.dm | 2 +-
.../spreading/spreading_response.dm | 2 +-
.../hydroponics/trays/tray_update_icons.dm | 2 +-
code/modules/keybindings/bindings_movekeys.dm | 2 +-
code/modules/lighting/lighting_fake_sun_vr.dm | 2 +-
.../logging/categories/log_category_admin.dm | 33 +
.../categories/log_category_compats.dm | 7 +
.../logging/categories/log_category_debug.dm | 23 +
.../logging/categories/log_category_game.dm | 48 +
.../logging/categories/log_category_href.dm | 6 +
.../categories/log_category_internal.dm | 6 +
.../logging/categories/log_category_misc.dm | 20 +
.../logging/categories/log_category_pda.dm | 3 +
code/modules/logging/log_category.dm | 70 ++
code/modules/logging/log_entry.dm | 127 +++
code/modules/logging/log_holder.dm | 356 ++++++++
code/modules/looking_glass/lg_area.dm | 2 +-
code/modules/looking_glass/lg_console.dm | 2 +-
code/modules/looking_glass/lg_imageholder.dm | 4 +-
code/modules/lore_codex/codex_tree.dm | 2 +-
code/modules/maps/bapi-dmm/bapi_dmm_reader.dm | 2 +-
.../modules/materials/materials/_materials.dm | 4 +-
code/modules/media/juke_remote.dm | 2 +-
code/modules/media/mediamanager.dm | 2 +-
code/modules/metric/activity.dm | 6 +-
.../mining/machinery/machine_processing.dm | 2 +-
code/modules/mining/mineral_effect.dm | 2 +-
code/modules/mining/resonator_vr.dm | 5 -
code/modules/mob/dead/observer/observer.dm | 2 +-
code/modules/mob/dead/observer/say.dm | 4 +-
code/modules/mob/emote.dm | 2 +-
code/modules/mob/language/generic.dm | 2 +-
code/modules/mob/language/language.dm | 4 +-
code/modules/mob/language/station.dm | 6 +-
code/modules/mob/language/station_vr.dm | 2 +-
code/modules/mob/living/carbon/human/human.dm | 2 +-
.../mob/living/carbon/human/human_damage.dm | 4 +-
.../mob/living/carbon/human/human_powers.dm | 4 +-
code/modules/mob/living/carbon/human/life.dm | 3 -
.../human/species/lleill/lleill_abilities.dm | 26 -
.../living/carbon/human/species/species.dm | 2 +-
.../human/species/station/prommie_blob.dm | 2 +-
.../human/species/station/traits/positive.dm | 4 +-
code/modules/mob/living/damage_procs.dm | 4 +-
code/modules/mob/living/living_defense.dm | 6 +-
code/modules/mob/living/say.dm | 4 +-
code/modules/mob/living/silicon/ai/malf.dm | 2 +-
code/modules/mob/living/silicon/pai/pai_vr.dm | 2 +-
.../mob/living/silicon/pai/software.dm | 2 +-
code/modules/mob/living/silicon/say.dm | 4 +-
.../subtypes/animal/alien animals/stardog.dm | 14 +-
.../subtypes/animal/borer/borer_captive.dm | 2 +-
.../simple_mob/subtypes/glamour/ddraig.dm | 15 -
code/modules/mob/login.dm | 26 +-
code/modules/mob/logout.dm | 2 +-
code/modules/mob/mob.dm | 6 +
code/modules/mob/mob_defines.dm | 18 +-
code/modules/mob/mob_movement.dm | 2 +-
code/modules/mob/new_player/lobby_browser.dm | 2 +-
code/modules/mob/new_player/login.dm | 4 +-
code/modules/mob/new_player/logout.dm | 2 +-
code/modules/mob/new_player/new_player_vr.dm | 2 +-
code/modules/mob/say_vr.dm | 8 +-
code/modules/multiz/stairs.dm | 10 +-
code/modules/news/news_init.dm | 4 +-
.../nifsoft/software/13_soulcatcher.dm | 4 +-
code/modules/organs/blood.dm | 8 +-
code/modules/organs/organ.dm | 2 +-
code/modules/organs/subtypes/standard.dm | 2 +-
code/modules/overmap/champagne.dm | 2 +-
code/modules/overmap/events/event_handler.dm | 2 +-
code/modules/overmap/ships/panicbutton.dm | 2 +-
code/modules/overmap/spacetravel.dm | 2 +-
code/modules/pda/messenger.dm | 2 +-
code/modules/pda/pda.dm | 2 +-
code/modules/pda/utilities.dm | 2 +-
.../persistence/storage/smartfridge.dm | 2 +-
code/modules/planet/sun.dm | 2 +-
code/modules/planet/weather.dm | 8 +-
code/modules/power/apc.dm | 2 +-
code/modules/power/fusion/core/core_field.dm | 2 +-
.../power/singularity/containment_field.dm | 2 +-
code/modules/power/smes.dm | 2 +-
code/modules/projectiles/gun.dm | 16 +-
code/modules/random_map/drop/supply.dm | 2 +-
code/modules/reagents/Chemistry-Colours.dm | 2 +-
code/modules/reagents/reactions/_reactions.dm | 2 +-
.../reagent_containers/_reagent_containers.dm | 2 +-
.../reagents/reagent_containers/spray.dm | 9 +-
code/modules/reagents/reagents/medicine_vr.dm | 11 -
code/modules/recycling/recycling.dm | 2 +-
code/modules/resleeving/machines.dm | 2 +-
code/modules/rogueminer_vr/controller.dm | 6 +-
code/modules/rogueminer_vr/zonemaster.dm | 10 +-
code/modules/scripting/IDE.dm | 2 +-
.../scripting/Implementations/Telecomms.dm | 2 +-
.../scripting/Implementations/_Logic.dm | 6 +-
.../security levels/keycard authentication.dm | 8 +-
code/modules/shieldgen/shield_generator.dm | 2 +-
code/modules/shuttles/landmarks.dm | 2 +-
code/modules/shuttles/shuttle_emergency.dm | 4 +-
code/modules/shuttles/shuttles_multi.dm | 2 +-
code/modules/shuttles/shuttles_web.dm | 4 +-
code/modules/shuttles/web_datums.dm | 12 +-
code/modules/spells/spell_code.dm | 2 +-
code/modules/tgs_commands/vorestation.dm | 4 +-
code/modules/tgui/modules/power_monitor.dm | 2 +-
code/modules/tickets/tickets.dm | 4 +-
code/modules/turbolift/turbolift.dm | 4 +-
code/modules/turbolift/turbolift_floor.dm | 2 +-
code/modules/turbolift/turbolift_map.dm | 4 +-
code/modules/unit_tests/_unit_tests.dm | 1 +
code/modules/unit_tests/font_awesome_icons.dm | 3 +-
code/modules/unit_tests/mapping.dm | 19 +
code/modules/unit_tests/unit_test.dm | 9 +-
code/modules/vore/eating/belly_messages.dm | 4 +-
code/modules/vore/eating/belly_obj_liquids.dm | 2 +-
code/modules/vore/eating/belly_obj_vr.dm | 2 +-
code/modules/vore/eating/bellymodes_vr.dm | 2 +-
code/modules/vore/eating/living_vr.dm | 10 +-
code/modules/vore/eating/soulcatcher.dm | 4 +-
code/modules/vore/eating/vore_procs.dm | 2 +-
code/modules/vore/eating/vore_vr.dm | 4 +-
code/modules/vore/eating/vorepanel_vr.dm | 2 +-
code/modules/vore/persist/persist_vr.dm | 12 +-
code/modules/vore/trycatch_vr.dm | 15 +-
code/modules/webhooks/_webhook.dm | 6 +-
code/modules/xenoarcheaology/effect_master.dm | 1 -
code/modules/xenobio2/controller.dm | 2 +-
code/modules/xenobio2/mob/xeno procs.dm | 4 +-
code/modules/xgm/xgm_gas_data.dm | 2 +-
config/example/config.txt | 10 +
config/example/logging.txt | 26 +-
html/statbrowser.js | 837 +++++++++---------
maps/expedition_vr/alienship/_alienship.dm | 2 +-
maps/offmap_vr/common_offmaps.dm | 2 +-
maps/submaps/_helpers.dm | 6 +-
maps/submaps/engine_submaps/engine.dm | 2 +-
maps/tether/tether-07-solars.dmm | 92 +-
maps/tether/tether_areas.dm | 4 +-
.../virgo_minitest/virgo_minitest_shuttles.dm | 5 -
maps/~map_system/maps.dm | 2 +-
maps/~map_system/maps_vr.dm | 4 +-
.../code/game/machinery/bluespace_denier.dm | 2 +-
.../game/objects/effects/step_triggers.dm | 2 +-
.../code/modules/event/horde_infestation.dm | 4 +-
.../code/modules/event/infectedroom.dm | 8 +-
.../code/modules/lore_codex/codex_tree.dm | 2 +-
.../code/modules/lore_codex/cooking_codex.dm | 2 +-
.../code/modules/overmap/dynamic_sector.dm | 10 +-
.../code/modules/paperwork/faxmachine.dm | 2 +-
.../maps/common/common_shuttles_crew.dm | 2 +-
modular_chomp/maps/common/common_things.dm | 2 +-
.../maps/common/common_wildlife_encounter.dm | 8 +-
modular_chomp/maps/~map_system/maps.dm | 2 +-
.../tgui/interfaces/LogViewer/CategoryBar.tsx | 52 ++
.../interfaces/LogViewer/CategoryViewer.tsx | 149 ++++
.../tgui/interfaces/LogViewer/constants.ts | 1 +
.../tgui/interfaces/LogViewer/functions.ts | 8 +
.../tgui/interfaces/LogViewer/index.tsx | 53 ++
.../tgui/interfaces/LogViewer/types.ts | 36 +
tgui/packages/tgui/interfaces/PlayerNotes.tsx | 148 ++--
vorestation.dme | 32 +-
425 files changed, 4081 insertions(+), 2568 deletions(-)
create mode 100644 code/__defines/_flags.dm
create mode 100644 code/__defines/stack_trace.dm
create mode 100644 code/_compile_options.dm
create mode 100644 code/_helpers/guid.dm
delete mode 100644 code/_helpers/logging.dm
create mode 100644 code/_helpers/logging/_logging.dm
create mode 100644 code/_helpers/logging/admin.dm
create mode 100644 code/_helpers/logging/attack.dm
create mode 100644 code/_helpers/logging/game.dm
create mode 100644 code/_helpers/logging/mob.dm
create mode 100644 code/_helpers/logging/pda.dm
create mode 100644 code/_helpers/logging/research.dm
create mode 100644 code/_helpers/logging/talk.dm
delete mode 100644 code/_helpers/logging_vr.dm
create mode 100644 code/_helpers/stack_trace.dm
delete mode 100644 code/game/objects/items/devices/radio/jammer_vr.dm
delete mode 100644 code/game/objects/items/devices/radio/radio_vr.dm
create mode 100644 code/modules/client/persistent_client.dm
delete mode 100644 code/modules/error_handler/_defines.dm
delete mode 100644 code/modules/error_handler/~defines.dm
create mode 100644 code/modules/logging/categories/log_category_admin.dm
create mode 100644 code/modules/logging/categories/log_category_compats.dm
create mode 100644 code/modules/logging/categories/log_category_debug.dm
create mode 100644 code/modules/logging/categories/log_category_game.dm
create mode 100644 code/modules/logging/categories/log_category_href.dm
create mode 100644 code/modules/logging/categories/log_category_internal.dm
create mode 100644 code/modules/logging/categories/log_category_misc.dm
create mode 100644 code/modules/logging/categories/log_category_pda.dm
create mode 100644 code/modules/logging/log_category.dm
create mode 100644 code/modules/logging/log_entry.dm
create mode 100644 code/modules/logging/log_holder.dm
create mode 100644 code/modules/unit_tests/mapping.dm
create mode 100644 tgui/packages/tgui/interfaces/LogViewer/CategoryBar.tsx
create mode 100644 tgui/packages/tgui/interfaces/LogViewer/CategoryViewer.tsx
create mode 100644 tgui/packages/tgui/interfaces/LogViewer/constants.ts
create mode 100644 tgui/packages/tgui/interfaces/LogViewer/functions.ts
create mode 100644 tgui/packages/tgui/interfaces/LogViewer/index.tsx
create mode 100644 tgui/packages/tgui/interfaces/LogViewer/types.ts
diff --git a/SQL/DBSchema.sql b/SQL/DBSchema.sql
index 14283388b0..d85dc3555a 100644
--- a/SQL/DBSchema.sql
+++ b/SQL/DBSchema.sql
@@ -62,18 +62,6 @@ CREATE TABLE IF NOT EXISTS `erro_admin_log` (
-- Data exporting was unselected.
--- Dumping structure for table ss13.erro_attacklog
-CREATE TABLE IF NOT EXISTS `erro_attacklog` (
- `id` int(11) NOT NULL AUTO_INCREMENT,
- `time` datetime DEFAULT NULL,
- `ckey` varchar(64) DEFAULT NULL,
- `mob` varchar(128) DEFAULT NULL,
- `message` varchar(1024) NOT NULL,
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB AUTO_INCREMENT=886 DEFAULT CHARSET=latin1;
-
--- Data exporting was unselected.
-
-- Dumping structure for table ss13.erro_ban
CREATE TABLE IF NOT EXISTS `erro_ban` (
`id` int(11) NOT NULL AUTO_INCREMENT,
@@ -117,19 +105,6 @@ CREATE TABLE IF NOT EXISTS `erro_connection_log` (
-- Data exporting was unselected.
--- Dumping structure for table ss13.erro_dialog
-CREATE TABLE IF NOT EXISTS `erro_dialog` (
- `mid` int(11) NOT NULL AUTO_INCREMENT,
- `time` datetime NOT NULL,
- `ckey` varchar(32) NOT NULL,
- `mob` varchar(128) DEFAULT NULL,
- `type` varchar(32) NOT NULL,
- `message` text NOT NULL,
- PRIMARY KEY (`mid`)
-) ENGINE=InnoDB AUTO_INCREMENT=3345 DEFAULT CHARSET=latin1;
-
--- Data exporting was unselected.
-
-- Dumping structure for table ss13.erro_feedback
CREATE TABLE IF NOT EXISTS `erro_feedback` (
`id` int(11) NOT NULL AUTO_INCREMENT,
diff --git a/archive/maps/gateway_archive_vr/labyrinth.dm b/archive/maps/gateway_archive_vr/labyrinth.dm
index 8c1d15cf53..6fb71a91b3 100644
--- a/archive/maps/gateway_archive_vr/labyrinth.dm
+++ b/archive/maps/gateway_archive_vr/labyrinth.dm
@@ -185,7 +185,7 @@
else
M.make_jittery(500)
chassis.use_power(energy_drain)
- log_message("Honked from [src.name]. HONK!")
+ src.log_message("Honked from [src.name]. HONK!")
do_after_cooldown()
return
diff --git a/archive/maps/southern_cross/events/wildlife_encounter.dm b/archive/maps/southern_cross/events/wildlife_encounter.dm
index 04d7c10e01..267107d03a 100644
--- a/archive/maps/southern_cross/events/wildlife_encounter.dm
+++ b/archive/maps/southern_cross/events/wildlife_encounter.dm
@@ -20,7 +20,7 @@
/datum/event2/event/wildlife_encounter/set_up()
for(var/mob/living/L in GLOB.player_list)
//if(!(L.z in get_location_z_levels()))
- // log_debug("Not on the right z-level")
+ // log_mapping("Not on the right z-level")
// continue // Not on the right z-level.
if(L.stat)
continue // Don't want dead people.
@@ -34,7 +34,7 @@
/datum/event2/event/wildlife_encounter/start()
if(!victim)
- log_debug("Failed to find a target for random encounter. Aborting.")
+ log_game("Failed to find a target for random encounter. Aborting.")
abort()
return
@@ -60,19 +60,19 @@
for(var/i = 1 to potential_victims.len)
if (get_dist(spawning_turf, potential_victims[i]) < world.view)
spawning_turf = null
- log_debug("Failed to locate position out of sight of [potential_victims[i]].")
+ log_game("Failed to locate position out of sight of [potential_victims[i]].")
attempts++
potential_victims = null
- log_debug("Sending [number_of_packs] [build_path]\s after \the [victim].")
+ log_game("Sending [number_of_packs] [build_path]\s after \the [victim].")
for(var/i = 1 to number_of_packs)
if(spawning_turf)
var/mob/living/simple_mob/M = new build_path(spawning_turf)
M.ai_holder?.give_destination(get_turf(victim))
else
- log_debug("Failed to locate turf to spawn encounter.")
+ log_game("Failed to locate turf to spawn encounter.")
/datum/event2/event/wildlife_encounter/proc/item_to_spawn()
return pick(prob(22);/mob/living/simple_mob/animal/sif/savik,
diff --git a/code/ZAS/Fire.dm b/code/ZAS/Fire.dm
index 7b6c36e790..2a43b049d6 100644
--- a/code/ZAS/Fire.dm
+++ b/code/ZAS/Fire.dm
@@ -237,8 +237,8 @@ If it gains pressure too slowly, it may leak or just rupture instead of explodin
if((temperature > PHORON_MINIMUM_BURN_TEMPERATURE || force_burn) && (no_check ||check_recombustability(zone? zone.fuel_objs : null)))
#ifdef FIREDBG
- log_debug("***************** FIREDBG *****************")
- log_debug("Burning [zone? zone.name : "zoneless gas_mixture"]!")
+ log_world("***************** FIREDBG *****************")
+ log_world("Burning [zone? zone.name : "zoneless gas_mixture"]!")
#endif
var/gas_fuel = 0
@@ -291,13 +291,13 @@ If it gains pressure too slowly, it may leak or just rupture instead of explodin
var/used_oxidizers = used_fuel*(FIRE_REACTION_OXIDIZER_AMOUNT/FIRE_REACTION_FUEL_AMOUNT)
#ifdef FIREDBG
- log_debug("gas_fuel = [gas_fuel], liquid_fuel = [liquid_fuel], total_oxidizers = [total_oxidizers]")
- log_debug("fuel_area = [fuel_area], total_fuel = [total_fuel], reaction_limit = [reaction_limit]")
- log_debug("firelevel -> [firelevel] (gas: [gas_firelevel], liquid: [liquid_firelevel])")
- log_debug("liquid_reaction_progress = [liquid_reaction_progress]")
- log_debug("gas_reaction_progress = [gas_reaction_progress]")
- log_debug("total_reaction_progress = [total_reaction_progress]")
- log_debug("used_fuel = [used_fuel], used_oxidizers = [used_oxidizers]; ")
+ log_world("gas_fuel = [gas_fuel], liquid_fuel = [liquid_fuel], total_oxidizers = [total_oxidizers]")
+ log_world("fuel_area = [fuel_area], total_fuel = [total_fuel], reaction_limit = [reaction_limit]")
+ log_world("firelevel -> [firelevel] (gas: [gas_firelevel], liquid: [liquid_firelevel])")
+ log_world("liquid_reaction_progress = [liquid_reaction_progress]")
+ log_world("gas_reaction_progress = [gas_reaction_progress]")
+ log_world("total_reaction_progress = [total_reaction_progress]")
+ log_world("used_fuel = [used_fuel], used_oxidizers = [used_oxidizers]; ")
#endif
//if the reaction is progressing too slow then it isn't self-sustaining anymore and burns out
@@ -326,8 +326,8 @@ If it gains pressure too slowly, it may leak or just rupture instead of explodin
update_values()
#ifdef FIREDBG
- log_debug("used_gas_fuel = [used_gas_fuel]; used_liquid_fuel = [used_liquid_fuel]; total = [used_fuel]")
- log_debug("new temperature = [temperature]; new pressure = [return_pressure()]")
+ log_world("used_gas_fuel = [used_gas_fuel]; used_liquid_fuel = [used_liquid_fuel]; total = [used_fuel]")
+ log_world("new temperature = [temperature]; new pressure = [return_pressure()]")
#endif
return firelevel
diff --git a/code/ZAS/Variable Settings.dm b/code/ZAS/Variable Settings.dm
index 015396c24a..7c46e4572b 100644
--- a/code/ZAS/Variable Settings.dm
+++ b/code/ZAS/Variable Settings.dm
@@ -170,7 +170,7 @@ var/global/vs_control/vsc = new
vars[ch] = vw
if(how == "Toggle")
newvar = (newvar?"ON":"OFF")
- to_world(span_world(span_blue("[key_name(user)] changed the setting [display_description] to [newvar].")))
+ to_chat(world, span_world(span_blue("[key_name(user)] changed the setting [display_description] to [newvar].")))
if(ch in plc.settings)
ChangeSettingsDialog(user,plc.settings)
else
@@ -323,7 +323,7 @@ var/global/vs_control/vsc = new
plc.N2O_HALLUCINATION = initial(plc.N2O_HALLUCINATION)
- to_world(span_world(span_blue("[key_name(user)] changed the global phoron/ZAS settings to \"[def]\"")))
+ to_chat(world, span_world(span_blue("[key_name(user)] changed the global phoron/ZAS settings to \"[def]\"")))
/pl_control/var/list/settings = list()
diff --git a/code/__defines/_flags.dm b/code/__defines/_flags.dm
new file mode 100644
index 0000000000..4bd4edcca7
--- /dev/null
+++ b/code/__defines/_flags.dm
@@ -0,0 +1,2 @@
+/// 33554431 (2^24 - 1) is the maximum value our bitflags can reach.
+#define MAX_BITFLAG_DIGITS 8
diff --git a/code/__defines/_helpers.dm b/code/__defines/_helpers.dm
index b7cf727299..85dd40153b 100644
--- a/code/__defines/_helpers.dm
+++ b/code/__defines/_helpers.dm
@@ -13,6 +13,17 @@
/// The Y/Height dimension of ICON_SIZE. This will more than likely be the smaller axis.
#define ICON_SIZE_Y 32
+//Returns the hex value of a decimal number
+//len == length of returned string
+#define num2hex(X, len) num2text(X, len, 16)
+
+//Returns an integer given a hex input, supports negative values "-ff"
+//skips preceding invalid characters
+#define hex2num(X) text2num(X, 16)
+
+/// Until a condition is true, sleep
+#define UNTIL(X) while(!(X)) stoplag()
+
/// Takes a datum as input, returns its ref string
#define text_ref(datum) ref(datum)
@@ -24,3 +35,6 @@
/// A null statement to guard against EmptyBlock lint without necessitating the use of pass()
/// Used to avoid proc-call overhead. But use sparingly. Probably pointless in most places.
#define EMPTY_BLOCK_GUARD ;
+
+/// Abstraction over using mob.client to just check if there's a connected player.
+#define HAS_CONNECTED_PLAYER(mob) (mob.client)
diff --git a/code/__defines/_tick.dm b/code/__defines/_tick.dm
index 5c7b2a3a86..9fc9aa96cc 100644
--- a/code/__defines/_tick.dm
+++ b/code/__defines/_tick.dm
@@ -28,5 +28,3 @@
#define TICK_CHECK_HIGH_PRIORITY ( TICK_USAGE > 95 )
/// runs stoplag if tick_usage is above 95, for high priority usage
#define CHECK_TICK_HIGH_PRIORITY ( TICK_CHECK_HIGH_PRIORITY? stoplag() : 0 )
-
-#define UNTIL(X) while(!(X)) stoplag()
diff --git a/code/__defines/logging.dm b/code/__defines/logging.dm
index 3b64f81c74..f87ab3f428 100644
--- a/code/__defines/logging.dm
+++ b/code/__defines/logging.dm
@@ -1,5 +1,133 @@
+/// The number of entries to store per category, don't make this too large or you'll start to see performance issues
+#define CONFIG_MAX_CACHED_LOG_ENTRIES 1000
+
+/// The number of *minimum* ticks between each log re-render, making this small will cause performance issues
+/// Admins can still manually request a re-render
+#define LOG_UPDATE_TIMEOUT 5 SECONDS
+
+// The maximum number of entries allowed in the signaler investigate log, keep this relatively small to prevent performance issues when an admin tries to query it
+#define INVESTIGATE_SIGNALER_LOG_MAX_LENGTH 500
+
+//Investigate logging defines
+#define INVESTIGATE_CARGO "cargo"
+#define INVESTIGATE_RESEARCH "research"
+
+// Logging types for log_message()
+#define LOG_ATTACK (1 << 0)
+#define LOG_SAY (1 << 1)
+#define LOG_WHISPER (1 << 2)
+#define LOG_EMOTE (1 << 3)
+#define LOG_DSAY (1 << 4)
+#define LOG_PDA (1 << 5)
+#define LOG_CHAT (1 << 6)
+#define LOG_COMMENT (1 << 7)
+#define LOG_TELECOMMS (1 << 8)
+#define LOG_OOC (1 << 9)
+#define LOG_LOOC (1 << 10)
+#define LOG_ADMIN (1 << 11)
+#define LOG_OWNERSHIP (1 << 12)
+#define LOG_GAME (1 << 13)
+#define LOG_ADMIN_PRIVATE (1 << 14)
+#define LOG_ASAY (1 << 15)
+#define LOG_MECHA (1 << 16)
+#define LOG_VIRUS (1 << 17)
+#define LOG_SHUTTLE (1 << 18)
+#define LOG_ECON (1 << 19)
+#define LOG_VICTIM (1 << 20)
+#define LOG_RADIO_EMOTE (1 << 21)
+#define LOG_SPEECH_INDICATORS (1 << 22)
+#define LOG_TRANSPORT (1 << 23)
+
+//Individual logging panel pages
+#define INDIVIDUAL_GAME_LOG (LOG_GAME)
+#define INDIVIDUAL_ATTACK_LOG (LOG_ATTACK | LOG_VICTIM)
+#define INDIVIDUAL_SAY_LOG (LOG_SAY | LOG_WHISPER | LOG_DSAY | LOG_SPEECH_INDICATORS)
+#define INDIVIDUAL_EMOTE_LOG (LOG_EMOTE | LOG_RADIO_EMOTE)
+#define INDIVIDUAL_COMMS_LOG (LOG_PDA | LOG_CHAT | LOG_COMMENT | LOG_TELECOMMS)
+#define INDIVIDUAL_OOC_LOG (LOG_OOC | LOG_LOOC | LOG_ADMIN)
+#define INDIVIDUAL_SHOW_ALL_LOG (LOG_ATTACK | LOG_SAY | LOG_WHISPER | LOG_EMOTE | LOG_RADIO_EMOTE | LOG_DSAY | LOG_PDA | LOG_CHAT | LOG_COMMENT | LOG_TELECOMMS | LOG_OOC | LOG_LOOC | LOG_ADMIN | LOG_OWNERSHIP | LOG_GAME | LOG_ADMIN_PRIVATE | LOG_ASAY | LOG_MECHA | LOG_VIRUS | LOG_SHUTTLE | LOG_ECON | LOG_VICTIM | LOG_SPEECH_INDICATORS)
+
+// Log entry keys
+#define LOG_ENTRY_KEY_TIMESTAMP "ts"
+#define LOG_ENTRY_KEY_CATEGORY "cat"
+#define LOG_ENTRY_KEY_MESSAGE "msg"
+#define LOG_ENTRY_KEY_DATA "data"
+#define LOG_ENTRY_KEY_WORLD_STATE "w-state"
+#define LOG_ENTRY_KEY_SEMVER_STORE "s-store"
+#define LOG_ENTRY_KEY_ID "id"
+#define LOG_ENTRY_KEY_SCHEMA_VERSION "s-ver"
+
+// Internal categories
+#define LOG_CATEGORY_INTERNAL_CATEGORY_NOT_FOUND "internal-category-not-found"
+#define LOG_CATEGORY_INTERNAL_ERROR "internal-error"
+
+// Misc categories
+#define LOG_CATEGORY_ATTACK "attack"
+#define LOG_CATEGORY_CONFIG "config"
+#define LOG_CATEGORY_QDEL "qdel"
+#define LOG_CATEGORY_RUNTIME "runtime"
+#define LOG_CATEGORY_SUSPICIOUS_LOGIN "suspicious-logins"
+#define LOG_CATEGORY_VORE "vore"
+
+// Admin categories
+#define LOG_CATEGORY_ADMIN "admin"
+#define LOG_CATEGORY_ADMIN_DSAY "admin-dsay"
+
+// Admin private categories
+#define LOG_CATEGORY_ADMIN_PRIVATE "adminprivate"
+#define LOG_CATEGORY_ADMIN_PRIVATE_ASAY "adminprivate-asay"
+#define LOG_CATEGORY_ADMIN_PRIVATE_MSAY "adminprivate-msay"
+#define LOG_CATEGORY_ADMIN_PRIVATE_ESAY "adminprivate-esay"
+
+// Debug categories
+#define LOG_CATEGORY_DEBUG "debug"
+#define LOG_CATEGORY_DEBUG_ASSET "debug-asset"
+#define LOG_CATEGORY_DEBUG_MAPPING "debug-mapping"
+#define LOG_CATEGORY_DEBUG_MOBTAG "debug-mobtag"
+#define LOG_CATEGORY_DEBUG_SQL "debug-sql"
+
+// Compatibility categories, for when stuff is changed and you need existing functionality to work
+#define LOG_CATEGORY_COMPAT_GAME "game-compat"
+
+// Game categories
+#define LOG_CATEGORY_GAME "game"
+#define LOG_CATEGORY_GAME_ACCESS "game-access"
+#define LOG_CATEGORY_GAME_EMOTE "game-emote"
+#define LOG_CATEGORY_GAME_OOC "game-ooc"
+#define LOG_CATEGORY_GAME_LOOC "game-looc"
+#define LOG_CATEGORY_GAME_PRAYER "game-prayer"
+#define LOG_CATEGORY_GAME_SAY "game-say"
+#define LOG_CATEGORY_GAME_TOPIC "game-topic"
+#define LOG_CATEGORY_GAME_VOTE "game-vote"
+#define LOG_CATEGORY_GAME_WHISPER "game-whisper"
+
+// HREF categories
+#define LOG_CATEGORY_HREF "href"
+#define LOG_CATEGORY_HREF_TGUI "href-tgui"
+
+// PDA categories
+#define LOG_CATEGORY_PDA "pda"
+
+// Flags that apply to the entry_flags var on logging categories
+// These effect how entry datums process the inputs passed into them
+/// Enables data list usage for readable log entries
+/// You'll likely want to disable internal formatting to make this work properly
+#define ENTRY_USE_DATA_W_READABLE (1<<0)
+
+
+#define SCHEMA_VERSION "schema-version"
+
+// Default log schema version
+#define LOG_CATEGORY_SCHEMA_VERSION_NOT_SET "0.0.1"
+
+//wrapper macros for easier grepping
+#define DIRECT_OUTPUT(A, B) A << B
+#define DIRECT_INPUT(A, B) A >> B
+#define SEND_IMAGE(target, image) DIRECT_OUTPUT(target, image)
+#define SEND_SOUND(target, sound) DIRECT_OUTPUT(target, sound)
#define SEND_TEXT(target, text) DIRECT_OUTPUT(target, text)
#define WRITE_FILE(file, text) DIRECT_OUTPUT(file, text)
#define READ_FILE(file, text) DIRECT_INPUT(file, text)
-
-#define INVESTIGATE_RESEARCH "research"
+//This is an external call, "true" and "false" are how rust parses out booleans
+#define WRITE_LOG(log, text) rustg_log_write(log, text, "true")
+#define WRITE_LOG_NO_FORMAT(log, text) rustg_log_write(log, text, "false")
diff --git a/code/__defines/shuttle.dm b/code/__defines/shuttle.dm
index 9bf7dcad6f..76989a0e95 100644
--- a/code/__defines/shuttle.dm
+++ b/code/__defines/shuttle.dm
@@ -23,5 +23,5 @@
#ifndef DEBUG_SHUTTLES
#define log_shuttle(M)
#else
- #define log_shuttle(M) log_debug("[M]")
+ #define log_shuttle(M) log_world("[M]")
#endif
diff --git a/code/__defines/stack_trace.dm b/code/__defines/stack_trace.dm
new file mode 100644
index 0000000000..4911b4a0d5
--- /dev/null
+++ b/code/__defines/stack_trace.dm
@@ -0,0 +1,4 @@
+/// gives us the stack trace from CRASH() without ending the current proc.
+#define stack_trace(message) _stack_trace(message, __FILE__, __LINE__)
+
+#define WORKAROUND_IDENTIFIER "%//%"
diff --git a/code/__defines/tgs.config.dm b/code/__defines/tgs.config.dm
index c57439c7e4..0dc0e64f9a 100644
--- a/code/__defines/tgs.config.dm
+++ b/code/__defines/tgs.config.dm
@@ -3,9 +3,9 @@
#define TGS_READ_GLOBAL(Name) GLOB.##Name
#define TGS_WRITE_GLOBAL(Name, Value) GLOB.##Name = ##Value
#define TGS_WORLD_ANNOUNCE(message) to_chat(world, span_boldannounce("[html_encode(##message)]"))
-#define TGS_INFO_LOG(message) log_to_dd("TGS Info: [##message]")
-#define TGS_WARNING_LOG(message) log_to_dd("TGS Warn: [##message]")
-#define TGS_ERROR_LOG(message) log_to_dd("TGS Error: [##message]")
+#define TGS_INFO_LOG(message) log_world("TGS Info: [##message]")
+#define TGS_WARNING_LOG(message) log_world("TGS Warn: [##message]")
+#define TGS_ERROR_LOG(message) stack_trace("TGS Error: [##message]")
#define TGS_NOTIFY_ADMINS(event) message_admins(##event)
#define TGS_CLIENT_COUNT GLOB.clients.len
#define TGS_PROTECT_DATUM(Path) GENERAL_PROTECT_DATUM(##Path)
diff --git a/code/_compile_options.dm b/code/_compile_options.dm
new file mode 100644
index 0000000000..bc43d51fa2
--- /dev/null
+++ b/code/_compile_options.dm
@@ -0,0 +1,7 @@
+// Comment this out if you are debugging problems that might be obscured by custom error handling in world/Error
+#ifdef DEBUG
+#define USE_CUSTOM_ERROR_HANDLER
+#endif
+
+// We do not have dreamlua implemented
+#define DISABLE_DREAMLUAU
diff --git a/code/_global_vars/logging.dm b/code/_global_vars/logging.dm
index 5ac744da96..4e04f43faf 100644
--- a/code/_global_vars/logging.dm
+++ b/code/_global_vars/logging.dm
@@ -5,6 +5,44 @@ GLOBAL_PROTECT(round_id)
GLOBAL_VAR_INIT(log_directory, "data/logs/") //See world.dm for the full calculated path
GLOBAL_PROTECT(log_directory)
+#define DECLARE_LOG_NAMED(log_var_name, log_file_name, start)\
+GLOBAL_VAR(##log_var_name);\
+GLOBAL_PROTECT(##log_var_name);\
+/world/_initialize_log_files(temp_log_override = null){\
+ ..();\
+ GLOB.##log_var_name = temp_log_override || "[GLOB.log_directory]/[##log_file_name].log";\
+ if(!temp_log_override && ##start){\
+ start_log(GLOB.##log_var_name);\
+ }\
+}
+
+#define DECLARE_LOG(log_name, start) DECLARE_LOG_NAMED(##log_name, "[copytext(#log_name, 1, length(#log_name) - 3)]", start)
+#define START_LOG TRUE
+#define DONT_START_LOG FALSE
+
+/// Populated by log declaration macros to set log file names and start messages
+/world/proc/_initialize_log_files(temp_log_override = null)
+ // Needs to be here to avoid compiler warnings
+ SHOULD_CALL_PARENT(TRUE)
+ return
+
+// All individual log files.
+// These should be used where the log category cannot easily be a json log file.
+DECLARE_LOG(config_error_log, DONT_START_LOG)
+DECLARE_LOG(perf_log, DONT_START_LOG) // Declared here but name is set in time_track subsystem
+
+#ifdef REFERENCE_TRACKING_LOG_APART
+DECLARE_LOG_NAMED(harddel_log, "harddels", START_LOG)
+#endif
+
+#if defined(UNIT_TESTS) || defined(SPACEMAN_DMM)
+DECLARE_LOG_NAMED(test_log, "tests", START_LOG)
+#endif
+
+/// All admin related log lines minus their categories
+GLOBAL_LIST_EMPTY(admin_activities)
+GLOBAL_PROTECT(admin_activities)
+
GLOBAL_VAR(diary)
GLOBAL_PROTECT(diary)
@@ -30,3 +68,8 @@ GLOBAL_PROTECT(bombers)
/// Stores who uploaded laws to which silicon-based lifeform, and what the law was
GLOBAL_LIST_EMPTY(lawchanges)
GLOBAL_PROTECT(lawchanges)
+
+#undef DECLARE_LOG
+#undef DECLARE_LOG_NAMED
+#undef START_LOG
+#undef DONT_START_LOG
diff --git a/code/_helpers/_lists.dm b/code/_helpers/_lists.dm
index bfac0f758d..0688d3c390 100644
--- a/code/_helpers/_lists.dm
+++ b/code/_helpers/_lists.dm
@@ -910,7 +910,7 @@ GLOBAL_LIST_EMPTY(json_cache)
GLOB.json_cache[json_to_decode] = json_decode(json_to_decode)
. = GLOB.json_cache[json_to_decode]
catch(var/exception/e)
- log_error("Exception during JSON decoding ([json_to_decode]): [e]")
+ log_runtime("Exception during JSON decoding ([json_to_decode]): [e]")
return list()
//takes an input_key, as text, and the list of keys already used, outputting a replacement key in the format of "[input_key] ([number_of_duplicates])" if it finds a duplicate
diff --git a/code/_helpers/files.dm b/code/_helpers/files.dm
index a776c3363d..716df480f9 100644
--- a/code/_helpers/files.dm
+++ b/code/_helpers/files.dm
@@ -1,17 +1,3 @@
-//checks if a file exists and contains text
-//returns text as a string if these conditions are met
-/proc/return_file_text(filename)
- if(fexists(filename) == 0)
- error("File not found ([filename])")
- return
-
- var/text = file2text(filename)
- if(!text)
- error("File empty ([filename])")
- return
-
- return text
-
/**
* For FTP requests. (i.e. downloading runtime logs.)
*
diff --git a/code/_helpers/global_lists.dm b/code/_helpers/global_lists.dm
index 144198ba08..4008bf548e 100644
--- a/code/_helpers/global_lists.dm
+++ b/code/_helpers/global_lists.dm
@@ -193,7 +193,6 @@ GLOBAL_LIST_EMPTY(mannequins)
if (isnull(GLOB.all_languages[L.name]))
GLOB.all_languages[L.name] = L
else
- log_debug("Language name conflict! [T] is named [L.name], but that is taken by [GLOB.all_languages[L.name].type]")
if(isnull(GLOB.language_name_conflicts[L.name]))
GLOB.language_name_conflicts[L.name] = list(GLOB.all_languages[L.name])
GLOB.language_name_conflicts[L.name] += L
@@ -204,7 +203,6 @@ GLOBAL_LIST_EMPTY(mannequins)
if(isnull(GLOB.language_keys[L.key]))
GLOB.language_keys[L.key] = L
else
- log_debug("Language key conflict! [L] has key [L.key], but that is taken by [(GLOB.language_keys[L.key])]")
if(isnull(GLOB.language_key_conflicts[L.key]))
GLOB.language_key_conflicts[L.key] = list(GLOB.language_keys[L.key])
GLOB.language_key_conflicts[L.key] += L
diff --git a/code/_helpers/guid.dm b/code/_helpers/guid.dm
new file mode 100644
index 0000000000..49903cceb3
--- /dev/null
+++ b/code/_helpers/guid.dm
@@ -0,0 +1,19 @@
+/**
+ * returns a GUID like identifier (using a mostly made up record format)
+ * guids are not on their own suitable for access or security tokens, as most of their bits are predictable.
+ * (But may make a nice salt to one)
+**/
+/proc/GUID()
+ var/const/GUID_VERSION = "b"
+ var/const/GUID_VARIANT = "d"
+ var/node_id = copytext_char(md5("[rand()*rand(1,9999999)][world.name][world.hub][world.hub_password][world.internet_address][world.address][world.contents.len][world.status][world.port][rand()*rand(1,9999999)]"), 1, 13)
+
+ var/time_high = "[num2hex(text2num(time2text(world.realtime,"YYYY")), 2)][num2hex(world.realtime, 6)]"
+
+ var/time_mid = num2hex(world.timeofday, 4)
+
+ var/time_low = num2hex(world.time, 3)
+
+ var/time_clock = num2hex(TICK_DELTA_TO_MS(world.tick_usage), 3)
+
+ return "{[time_high]-[time_mid]-[GUID_VERSION][time_low]-[GUID_VARIANT][time_clock]-[node_id]}"
diff --git a/code/_helpers/logging.dm b/code/_helpers/logging.dm
deleted file mode 100644
index 52a4cb9e94..0000000000
--- a/code/_helpers/logging.dm
+++ /dev/null
@@ -1,423 +0,0 @@
-//print an error message to world.log
-
-//This is an external call, "true" and "false" are how rust parses out booleans
-#define WRITE_LOG(log, text) rustg_log_write(log, text, "true")
-#define WRITE_LOG_NO_FORMAT(log, text) rustg_log_write(log, text, "false")
-
-/* For logging round startup. */
-/proc/start_log(log)
- WRITE_LOG(log, "START: Starting up [GLOB.log_directory].")
- return log
-
-/* Close open log handles. This should be called as late as possible, and no logging should hapen after. */
-/proc/shutdown_logging()
- rustg_log_close_all()
-
-/proc/error(msg)
- to_world_log("## ERROR: [msg]")
-
-#define WARNING(MSG) warning("[MSG] in [__FILE__] at line [__LINE__] src: [src] usr: [usr].")
-//print a warning message to world.log
-/proc/warning(msg)
- to_world_log("## WARNING: [msg]")
-
-//print a testing-mode debug message to world.log
-/proc/testing(msg)
- if (CONFIG_GET(flag/log_debug)) //CHOMPEdit
- to_world_log("## TESTING: [msg]")
-
-/proc/log_admin(text)
- GLOB.admin_log.Add(text)
- if (CONFIG_GET(flag/log_admin))
- WRITE_LOG(GLOB.diary, "ADMIN: [text]")
-
-/proc/log_admin_private(text)
- GLOB.admin_log.Add(text)
- if (CONFIG_GET(flag/log_admin))
- WRITE_LOG(GLOB.diary, "ADMINPRIVATE: [text]")
-
-/proc/log_adminpm(text, client/source, client/dest)
- GLOB.admin_log.Add(text)
- if (CONFIG_GET(flag/log_admin))
- WRITE_LOG(GLOB.diary, "ADMINPM: [key_name(source)]->[key_name(dest)]: [html_decode(text)]")
-
-/proc/log_pray(text, client/source)
- GLOB.admin_log.Add(text)
- if (CONFIG_GET(flag/log_admin))
- WRITE_LOG(GLOB.diary, "PRAY: [key_name(source)]: [text]")
-
-/proc/log_debug(text)
- if (CONFIG_GET(flag/log_debug))
- WRITE_LOG(GLOB.debug_log, "DEBUG: [sanitize(text)]")
-
- for(var/client/C in GLOB.admins)
- if(C.prefs?.read_preference(/datum/preference/toggle/show_debug_logs))
- to_chat(C,
- type = MESSAGE_TYPE_DEBUG,
- html = span_filter_debuglogs("DEBUG: [text]"))
-
-/proc/log_game(text)
- if (CONFIG_GET(flag/log_game))
- WRITE_LOG(GLOB.diary, "GAME: [text]")
-
-/proc/log_vote(text)
- if (CONFIG_GET(flag/log_vote))
- WRITE_LOG(GLOB.diary, "VOTE: [text]")
-
-/proc/log_access_in(client/new_client)
- if (CONFIG_GET(flag/log_access))
- var/message = "[key_name(new_client)] - IP:[new_client.address] - CID:[new_client.computer_id] - BYOND v[new_client.byond_version]"
- WRITE_LOG(GLOB.diary, "ACCESS IN: [message]") //VOREStation Edit
-
-/proc/log_access_out(mob/last_mob)
- if (CONFIG_GET(flag/log_access))
- var/message = "[key_name(last_mob)] - IP:[last_mob.lastKnownIP] - CID:Logged Out - BYOND Logged Out"
- WRITE_LOG(GLOB.diary, "ACCESS OUT: [message]")
-
-/proc/log_say(text, mob/speaker)
- if (CONFIG_GET(flag/log_say))
- WRITE_LOG(GLOB.diary, "SAY: [speaker.simple_info_line()]: [html_decode(text)]")
-
- //Log the message to in-game dialogue logs, as well. //CHOMPEdit Begin
- if(speaker.client)
- //speaker.dialogue_log += span_bold("([time_stamp()])") + " (" + span_bold("[speaker]/[speaker.client]") + ") " + span_underline("SAY:") + " - " + span_green("[text]")
- if(!SSdbcore.IsConnected())
- establish_db_connection()
- if(!SSdbcore.IsConnected())
- return null
- var/datum/db_query/query_insert = SSdbcore.NewQuery("INSERT INTO erro_dialog (mid, time, ckey, mob, type, message) VALUES (null, NOW(), :sender_ckey, :sender_mob, :message_type, :message_content)", \
- list("sender_ckey" = speaker.ckey, "sender_mob" = speaker.real_name, "message_type" = "say", "message_content" = text))
- if(!query_insert.Execute())
- log_debug("Error during logging: "+query_insert.ErrorMsg())
- qdel(query_insert)
- return
- qdel(query_insert)
- //GLOB.round_text_log += span_bold("([time_stamp()])") + " (" + span_bold("[speaker]/[speaker.client]") + ") " + span_underline("SAY:") + " - " + span_green("[text]")
- //CHOMPEdit End
-
-/proc/log_ooc(text, client/user)
- if (CONFIG_GET(flag/log_ooc))
- WRITE_LOG(GLOB.diary, "OOC: [user.simple_info_line()]: [html_decode(text)]")
- if(!SSdbcore.IsConnected())
- establish_db_connection()
- if(!SSdbcore.IsConnected())
- return null
- var/datum/db_query/query_insert = SSdbcore.NewQuery("INSERT INTO erro_dialog (mid, time, ckey, mob, type, message) VALUES (null, NOW(), :sender_ckey, :sender_mob, :message_type, :message_content)", \
- list("sender_ckey" = user.ckey, "sender_mob" = user.mob.real_name, "message_type" = "ooc", "message_content" = text))
- if(!query_insert.Execute())
- log_debug("Error during logging: "+query_insert.ErrorMsg())
- qdel(query_insert)
- return
- qdel(query_insert)
- //GLOB.round_text_log += span_bold("([time_stamp()])") + " (" + span_bold("[user]") + ") " + span_underline("OOC:") + " - " + span_blue(span_bold("[text]"))
-
-/proc/log_aooc(text, client/user)
- if (CONFIG_GET(flag/log_ooc))
- WRITE_LOG(GLOB.diary, "AOOC: [user.simple_info_line()]: [html_decode(text)]")
- if(!SSdbcore.IsConnected())
- establish_db_connection()
- if(!SSdbcore.IsConnected())
- return null
- var/datum/db_query/query_insert = SSdbcore.NewQuery("INSERT INTO erro_dialog (mid, time, ckey, mob, type, message) VALUES (null, NOW(), :sender_ckey, :sender_mob, :message_type, :message_content)", \
- list("sender_ckey" = user.ckey, "sender_mob" = user.mob.real_name, "message_type" = "aooc", "message_content" = text))
- if(!query_insert.Execute())
- log_debug("Error during logging: "+query_insert.ErrorMsg())
- qdel(query_insert)
- return
- qdel(query_insert)
- //GLOB.round_text_log += span_bold("([time_stamp()])") + " (" + span_bold("[user]") + ") " + span_underline("AOOC:") + " - " + span_red(span_bold("[text]"))
-
-/proc/log_looc(text, client/user)
- if (CONFIG_GET(flag/log_ooc))
- WRITE_LOG(GLOB.diary, "LOOC: [user.simple_info_line()]: [html_decode(text)]")
- if(!SSdbcore.IsConnected())
- establish_db_connection()
- if(!SSdbcore.IsConnected())
- return null
- var/datum/db_query/query_insert = SSdbcore.NewQuery("INSERT INTO erro_dialog (mid, time, ckey, mob, type, message) VALUES (null, NOW(), :sender_ckey, :sender_mob, :message_type, :message_content)", \
- list("sender_ckey" = user.ckey, "sender_mob" = user.mob.real_name, "message_type" = "looc", "message_content" = text))
- if(!query_insert.Execute())
- log_debug("Error during logging: "+query_insert.ErrorMsg())
- qdel(query_insert)
- return
- qdel(query_insert)
- //GLOB.round_text_log += span_bold("([time_stamp()])") + " (" + span_bold("[user]") + ") " + span_underline("LOOC:") + " - " + span_orange(span_bold("[text]"))
-
-/proc/log_whisper(text, mob/speaker)
- if (CONFIG_GET(flag/log_whisper))
- WRITE_LOG(GLOB.diary, "WHISPER: [speaker.simple_info_line()]: [html_decode(text)]")
-
- if(speaker.client)
- //speaker.dialogue_log += span_bold("([time_stamp()])") + " (" + span_bold("[speaker]/[speaker.client]") + ") " + span_underline("SAY:") + " - " + span_gray(span_italics("[text]"))
- //GLOB.round_text_log += span_bold("([time_stamp()])") + " (" + span_bold("[speaker]/[speaker.client]") + ") " + span_underline("SAY:") + " - " + span_gray(span_italics("[text]"))
- if(!SSdbcore.IsConnected())
- establish_db_connection()
- if(!SSdbcore.IsConnected())
- return null
- var/datum/db_query/query_insert = SSdbcore.NewQuery("INSERT INTO erro_dialog (mid, time, ckey, mob, type, message) VALUES (null, NOW(), :sender_ckey, :sender_mob, :message_type, :message_content)", \
- list("sender_ckey" = speaker.ckey, "sender_mob" = speaker.real_name, "message_type" = "whisper", "message_content" = text))
- if(!query_insert.Execute())
- log_debug("Error during logging: "+query_insert.ErrorMsg())
- qdel(query_insert)
- return
- qdel(query_insert)
-
-/proc/log_emote(text, mob/speaker)
- if (CONFIG_GET(flag/log_emote))
- WRITE_LOG(GLOB.diary, "EMOTE: [speaker.simple_info_line()]: [html_decode(text)]")
- //CHOMPEdit Begin
- if(speaker.client)
- //speaker.dialogue_log += span_bold("([time_stamp()])") + " (" + span_bold("[speaker]/[speaker.client]") + ") " + span_underline("EMOTE:") + " - " + span_pink("[text]")
- //GLOB.round_text_log += span_bold("([time_stamp()])") + " (" + span_bold("[speaker]/[speaker.client]") + ") " + span_underline("EMOTE:") + " - " + span_pink("[text]")
- if(!SSdbcore.IsConnected())
- establish_db_connection()
- if(!SSdbcore.IsConnected())
- return null
- var/datum/db_query/query_insert = SSdbcore.NewQuery("INSERT INTO erro_dialog (mid, time, ckey, mob, type, message) VALUES (null, NOW(), :sender_ckey, :sender_mob, :message_type, :message_content)", \
- list("sender_ckey" = speaker.ckey, "sender_mob" = speaker.real_name, "message_type" = "emote", "message_content" = text))
- if(!query_insert.Execute())
- log_debug("Error during logging: "+query_insert.ErrorMsg())
- qdel(query_insert)
- return
- qdel(query_insert)
- //CHOMPEdit End
-
-/proc/log_attack(attacker, defender, message)
- if (CONFIG_GET(flag/log_attack))
- WRITE_LOG(GLOB.diary, "ATTACK: [attacker] against [defender]: [message]")
-
-/proc/log_adminsay(text, mob/speaker)
- if (CONFIG_GET(flag/log_adminchat))
- WRITE_LOG(GLOB.diary, "ADMINSAY: [speaker.simple_info_line()]: [html_decode(text)]")
-
-/proc/log_modsay(text, mob/speaker)
- if (CONFIG_GET(flag/log_adminchat))
- WRITE_LOG(GLOB.diary, "MODSAY: [speaker.simple_info_line()]: [html_decode(text)]")
-
-/proc/log_eventsay(text, mob/speaker)
- if (CONFIG_GET(flag/log_adminchat))
- WRITE_LOG(GLOB.diary, "EVENTSAY: [speaker.simple_info_line()]: [html_decode(text)]")
-
-/proc/log_ghostsay(text, mob/speaker)
- if (CONFIG_GET(flag/log_say))
- WRITE_LOG(GLOB.diary, "DEADCHAT: [speaker.simple_info_line()]: [html_decode(text)]")
- //CHOMPEdit Begin
- if(speaker.client)
- if(!SSdbcore.IsConnected())
- establish_db_connection()
- if(!SSdbcore.IsConnected())
- return null
- var/datum/db_query/query_insert = SSdbcore.NewQuery("INSERT INTO erro_dialog (mid, time, ckey, mob, type, message) VALUES (null, NOW(), :sender_ckey, :sender_mob, :message_type, :message_content)", \
- list("sender_ckey" = speaker.ckey, "sender_mob" = speaker.real_name, "message_type" = "deadsay", "message_content" = text))
- if(!query_insert.Execute())
- log_debug("Error during logging: "+query_insert.ErrorMsg())
- qdel(query_insert)
- return
- qdel(query_insert)
-
- //speaker.dialogue_log += span_bold("([time_stamp()])") + " (" + span_bold("[speaker]/[speaker.client]") + ") " + span_underline("DEADSAY:") + " - " + span_green("[text]")
- //GLOB.round_text_log += span_small(span_purple(span_bold("([time_stamp()])") + " (" + span_bold("[speaker]/[speaker.client]") + ") " + span_underline("DEADSAY:") + " - [text]"))
- //CHOMPEdit End
-
-/proc/log_ghostemote(text, mob/speaker)
- if (CONFIG_GET(flag/log_emote))
- WRITE_LOG(GLOB.diary, "DEADEMOTE: [speaker.simple_info_line()]: [html_decode(text)]")
- //CHOMPEdit Begin
- if(speaker.client)
- if(!SSdbcore.IsConnected())
- establish_db_connection()
- if(!SSdbcore.IsConnected())
- return null
- var/datum/db_query/query_insert = SSdbcore.NewQuery("INSERT INTO erro_dialog (mid, time, ckey, mob, type, message) VALUES (null, NOW(), :sender_ckey, :sender_mob, :message_type, :message_content)", \
- list("sender_ckey" = speaker.ckey, "sender_mob" = speaker.real_name, "message_type" = "deademote", "message_content" = text))
- if(!query_insert.Execute())
- log_debug("Error during logging: "+query_insert.ErrorMsg())
- qdel(query_insert)
- return
- qdel(query_insert)
- //CHOMPEdit End
-
-/proc/log_adminwarn(text)
- if (CONFIG_GET(flag/log_adminwarn))
- WRITE_LOG(GLOB.diary, "ADMINWARN: [html_decode(text)]")
-
-/proc/log_pda(text, mob/speaker)
- if (CONFIG_GET(flag/log_pda))
- WRITE_LOG(GLOB.diary, "PDA: [speaker.simple_info_line()]: [html_decode(text)]")
- //CHOMPEdit Begin
- if(speaker.client)
- if(!SSdbcore.IsConnected())
- establish_db_connection()
- if(!SSdbcore.IsConnected())
- return null
- var/datum/db_query/query_insert = SSdbcore.NewQuery("INSERT INTO erro_dialog (mid, time, ckey, mob, type, message) VALUES (null, NOW(), :sender_ckey, :sender_mob, :message_type, :message_content)", \
- list("sender_ckey" = speaker.ckey, "sender_mob" = speaker.real_name, "message_type" = "pda", "message_content" = text))
- if(!query_insert.Execute())
- log_debug("Error during logging: "+query_insert.ErrorMsg())
- qdel(query_insert)
- return
- qdel(query_insert)
-
- //speaker.dialogue_log += span_bold("([time_stamp()])") + " (" + span_bold("[speaker]/[speaker.client]") + ") " + span_underline("MSG:") + " - " + span_darkgreen("[text]")
- //GLOB.round_text_log += span_bold("([time_stamp()])") + " (" + span_bold("[speaker]/[speaker.client]") + ") " + span_underline("MSG:") + " - " + span_darkgreen("[text]")
- //CHOMPEdit End
-
-/proc/log_to_dd(text)
- to_world_log(text) //this comes before the config check because it can't possibly runtime
- if(config?.loaded && CONFIG_GET(flag/log_world_output))
- WRITE_LOG(GLOB.diary, "DD_OUTPUT: [text]")
-
-/proc/log_error(text)
- to_world_log(text)
- WRITE_LOG(GLOB.error_log, "RUNTIME: [text]")
-
-/proc/log_misc(text)
- WRITE_LOG(GLOB.diary, "MISC: [text]")
-
-/proc/log_sql(text)
- WRITE_LOG(GLOB.sql_error_log, "SQL: [text]")
-
-/proc/log_query_debug(text)
- WRITE_LOG(GLOB.query_debug_log, "SQL: [text]")
-
-/proc/log_topic(text)
- if(GLOB.Debug2)
- WRITE_LOG(GLOB.diary, "TOPIC: [text]")
-
-/proc/log_unit_test(text)
- to_world_log("## UNIT_TESTS: [text]")
-
-#ifdef REFERENCE_TRACKING_LOG
-#define log_reftracker(msg) WRITE_LOG(GLOB.diary, "## REF SEARCH [msg]")
-#else
-#define log_reftracker(msg)
-#endif
-
-/proc/log_asset(text)
- WRITE_LOG(GLOB.diary, "ASSET: [text]")
-
-/// Puts the text into the research html file, not log. See [INVESTIGATE_RESEARCH] for [/atom/proc/investigate_log]
-/proc/log_research(text)
- if(!text)
- return
- var/html_file = file("[GLOB.log_directory]/[INVESTIGATE_RESEARCH].html")
- WRITE_FILE(html_file, "[time_stamp()] [text]
")
-
-/proc/report_progress(var/progress_message)
- admin_notice(span_boldannounce("[progress_message]"), R_DEBUG)
- to_world_log(progress_message)
-
-//pretty print a direction bitflag, can be useful for debugging.
-/proc/print_dir(var/dir)
- var/list/comps = list()
- if(dir & NORTH) comps += "NORTH"
- if(dir & SOUTH) comps += "SOUTH"
- if(dir & EAST) comps += "EAST"
- if(dir & WEST) comps += "WEST"
- if(dir & UP) comps += "UP"
- if(dir & DOWN) comps += "DOWN"
-
- return english_list(comps, nothing_text="0", and_text="|", comma_text="|")
-
-//more or less a logging utility
-//Always return "Something/(Something)", even if it's an error message.
-/proc/key_name(var/whom, var/include_link = FALSE, var/include_name = TRUE, var/highlight_special_characters = TRUE)
- var/mob/M
- var/client/C
- var/key
-
- if(!whom)
- return "INVALID/INVALID"
- if(istype(whom, /client))
- C = whom
- M = C.mob
- key = C.key
- else if(ismob(whom))
- M = whom
- C = M.client
- key = M.key
- else if(istype(whom, /datum/mind))
- var/datum/mind/D = whom
- key = D.key
- M = D.current
- if(D.current)
- C = D.current.client
- else if(istype(whom, /datum))
- var/datum/D = whom
- return "INVALID/([D.type])"
- else if(istext(whom))
- return "AUTOMATED/[whom]" //Just give them the text back
- else
- return "INVALID/INVALID"
-
- . = ""
-
- if(key)
- if(include_link && C)
- . += ""
-
- if(C && C.holder && C.holder.fakekey)
- . += C.holder.rank_names() // CHOMPEdit: Stealth mode displays staff rank in PM Messages
- else
- . += key
-
- if(include_link)
- if(C) . += ""
- else . += " (DC)"
- else
- . += "INVALID"
-
- if(include_name)
- var/name = "INVALID"
- if(M)
- if(M.real_name)
- name = M.real_name
- else if(M.name)
- name = M.name
-
- if(include_link && is_special_character(M) && highlight_special_characters)
- name = span_orange("[name]") //Orange
-
- . += "/([name])"
-
- return .
-
-/proc/key_name_admin(var/whom, var/include_name = 1)
- return key_name(whom, 1, include_name)
-
-// Helper procs for building detailed log lines
-//
-// These procs must not fail under ANY CIRCUMSTANCES!
-//
-
-/datum/proc/log_info_line()
- return "[src] ([type])"
-
-/atom/log_info_line()
- . = ..()
- var/turf/t = get_turf(src)
- if(istype(t))
- return "[.] @ [t.log_info_line()]"
- else if(loc)
- return "[.] @ ([loc]) (0,0,0) ([loc.type])"
- else
- return "[.] @ (NULL) (0,0,0) (NULL)"
-
-/turf/log_info_line()
- return "([src]) ([x],[y],[z]) ([type])"
-
-/mob/log_info_line()
- return "[..()] (ckey=[ckey])"
-
-/proc/log_info_line(var/datum/d)
- if(!d)
- return "*null*"
- if(!istype(d))
- return json_encode(d)
- return d.log_info_line()
-
-/mob/proc/simple_info_line()
- return "[key_name(src)] ([x],[y],[z])"
-
-/client/proc/simple_info_line()
- return "[key_name(src)] ([mob.x],[mob.y],[mob.z])"
diff --git a/code/_helpers/logging/_logging.dm b/code/_helpers/logging/_logging.dm
new file mode 100644
index 0000000000..b38409a1d3
--- /dev/null
+++ b/code/_helpers/logging/_logging.dm
@@ -0,0 +1,274 @@
+//print a warning message to world.log
+#define WARNING(MSG) warning("[MSG] in [__FILE__] at line [__LINE__] src: [UNLINT(src)] usr: [usr].")
+/proc/warning(msg)
+ msg = "## WARNING: [msg]"
+ log_world(msg)
+
+//not an error or a warning, but worth to mention on the world log, just in case.
+#define NOTICE(MSG) notice(MSG)
+/proc/notice(msg)
+ msg = "## NOTICE: [msg]"
+ log_world(msg)
+
+#define SET_SERIALIZATION_SEMVER(semver_list, semver) semver_list[type] = semver
+#define CHECK_SERIALIZATION_SEMVER(wanted, actual) (__check_serialization_semver(wanted, actual))
+
+/// Checks if the actual semver is equal or later than the wanted semver
+/// Must be passed as TEXT; you're probably looking for CHECK_SERIALIZATION_SEMVER, look right above
+/proc/__check_serialization_semver(wanted, actual)
+ if(wanted == actual)
+ return TRUE
+
+ var/list/wanted_versions = semver_to_list(wanted)
+ var/list/actual_versions = semver_to_list(actual)
+
+ if(!wanted_versions || !actual_versions)
+ stack_trace("Invalid semver string(s) passed to __check_serialization_semver: '[wanted]' and '[actual]'")
+ return FALSE
+
+ if(wanted_versions[1] != actual_versions[1])
+ return FALSE // major must always
+
+ if(wanted_versions[2] > actual_versions[2])
+ return FALSE // actual must be later than wanted
+
+ // patch is not checked
+ return TRUE
+
+//print a testing-mode debug message to world.log and world
+#ifdef TESTING
+#define testing(msg) log_world("## TESTING: [msg]"); to_chat(world, "## TESTING: [msg]")
+
+GLOBAL_LIST_INIT(testing_global_profiler, list("_PROFILE_NAME" = "Global"))
+// we don't really check if a word or name is used twice, be aware of that
+#define testing_profile_start(NAME, LIST) LIST[NAME] = world.timeofday
+#define testing_profile_current(NAME, LIST) round((world.timeofday - LIST[NAME])/10,0.1)
+#define testing_profile_output(NAME, LIST) testing("[LIST["_PROFILE_NAME"]] profile of [NAME] is [testing_profile_current(NAME,LIST)]s")
+#define testing_profile_output_all(LIST) { for(var/_NAME in LIST) { testing_profile_current(,_NAME,LIST); }; };
+#else
+#define testing(msg)
+#define testing_profile_start(NAME, LIST)
+#define testing_profile_current(NAME, LIST)
+#define testing_profile_output(NAME, LIST)
+#define testing_profile_output_all(LIST)
+#endif
+
+#if defined(UNIT_TESTS) || defined(SPACEMAN_DMM)
+/proc/log_test(text)
+ WRITE_LOG(GLOB.test_log, text)
+ SEND_TEXT(world.log, text)
+#endif
+
+#if defined(REFERENCE_TRACKING_LOG_APART)
+#define log_reftracker(msg) log_harddel("## REF SEARCH [msg]")
+
+/proc/log_harddel(text)
+ WRITE_LOG(GLOB.harddel_log, text)
+
+#elif defined(REFERENCE_TRACKING) // Doing it locally
+#define log_reftracker(msg) log_world("## REF SEARCH [msg]")
+
+#else //Not tracking at all
+#define log_reftracker(msg)
+#endif
+
+/**
+ * Generic logging helper
+ *
+ * reads the type of the log
+ * and writes it to the respective log file
+ * unless log_globally is FALSE
+ * Arguments:
+ * * message - The message being logged
+ * * message_type - the type of log the message is(ATTACK, SAY, etc)
+ * * color - color of the log text
+ * * log_globally - boolean checking whether or not we write this log to the log file
+ */
+/atom/proc/log_message(message, message_type, color = null, log_globally = TRUE, list/data)
+ if(!log_globally)
+ return
+
+ var/log_text = "[key_name_and_tag(src)] [message] [loc_name(src)]"
+ switch(message_type)
+ /// ship both attack logs and victim logs to the end of round attack.log just to ensure we don't lose information
+ if(LOG_ATTACK, LOG_VICTIM)
+ log_attack(log_text, data)
+ if(LOG_SAY)
+ log_say(log_text, data)
+ if(LOG_WHISPER)
+ log_whisper(log_text, data)
+ if(LOG_EMOTE)
+ log_emote(log_text, data)
+ if(LOG_PDA)
+ log_pda(log_text, data)
+ if(LOG_OOC)
+ log_ooc(log_text, data)
+ if(LOG_LOOC)
+ log_looc(log_text, data)
+ if(LOG_ADMIN)
+ log_admin(log_text, data)
+ if(LOG_ADMIN_PRIVATE)
+ log_admin_private(log_text, data)
+ if(LOG_ASAY)
+ log_adminsay(log_text, data)
+ if(LOG_GAME)
+ log_game(log_text, data)
+ else
+ stack_trace("Invalid individual logging type: [message_type]. Defaulting to [LOG_GAME] (LOG_GAME).")
+ log_game(log_text, data)
+
+/* For logging round startup. */
+/proc/start_log(log)
+ WRITE_LOG(log, "Starting up round ID [GLOB.round_id].\n-------------------------")
+
+/* Close open log handles. This should be called as late as possible, and no logging should hapen after. */
+/proc/shutdown_logging()
+ rustg_log_close_all()
+ logger.shutdown_logging()
+
+/* Helper procs for building detailed log lines */
+/proc/key_name(whom, include_link = null, include_name = TRUE)
+ var/mob/M
+ var/client/C
+ var/key
+ var/ckey
+ var/fallback_name
+
+ if(!whom)
+ return "*null*"
+ if(istype(whom, /client))
+ C = whom
+ M = C.mob
+ key = C.key
+ ckey = C.ckey
+ else if(ismob(whom))
+ M = whom
+ C = M.client
+ key = M.key
+ ckey = M.ckey
+ else if(istext(whom))
+ key = whom
+ ckey = ckey(whom)
+ C = GLOB.directory[ckey]
+ if(C)
+ M = C.mob
+ else if(istype(whom,/datum/mind))
+ var/datum/mind/mind = whom
+ key = mind.key
+ ckey = ckey(key)
+ if(mind.current)
+ M = mind.current
+ if(M.client)
+ C = M.client
+ else
+ fallback_name = mind.name
+ else // Catch-all cases if none of the types above match
+ var/swhom = null
+
+ if(istype(whom, /atom))
+ var/atom/A = whom
+ swhom = "[A.name]"
+ else if(isdatum(whom))
+ swhom = "[whom]"
+
+ if(!swhom)
+ swhom = "*invalid*"
+
+ return "\[[swhom]\]"
+
+ . = ""
+
+ if(!ckey)
+ include_link = FALSE
+
+ if(key)
+ if(C?.holder && C.holder.fakekey && !include_name)
+ if(include_link)
+ . += ""
+ . += "Administrator"
+ else
+ if(include_link)
+ . += ""
+ . += key
+ if(!C)
+ . += "\[DC\]"
+
+ if(include_link)
+ . += ""
+ else
+ . += "*no key*"
+
+ if(include_name)
+ if(M)
+ if(M.real_name)
+ . += "/([M.real_name])"
+ else if(M.name)
+ . += "/([M.name])"
+ else if(fallback_name)
+ . += "/([fallback_name])"
+
+ return .
+
+/proc/key_name_admin(whom, include_name = TRUE)
+ return key_name(whom, TRUE, include_name)
+
+/proc/key_name_and_tag(whom, include_link = null, include_name = TRUE)
+ var/tag = "!tagless!" // whom can be null in key_name() so lets set this as a safety
+ if(isatom(whom))
+ var/atom/subject = whom
+ tag = subject.tag
+ return "[key_name(whom, include_link, include_name)] ([tag])"
+
+/proc/loc_name(atom/A)
+ if(!istype(A))
+ return "(INVALID LOCATION)"
+
+ var/turf/T = A
+ if (!istype(T))
+ T = get_turf(A)
+
+ if(istype(T))
+ return "([AREACOORD(T)])"
+ else if(A.loc)
+ return "(UNKNOWN (?, ?, ?))"
+
+// Virgo specific Helper procs for building detailed log lines
+//
+// These procs must not fail under ANY CIRCUMSTANCES!
+// Are these even still required?
+
+/proc/report_progress(var/progress_message)
+ admin_notice(span_boldannounce("[progress_message]"), R_DEBUG)
+ log_world(progress_message)
+
+/datum/proc/log_info_line()
+ return "[src] ([type])"
+
+/atom/log_info_line()
+ . = ..()
+ var/turf/t = get_turf(src)
+ if(istype(t))
+ return "[.] @ [t.log_info_line()]"
+ else if(loc)
+ return "[.] @ ([loc]) (0,0,0) ([loc.type])"
+ else
+ return "[.] @ (NULL) (0,0,0) (NULL)"
+
+/turf/log_info_line()
+ return "([src]) ([x],[y],[z]) ([type])"
+
+/mob/log_info_line()
+ return "[..()] (ckey=[ckey])"
+
+/proc/log_info_line(var/datum/d)
+ if(!d)
+ return "*null*"
+ if(!istype(d))
+ return json_encode(d)
+ return d.log_info_line()
+
+/mob/proc/simple_info_line()
+ return "[key_name(src)] ([x],[y],[z])"
+
+/client/proc/simple_info_line()
+ return "[key_name(src)] ([mob.x],[mob.y],[mob.z])"
diff --git a/code/_helpers/logging/admin.dm b/code/_helpers/logging/admin.dm
new file mode 100644
index 0000000000..cff42007ac
--- /dev/null
+++ b/code/_helpers/logging/admin.dm
@@ -0,0 +1,42 @@
+/* Items with ADMINPRIVATE prefixed are stripped from public logs. */
+
+// For backwards compatibility these are currently also added to LOG_CATEGORY_GAME with their respective prefix
+// This is to avoid breaking any existing tools that rely on the old format, but should be removed in the future
+
+/// General logging for admin actions
+/proc/log_admin(text, list/data)
+ GLOB.admin_activities.Add(text)
+ logger.Log(LOG_CATEGORY_ADMIN, text, data)
+ logger.Log(LOG_CATEGORY_COMPAT_GAME, "ADMIN: [text]")
+
+/// General logging for admin actions
+/proc/log_admin_private(text, list/data)
+ GLOB.admin_activities.Add(text)
+ logger.Log(LOG_CATEGORY_ADMIN_PRIVATE, text, data)
+ logger.Log(LOG_CATEGORY_COMPAT_GAME, "ADMINPRIVATE: [text]")
+
+/// Logging for AdminSay (ASAY) messages
+/proc/log_adminsay(text, list/data)
+ GLOB.admin_activities.Add(text)
+ logger.Log(LOG_CATEGORY_ADMIN_PRIVATE_ASAY, text, data)
+ logger.Log(LOG_CATEGORY_COMPAT_GAME, "ADMINPRIVATE: ASAY: [text]")
+
+/proc/log_modsay(text, list/data)
+ logger.Log(LOG_CATEGORY_ADMIN_PRIVATE_MSAY, text, data)
+ logger.Log(LOG_CATEGORY_COMPAT_GAME, "ADMINPRIVATE: MODSAY: [text]")
+
+/proc/log_eventsay(text, list/data)
+ logger.Log(LOG_CATEGORY_ADMIN_PRIVATE_ESAY, text, data)
+ logger.Log(LOG_CATEGORY_COMPAT_GAME, "ADMINPRIVATE: EVENTSAY: [text]")
+
+/**
+ * Writes to a special log file if the log_suspicious_login config flag is set,
+ * which is intended to contain all logins that failed under suspicious circumstances.
+ *
+ * Mirrors this log entry to log_access when access_log_mirror is TRUE, so this proc
+ * doesn't need to be used alongside log_access and can replace it where appropriate.
+ */
+/proc/log_suspicious_login(text, list/data, access_log_mirror = TRUE)
+ logger.Log(LOG_CATEGORY_SUSPICIOUS_LOGIN, text)
+ if(access_log_mirror)
+ log_access(text)
diff --git a/code/_helpers/logging/attack.dm b/code/_helpers/logging/attack.dm
new file mode 100644
index 0000000000..69a843023b
--- /dev/null
+++ b/code/_helpers/logging/attack.dm
@@ -0,0 +1,40 @@
+/// Generic attack logging
+/proc/log_attack(text, list/data)
+ logger.Log(LOG_CATEGORY_ATTACK, text, data)
+
+/**
+ * Log a combat message in the attack log
+ *
+ * Arguments:
+ * * atom/user - argument is the actor performing the action
+ * * atom/target - argument is the target of the action
+ * * what_done - is a verb describing the action (e.g. punched, throwed, kicked, etc.)
+ * * atom/object - is a tool with which the action was made (usually an item)
+ * * addition - is any additional text, which will be appended to the rest of the log line
+ */
+/proc/log_combat(atom/user, atom/target, what_done, atom/object=null, addition=null)
+ var/ssource = key_name(user)
+ var/starget = key_name(target)
+
+ var/mob/living/living_target = target
+ var/hp = istype(living_target) ? " (NEWHP: [living_target.health]) " : ""
+
+ var/sobject = ""
+ if(object)
+ sobject = " with [object]"
+ var/saddition = ""
+ if(addition)
+ saddition = " [addition]"
+
+ var/postfix = "[sobject][saddition][hp]"
+
+ var/message = "[what_done] [starget][postfix]"
+ user.log_message(message, LOG_ATTACK, color="red")
+
+ if(user != target)
+ var/reverse_message = "was [what_done] by [ssource][postfix]"
+ target.log_message(reverse_message, LOG_VICTIM, color="orange", log_globally=FALSE)
+
+/// Log for vore interactions
+/proc/log_vore(text, list/data)
+ logger.Log(LOG_CATEGORY_VORE, text, data)
diff --git a/code/_helpers/logging/debug.dm b/code/_helpers/logging/debug.dm
index 18bce9523f..752a606956 100644
--- a/code/_helpers/logging/debug.dm
+++ b/code/_helpers/logging/debug.dm
@@ -1,11 +1,50 @@
+/// Logging for loading and caching assets
+/proc/log_asset(text, list/data)
+ logger.Log(LOG_CATEGORY_DEBUG_ASSET, text, data)
+
/// Logging for config errors
/// Rarely gets called; just here in case the config breaks.
/proc/log_config(text, list/data)
- var/entry = "CONFIG: "
-
- entry += text
- entry += " | DATA: "
- entry += data
-
- WRITE_LOG(GLOB.diary, entry)
+ logger.Log(LOG_CATEGORY_CONFIG, text, data)
+ SEND_TEXT(world.log, text)
+
+/// Logging for mapping errors
+/proc/log_mapping(text, skip_world_log)
+#ifdef UNIT_TESTS
+ GLOB.unit_test_mapping_logs += text
+#endif
+#ifdef MAP_TEST
+ message_admins("Mapping: [text]")
+#endif
+ logger.Log(LOG_CATEGORY_DEBUG_MAPPING, text)
+ if(skip_world_log)
+ return
+ SEND_TEXT(world.log, text)
+
+/// Logging for game performance
+/proc/log_perf(list/perf_info)
+ . = "[perf_info.Join(",")]\n"
+ WRITE_LOG_NO_FORMAT(GLOB.perf_log, .)
+
+/// Logging for hard deletes
+/proc/log_qdel(text, list/data)
+ logger.Log(LOG_CATEGORY_QDEL, text, data)
+
+/* Log to the logfile only. */
+/proc/log_runtime(text, list/data)
+ logger.Log(LOG_CATEGORY_RUNTIME, text, data)
+
+/// Logging for DB errors
+/proc/log_sql(text, list/data)
+ logger.Log(LOG_CATEGORY_DEBUG_SQL, text, data)
+
+/// Logging for world/Topic
+/proc/log_topic(text, list/data)
+ logger.Log(LOG_CATEGORY_GAME_TOPIC, text, data)
+
+/// Log to both DD and the logfile.
+/proc/log_world(text, list/data)
+#ifdef USE_CUSTOM_ERROR_HANDLER
+ logger.Log(LOG_CATEGORY_RUNTIME, text, data)
+#endif
SEND_TEXT(world.log, text)
diff --git a/code/_helpers/logging/game.dm b/code/_helpers/logging/game.dm
new file mode 100644
index 0000000000..dc825141d8
--- /dev/null
+++ b/code/_helpers/logging/game.dm
@@ -0,0 +1,27 @@
+/// Logging for generic/unsorted game messages
+/proc/log_game(text, list/data)
+ logger.Log(LOG_CATEGORY_GAME, text, data)
+
+/// Logging for emotes
+/proc/log_emote(text, list/data)
+ logger.Log(LOG_CATEGORY_GAME_EMOTE, text, data)
+
+/// Logging for messages sent in OOC
+/proc/log_ooc(text, list/data)
+ logger.Log(LOG_CATEGORY_GAME_OOC, text, data)
+
+/// Logging for messages sent in LOOC
+/proc/log_looc(text, list/data)
+ logger.Log(LOG_CATEGORY_GAME_LOOC, text, data)
+
+/// Logging for prayed messages
+/proc/log_prayer(text, list/data)
+ logger.Log(LOG_CATEGORY_GAME_PRAYER, text, data)
+
+/// Logging for logging in & out of the game, with error messages.
+/proc/log_access(text, list/data)
+ logger.Log(LOG_CATEGORY_GAME_ACCESS, text, data)
+
+/// Logging for OOC votes
+/proc/log_vote(text, list/data)
+ logger.Log(LOG_CATEGORY_GAME_VOTE, text, data)
diff --git a/code/_helpers/logging/mob.dm b/code/_helpers/logging/mob.dm
new file mode 100644
index 0000000000..9db2f0f6db
--- /dev/null
+++ b/code/_helpers/logging/mob.dm
@@ -0,0 +1,54 @@
+/**
+ * Logs a message to the mob_tags log, including the mobs tag
+ * Arguments:
+ * * text - text to log.
+ */
+/mob/proc/log_mob_tag(text, list/data)
+ logger.Log(LOG_CATEGORY_DEBUG_MOBTAG, text, data)
+
+/// Logs a message in a mob's individual log, and in the global logs as well if log_globally is true
+/mob/log_message(message, message_type, color = null, log_globally = TRUE, list/data)
+ if(!LAZYLEN(message))
+ stack_trace("Empty message")
+ return
+
+ // Cannot use the list as a map if the key is a number, so we stringify it (thank you BYOND)
+ var/smessage_type = num2text(message_type, MAX_BITFLAG_DIGITS)
+
+ if(HAS_CONNECTED_PLAYER(src))
+ if(!islist(persistent_client.logging[smessage_type]))
+ persistent_client.logging[smessage_type] = list()
+
+ if(!islist(logging[smessage_type]))
+ logging[smessage_type] = list()
+
+ var/colored_message = message
+ if(color)
+ if(color[1] == "#")
+ colored_message = "[message]"
+ else
+ colored_message = "[message]"
+
+ //This makes readability a bit better for admins.
+ switch(message_type)
+ if(LOG_WHISPER)
+ colored_message = "(WHISPER) [colored_message]"
+ if(LOG_OOC)
+ colored_message = "(OOC) [colored_message]"
+ if(LOG_LOOC)
+ colored_message = "(LOOC) [colored_message]"
+ if(LOG_ASAY)
+ colored_message = "(ASAY) [colored_message]"
+ if(LOG_EMOTE)
+ colored_message = "(EMOTE) [colored_message]"
+ if(LOG_RADIO_EMOTE)
+ colored_message = "(RADIOEMOTE) [colored_message]"
+
+ var/list/timestamped_message = list("\[[time_stamp(format = "YYYY-MM-DD hh:mm:ss")]\] [key_name_and_tag(src)] [loc_name(src)] (Event #[LAZYLEN(logging[smessage_type])])" = colored_message)
+
+ logging[smessage_type] += timestamped_message
+
+ if(HAS_CONNECTED_PLAYER(src))
+ persistent_client.logging[smessage_type] += timestamped_message
+
+ ..()
diff --git a/code/_helpers/logging/pda.dm b/code/_helpers/logging/pda.dm
new file mode 100644
index 0000000000..f37aea47ad
--- /dev/null
+++ b/code/_helpers/logging/pda.dm
@@ -0,0 +1,3 @@
+/// Logging for PDA messages sent
+/proc/log_pda(text, list/data)
+ logger.Log(LOG_CATEGORY_PDA, text, data)
diff --git a/code/_helpers/logging/research.dm b/code/_helpers/logging/research.dm
new file mode 100644
index 0000000000..f352123f9a
--- /dev/null
+++ b/code/_helpers/logging/research.dm
@@ -0,0 +1,6 @@
+/// Puts the text into the research html file, not log. See [INVESTIGATE_RESEARCH] for [/atom/proc/investigate_log]
+/proc/log_research(text)
+ if(!text)
+ return
+ var/html_file = file("[GLOB.log_directory]/[INVESTIGATE_RESEARCH].html")
+ WRITE_FILE(html_file, "[time_stamp(format = "YYYY-MM-DD hh:mm:ss")] [text]
")
diff --git a/code/_helpers/logging/talk.dm b/code/_helpers/logging/talk.dm
new file mode 100644
index 0000000000..36e8dfb3d8
--- /dev/null
+++ b/code/_helpers/logging/talk.dm
@@ -0,0 +1,25 @@
+/**
+ * Helper for logging chat messages or other logs with arbitrary inputs (e.g. announcements)
+ *
+ * This proc compiles a log string by prefixing the tag to the message
+ * and suffixing what it was forced_by if anything
+ * if the message lacks a tag and suffix then it is logged on its own
+ * Arguments:
+ * * message - The message being logged
+ * * message_type - the type of log the message is(ATTACK, SAY, etc)
+ * * tag - tag that indicates the type of text(announcement, telepathy, etc)
+ * * log_globally - boolean checking whether or not we write this log to the log file
+ * * forced_by - source that forced the dialogue if any
+ */
+/atom/proc/log_talk(message, message_type, tag = null, log_globally = TRUE, forced_by = null, custom_say_emote = null)
+ var/prefix = tag ? "([tag]) " : ""
+ var/suffix = forced_by ? " FORCED by [forced_by]" : ""
+ log_message("[prefix][custom_say_emote ? "*[custom_say_emote]*, " : ""]\"[message]\"[suffix]", message_type, log_globally = log_globally)
+
+/// Logging for generic spoken messages
+/proc/log_say(text, list/data)
+ logger.Log(LOG_CATEGORY_GAME_SAY, text, data)
+
+/// Logging for whispered messages
+/proc/log_whisper(text, list/data)
+ logger.Log(LOG_CATEGORY_GAME_WHISPER, text, data)
diff --git a/code/_helpers/logging/ui.dm b/code/_helpers/logging/ui.dm
index 57e927c5b3..1c72f314f3 100644
--- a/code/_helpers/logging/ui.dm
+++ b/code/_helpers/logging/ui.dm
@@ -1,13 +1,17 @@
-/proc/log_href(text)
- //WRITE_LOG(GLOB.world_href_log, "HREF: [text]")
- WRITE_LOG(GLOB.href_logfile, "HREF: [text]")
+/proc/log_href(text, list/data)
+ logger.Log(LOG_CATEGORY_HREF, text, data)
/**
* Appends a tgui-related log entry. All arguments are optional.
*/
-/proc/log_tgui(user, message, context,
- datum/tgui_window/window,
- datum/src_object)
+/proc/log_tgui(
+ user,
+ message,
+ context,
+ datum/tgui_window/window,
+ datum/src_object,
+)
+
var/entry = ""
// Insert user info
if(!user)
@@ -32,5 +36,4 @@
// Insert message
if(message)
entry += "\n[message]"
- //WRITE_LOG(GLOB.tgui_log, entry)
- WRITE_LOG(GLOB.diary, entry)
+ logger.Log(LOG_CATEGORY_HREF_TGUI, entry)
diff --git a/code/_helpers/logging_vr.dm b/code/_helpers/logging_vr.dm
deleted file mode 100644
index a4cd514d56..0000000000
--- a/code/_helpers/logging_vr.dm
+++ /dev/null
@@ -1,53 +0,0 @@
-/proc/log_nsay(text, inside, mob/speaker)
- if (CONFIG_GET(flag/log_say))
- WRITE_LOG(GLOB.diary, "NSAY (NIF:[inside]): [speaker.simple_info_line()]: [html_decode(text)]")
- //CHOMPEdit Begin
- if(speaker.client)
- if(!SSdbcore.IsConnected())
- establish_db_connection()
- if(!SSdbcore.IsConnected())
- return null
- var/datum/db_query/query_insert = SSdbcore.NewQuery("INSERT INTO erro_dialog (mid, time, ckey, mob, type, message) VALUES (null, NOW(), :sender_ckey, :sender_mob, :message_type, :message_content)", \
- list("sender_ckey" = speaker.ckey, "sender_mob" = speaker.real_name, "message_type" = "nsay", "message_content" = text))
- if(!query_insert.Execute())
- log_debug("Error during logging: "+query_insert.ErrorMsg())
- qdel(query_insert)
- return
- qdel(query_insert)
- //CHOMPEdit End
-
-/proc/log_nme(text, inside, mob/speaker)
- if (CONFIG_GET(flag/log_emote))
- WRITE_LOG(GLOB.diary, "NME (NIF:[inside]): [speaker.simple_info_line()]: [html_decode(text)]")
- //CHOMPEdit Begin
- if(speaker.client)
- if(!SSdbcore.IsConnected())
- establish_db_connection()
- if(!SSdbcore.IsConnected())
- return null
- var/datum/db_query/query_insert = SSdbcore.NewQuery("INSERT INTO erro_dialog (mid, time, ckey, mob, type, message) VALUES (null, NOW(), :sender_ckey, :sender_mob, :message_type, :message_content)", \
- list("sender_ckey" = speaker.ckey, "sender_mob" = speaker.real_name, "message_type" = "nme", "message_content" = text))
- if(!query_insert.Execute())
- log_debug("Error during logging: "+query_insert.ErrorMsg())
- qdel(query_insert)
- return
- qdel(query_insert)
- //CHOMPEdit End
-
-/proc/log_subtle(text, mob/speaker)
- if (CONFIG_GET(flag/log_emote))
- WRITE_LOG(GLOB.diary, "SUBTLE: [speaker.simple_info_line()]: [html_decode(text)]")
- //CHOMPEdit Begin
- if(speaker.client)
- if(!SSdbcore.IsConnected())
- establish_db_connection()
- if(!SSdbcore.IsConnected())
- return null
- var/datum/db_query/query_insert = SSdbcore.NewQuery("INSERT INTO erro_dialog (mid, time, ckey, mob, type, message) VALUES (null, NOW(), :sender_ckey, :sender_mob, :message_type, :message_content)", \
- list("sender_ckey" = speaker.ckey, "sender_mob" = speaker.real_name, "message_type" = "subtle", "message_content" = text))
- if(!query_insert.Execute())
- log_debug("Error during logging: "+query_insert.ErrorMsg())
- qdel(query_insert)
- return
- qdel(query_insert)
- //CHOMPEdit End
diff --git a/code/_helpers/mobs.dm b/code/_helpers/mobs.dm
index f2d222ea79..2f4263d520 100644
--- a/code/_helpers/mobs.dm
+++ b/code/_helpers/mobs.dm
@@ -150,7 +150,7 @@ Proc for attack log creation, because really why not
6 is additional information, anything that needs to be added
*/
-/proc/add_attack_logs(mob/user, mob/target, what_done, var/admin_notify = TRUE, var/use_async = TRUE) //CHOMPEdit
+/proc/add_attack_logs(mob/user, mob/target, what_done, var/admin_notify = TRUE)
if(islist(target)) //Multi-victim adding
var/list/targets = target
for(var/mob/M in targets)
@@ -160,27 +160,11 @@ Proc for attack log creation, because really why not
var/user_str = key_name(user)
var/target_str = key_name(target)
- if(ismob(user)) //CHOMPEdit Begin
- if(SSdbcore.Connect())
- user.attack_log += text("\[[time_stamp()]\] [span_red("Attacked [target_str]: [what_done]")]")
- var/datum/db_query/query_insert = SSdbcore.NewQuery("INSERT INTO erro_attacklog (id, time, ckey, mob, message) VALUES (null, NOW(), :t_ckey, :t_mob, :t_content)", list("t_ckey" = user.ckey, "t_mob" = user.real_name, "t_content" = "Attacked [target_str]: [what_done]"))
- spawn() //Change this to a spawn so it doesn't hold us up
- query_insert.Execute(async=use_async)
- qdel(query_insert)
- //if(SSdbcore.Connect())
- // rustg_sql_query_async(SSdbcore.connection, "INSERT INTO erro_attacklog (id, time, ckey, mob, message) VALUES (null, NOW(), :t_ckey, :t_mob, :t_content)", json_encode(list("t_ckey" = user.ckey, "t_mob" = user.real_name, "t_content" = "Attacked [target_str]: [what_done]")))
+ if(ismob(user))
+ user.attack_log += text("\[[time_stamp()]\] [span_red("Attacked [target_str]: [what_done]")]")
if(ismob(target))
- if(SSdbcore.Connect())
- target.attack_log += text("\[[time_stamp()]\] [span_orange("Attacked by [user_str]: [what_done]")]")
- var/datum/db_query/query_insert = SSdbcore.NewQuery("INSERT INTO erro_attacklog (id, time, ckey, mob, message) VALUES (null, NOW(), :t_ckey, :t_mob, :t_content)", list("t_ckey" = target.ckey, "t_mob" = target.real_name, "t_content" = "Attacked by [user_str]: [what_done]"))
- spawn() //Change this to a spawn so it doesn't hold us up
- if(query_insert)
- query_insert.Execute(async=use_async)
- qdel(query_insert)
- //if(SSdbcore.Connect())
- // rustg_sql_query_async(SSdbcore.connection, "INSERT INTO erro_attacklog (id, time, ckey, mob, message) VALUES (null, NOW(), :t_ckey, :t_mob, :t_content)", json_encode(list("t_ckey" = target.ckey, "t_mob" = target.real_name, "t_content" = "Attacked by [user_str]: [what_done]")))
- //CHOMPEdit End
- log_attack(user_str,target_str,what_done)
+ target.attack_log += text("\[[time_stamp()]\] [span_orange("Attacked by [user_str]: [what_done]")]")
+ log_combat(user, target, what_done)
if(admin_notify)
msg_admin_attack("[key_name_admin(user)] vs [target_str]: [what_done]")
diff --git a/code/_helpers/stack_trace.dm b/code/_helpers/stack_trace.dm
new file mode 100644
index 0000000000..bb2d78de11
--- /dev/null
+++ b/code/_helpers/stack_trace.dm
@@ -0,0 +1,4 @@
+/// gives us the stack trace from CRASH() without ending the current proc.
+/// Do not call directly, use the [stack_trace] macro instead.
+/proc/_stack_trace(message, file, line)
+ CRASH("[message][WORKAROUND_IDENTIFIER][json_encode(list(file, line))][WORKAROUND_IDENTIFIER]")
diff --git a/code/_helpers/text.dm b/code/_helpers/text.dm
index 10497416e6..400959bfa4 100644
--- a/code/_helpers/text.dm
+++ b/code/_helpers/text.dm
@@ -669,3 +669,15 @@ GLOBAL_LIST_EMPTY(text_tag_cache)
temp = findtextEx(haystack, ascii2text(text2ascii(needles,i)), start, end) //Note: ascii2text(text2ascii) is faster than copytext()
if(temp) end = temp
return end
+
+/// Converts a semver string into a list of numbers
+/proc/semver_to_list(semver_string)
+ var/static/regex/semver_regex = regex(@"(\d+)\.(\d+)\.(\d+)", "")
+ if(!semver_regex.Find(semver_string))
+ return null
+
+ return list(
+ text2num(semver_regex.group[1]),
+ text2num(semver_regex.group[2]),
+ text2num(semver_regex.group[3]),
+ )
diff --git a/code/_helpers/time.dm b/code/_helpers/time.dm
index 9eea7fd893..cb923220f3 100644
--- a/code/_helpers/time.dm
+++ b/code/_helpers/time.dm
@@ -50,11 +50,10 @@ var/next_station_date_change = 1 DAY
station_date = num2text((text2num(time2text(REALTIMEOFDAY, "YYYY"))+544)) + "-" + time2text(REALTIMEOFDAY, "MM-DD") //CHOMP EDIT
return station_date
-//ISO 8601
-/proc/time_stamp()
- var/date_portion = time2text(world.timeofday, "YYYY-MM-DD")
- var/time_portion = time2text(world.timeofday, "hh:mm:ss")
- return "[date_portion]T[time_portion]"
+/// Returns UTC timestamp with the specifified format and optionally deciseconds
+/proc/time_stamp(format = "hh:mm:ss", show_ds)
+ var/time_string = time2text(world.timeofday, format, TIMEZONE_UTC)
+ return show_ds ? "[time_string]:[world.timeofday % 10]" : time_string
/* //ChompREMOVE
/proc/get_timezone_offset()
diff --git a/code/_helpers/turfs.dm b/code/_helpers/turfs.dm
index 47d6995e4d..d4e1b08e6d 100644
--- a/code/_helpers/turfs.dm
+++ b/code/_helpers/turfs.dm
@@ -79,7 +79,7 @@
var/turf/target = locate(dst_origin.x + x_pos, dst_origin.y + y_pos, dst_origin.z + z_pos)
if(!target)
- error("Null turf in translation @ ([dst_origin.x + x_pos], [dst_origin.y + y_pos], [dst_origin.z + z_pos])")
+ log_world("## ERROR Null turf in translation @ ([dst_origin.x + x_pos], [dst_origin.y + y_pos], [dst_origin.z + z_pos])")
turf_map[source] = target //if target is null, preserve that information in the turf map
return turf_map
@@ -106,7 +106,7 @@
//You can stay, though.
if(istype(T,/turf/space))
- error("Tried to translate a space turf: src=[log_info_line(T)] dst=[log_info_line(B)]")
+ log_world("## ERROR Tried to translate a space turf: src=[log_info_line(T)] dst=[log_info_line(B)]")
return FALSE // TODO - Is this really okay to do nothing?
var/turf/X //New Destination Turf
diff --git a/code/_helpers/type2type.dm b/code/_helpers/type2type.dm
index 026c0e8b99..59cd38a927 100644
--- a/code/_helpers/type2type.dm
+++ b/code/_helpers/type2type.dm
@@ -8,13 +8,6 @@
* angle2dir
*/
-//Splits the text of a file at seperator and returns them in a list.
-//returns an empty list if the file doesn't exist
-/world/proc/file2list(filename, seperator="\n", trim = TRUE)
- if (trim)
- return splittext(trim(file2text(filename)),seperator)
- return splittext(file2text(filename),seperator)
-
//returns a string the last bit of a type, without the preceeding '/'
/proc/type2top(the_type)
//handle the builtins manually
@@ -36,54 +29,18 @@
else //regex everything else (works for /proc too)
return lowertext(replacetext("[the_type]", "[type2parent(the_type)]/", ""))
-// Returns an integer given a hexadecimal number string as input.
-/proc/hex2num(hex)
- if (!istext(hex))
- return
-
- var/num = 0
- var/power = 1
- var/i = length(hex)
-
- while (i)
- var/char = text2ascii(hex, i)
- switch(char)
- if(48) pass() // 0 -- do nothing
- if(49 to 57) num += (char - 48) * power // 1-9
- if(97, 65) num += power * 10 // A
- if(98, 66) num += power * 11 // B
- if(99, 67) num += power * 12 // C
- if(100, 68) num += power * 13 // D
- if(101, 69) num += power * 14 // E
- if(102, 70) num += power * 15 // F
- else
- return
- power *= 16
- i--
- return num
-
-// Returns the hex value of a number given a value assumed to be a base-ten value
-/proc/num2hex(num, padlength)
- . = ""
- while(num > 0)
- var/hexdigit = GLOB.hexNums[(num & 0xF) + 1]
- . = "[hexdigit][.]"
- num >>= 4 //go to the next half-byte
-
- //pad with zeroes
- var/left = padlength - length(.)
- while (left-- > 0)
- . = "0[.]"
-
/proc/text2numlist(text, delimiter="\n")
var/list/num_list = list()
for(var/x in splittext(text, delimiter))
num_list += text2num(x)
return num_list
-// Splits the text of a file at seperator and returns them in a list.
-/proc/file2list(filename, seperator="\n")
- return splittext(return_file_text(filename),seperator)
+//Splits the text of a file at seperator and returns them in a list.
+//returns an empty list if the file doesn't exist
+/world/proc/file2list(filename, seperator="\n", trim = TRUE)
+ if (trim)
+ return splittext(trim(file2text(filename)),seperator)
+ return splittext(file2text(filename),seperator)
// Turns a direction into text
/proc/num2dir(direction)
@@ -93,7 +50,7 @@
if (4.0) return EAST
if (8.0) return WEST
else
- to_world_log("UNKNOWN DIRECTION: [direction]")
+ log_world("UNKNOWN DIRECTION: [direction]")
// Turns a direction into text
/proc/dir2text(direction)
@@ -597,12 +554,13 @@
if(fexists(filename))
. = file2text(filename)
if(!. && error_on_invalid_return)
- error("File empty ([filename])")
+ log_world("## ERROR File empty ([filename])")
else if(error_on_invalid_return)
- error("File not found ([filename])")
+ log_world("## ERROR File not found ([filename])")
catch(var/exception/E)
if(error_on_invalid_return)
- error("Exception when loading file as string: [E]")
+ log_world("## ERROR Exception when loading file as string: [E]")
+ log_runtime(E)
/// Return html to load a url.
diff --git a/code/_helpers/unsorted.dm b/code/_helpers/unsorted.dm
index 0d041757a1..e401845763 100644
--- a/code/_helpers/unsorted.dm
+++ b/code/_helpers/unsorted.dm
@@ -14,31 +14,6 @@
locate(min(CENTER.x+(RADIUS),world.maxx), min(CENTER.y+(RADIUS),world.maxy), CENTER.z) \
)
-//Inverts the colour of an HTML string
-/proc/invertHTML(HTMLstring)
-
- if (!( istext(HTMLstring) ))
- CRASH("Given non-text argument!")
- else
- if (length(HTMLstring) != 7)
- CRASH("Given non-HTML argument!")
- var/textr = copytext(HTMLstring, 2, 4)
- var/textg = copytext(HTMLstring, 4, 6)
- var/textb = copytext(HTMLstring, 6, 8)
- var/r = hex2num(textr)
- var/g = hex2num(textg)
- var/b = hex2num(textb)
- textr = num2hex(255 - r)
- textg = num2hex(255 - g)
- textb = num2hex(255 - b)
- if (length(textr) < 2)
- textr = text("0[]", textr)
- if (length(textg) < 2)
- textr = text("0[]", textg)
- if (length(textb) < 2)
- textr = text("0[]", textb)
- return text("#[][][]", textr, textg, textb)
-
//Returns the middle-most value
/proc/dd_range(var/low, var/high, var/num)
return max(low,min(high,num))
@@ -1219,7 +1194,7 @@ var/list/WALLITEMS = list(
colour = pick(list("FF0000","FF7F00","FFFF00","00FF00","0000FF","4B0082","8F00FF"))
else
for(var/i=1;i<=3;i++)
- var/temp_col = "[num2hex(rand(lower,upper))]"
+ var/temp_col = "[num2hex(rand(lower,upper), 2)]"
if(length(temp_col )<2)
temp_col = "0[temp_col]"
colour += temp_col
@@ -1514,21 +1489,6 @@ var/mob/dview/dview_mob
/proc/pass(...)
return
-//gives us the stack trace from CRASH() without ending the current proc.
-/proc/stack_trace(msg)
- CRASH(msg)
-
-/datum/proc/stack_trace(msg)
- CRASH(msg)
-
-GLOBAL_REAL_VAR(list/stack_trace_storage)
-/proc/gib_stack_trace()
- stack_trace_storage = list()
- stack_trace()
- stack_trace_storage.Cut(1, min(3,stack_trace_storage.len))
- . = stack_trace_storage
- stack_trace_storage = null
-
// \ref behaviour got changed in 512 so this is necesary to replicate old behaviour.
// If it ever becomes necesary to get a more performant REF(), this lies here in wait
// #define REF(thing) (thing && istype(thing, /datum) && (thing:datum_flags & DF_USE_TAG) && thing:tag ? "[thing:tag]" : "\ref[thing]")
diff --git a/code/_macros.dm b/code/_macros.dm
index 7124629bb6..e423455e9a 100644
--- a/code/_macros.dm
+++ b/code/_macros.dm
@@ -9,34 +9,18 @@
#define RANDOM_BLOOD_TYPE pick(4;"O-", 36;"O+", 3;"A-", 28;"A+", 1;"B-", 20;"B+", 1;"AB-", 5;"AB+")
#define DEFAULT_BLOOD_TYPE "A+"
-// #define to_chat(target, message) target << message Not anymore!
-//#define to_chat to_chat_filename=__FILE__;to_chat_line=__LINE__;to_chat_src=src;__to_chat
-//#define to_chat __to_chat
-#define to_world(message) to_chat(world, message)
-#define to_world_log(message) world.log << message
-// TODO - Baystation has this log to crazy places. For now lets just world.log, but maybe look into it later.
-#define log_world(message) to_world_log(message)
#define to_file(file_entry, source_var) file_entry << source_var
#define from_file(file_entry, target_var) file_entry >> target_var
#define show_browser(target, browser_content, browser_name) target << browse(browser_content, browser_name)
#define send_rsc(target, rsc_content, rsc_name) target << browse_rsc(rsc_content, rsc_name)
#define open_link(target, url) target << link(url)
-// From TG, might be useful to have.
-#define DIRECT_OUTPUT(A, B) A << B
-#define DIRECT_INPUT(A, B) A >> B
-#define SEND_IMAGE(target, image) DIRECT_OUTPUT(target, image)
-#define SEND_SOUND(target, sound) DIRECT_OUTPUT(target, sound)
-//#define WRITE_LOG is in logging.dm
-
#define CanInteract(user, state) (CanUseTopic(user, state) == STATUS_INTERACTIVE)
#define sequential_id(key) uniqueness_repository.Generate(/datum/uniqueness_generator/id_sequential, key)
#define random_id(key,min_id,max_id) uniqueness_repository.Generate(/datum/uniqueness_generator/id_random, key, min_id, max_id)
-#define ARGS_DEBUG log_debug("[__FILE__] - [__LINE__]") ; for(var/arg in args) { log_debug("\t[log_info_line(arg)]") }
-
#define WORLD_ICON_SIZE 32 //Needed for the R-UST port
#define PIXEL_MULTIPLIER WORLD_ICON_SIZE/32 //Needed for the R-UST port
diff --git a/code/_onclick/hud/ability_screen_objects.dm b/code/_onclick/hud/ability_screen_objects.dm
index 05e48d8bd3..6dda894c59 100644
--- a/code/_onclick/hud/ability_screen_objects.dm
+++ b/code/_onclick/hud/ability_screen_objects.dm
@@ -273,7 +273,7 @@
// Makes the ability be triggered. The subclasses of this are responsible for carrying it out in whatever way it needs to.
/obj/screen/ability/proc/activate()
- to_world("[src] had activate() called.")
+ to_chat(world, "[src] had activate() called.")
return
// This checks if the ability can be used.
@@ -308,7 +308,7 @@
if(object_used && verb_to_call)
call(object_used,verb_to_call)(arguments_to_use)
// call(object_used,verb_to_call)(arguments_to_use)
-// to_world(span_world("Attempted to call([object_used],[verb_to_call])([arguments_to_use])"))
+// to_chat(world, span_world("Attempted to call([object_used],[verb_to_call])([arguments_to_use])"))
// if(hascall(object_used, verb_to_call))
// call(object_used,verb_to_call)(arguments_to_use)
// else
diff --git a/code/_onclick/telekinesis.dm b/code/_onclick/telekinesis.dm
index 6ef4ee4949..7fadb38a0a 100644
--- a/code/_onclick/telekinesis.dm
+++ b/code/_onclick/telekinesis.dm
@@ -38,7 +38,7 @@
O.host = user
O.focus_object(src)
else
- warning("Strange attack_tk(): TK([user.has_telegrip()]) empty hand([!user.get_active_hand()])")
+ WARNING("Strange attack_tk(): TK([user.has_telegrip()]) empty hand([!user.get_active_hand()])")
return
diff --git a/code/controllers/autotransfer.dm b/code/controllers/autotransfer.dm
index f726f68bdc..a8e3702738 100644
--- a/code/controllers/autotransfer.dm
+++ b/code/controllers/autotransfer.dm
@@ -21,7 +21,7 @@ var/datum/controller/transfer_controller/transfer_controller
//VOREStation Edit START
if (round_duration_in_ds >= shift_last_vote - 2 MINUTES)
shift_last_vote = 1000000000000 //Setting to a stupidly high number since it'll be not used again. //CHOMPEdit
- to_world(span_world(span_notice("Warning: This upcoming round-extend vote will be your last chance to vote for shift extension. Wrap up your scenes in the next 60 minutes if the round is extended."))) //CHOMPStation Edit
+ to_chat(world, span_world(span_notice("Warning: This upcoming round-extend vote will be your last chance to vote for shift extension. Wrap up your scenes in the next 60 minutes if the round is extended."))) //CHOMPStation Edit
if (round_duration_in_ds >= shift_hard_end - 1 MINUTE)
init_shift_change(null, 1)
shift_hard_end = timerbuffer + CONFIG_GET(number/vote_autotransfer_interval) //If shuttle somehow gets recalled, let's force it to call again next time a vote would occur.
diff --git a/code/controllers/configuration/configuration.dm b/code/controllers/configuration/configuration.dm
index a2f5b2c9d1..116dbd811a 100644
--- a/code/controllers/configuration/configuration.dm
+++ b/code/controllers/configuration/configuration.dm
@@ -254,7 +254,7 @@
value = new_value
E = new_ver
else
- warning("[new_ver.type] is deprecated but gave no proper return for DeprecationUpdate()")
+ WARNING("[new_ver.type] is deprecated but gave no proper return for DeprecationUpdate()")
var/validated = E.ValidateAndSet(value)
if(!validated)
diff --git a/code/controllers/configuration/entries/general.dm b/code/controllers/configuration/entries/general.dm
index 8c3ec32dbd..4d539335c7 100644
--- a/code/controllers/configuration/entries/general.dm
+++ b/code/controllers/configuration/entries/general.dm
@@ -19,9 +19,18 @@
/// log messages sent in OOC
/datum/config_entry/flag/log_ooc
+/// log messages sent in LOOC
+/datum/config_entry/flag/log_looc
+
/// log login/logout
/datum/config_entry/flag/log_access
+/// Config entry which special logging of failed logins under suspicious circumstances.
+/datum/config_entry/flag/log_suspicious_login
+
+/// log prayers
+/datum/config_entry/flag/log_prayer
+
/// log client say
/datum/config_entry/flag/log_say
@@ -29,13 +38,12 @@
/datum/config_entry/flag/log_admin
protection = CONFIG_ENTRY_LOCKED
-/// log debug output
-/datum/config_entry/flag/log_debug
- default = TRUE
-
/// log game events
/datum/config_entry/flag/log_game
+/// log assets
+/datum/config_entry/flag/log_asset
+
/// log voting
/datum/config_entry/flag/log_vote
@@ -51,8 +59,8 @@
/// log admin chat messages
/datum/config_entry/flag/log_adminchat
-/// log warnings admins get about bomb construction and such
-/datum/config_entry/flag/log_adminwarn
+/// log EVENT chat messages
+/datum/config_entry/flag/log_eventchat
/// log pda messages
/datum/config_entry/flag/log_pda
@@ -72,9 +80,16 @@
/// logs graffiti
/datum/config_entry/flag/log_graffiti
+/// log all world.Topic() calls
+/datum/config_entry/flag/log_world_topic
+
/// logs all timers in buckets on automatic bucket reset (Useful for timer debugging)
/datum/config_entry/flag/log_timers_on_bucket_reset
+/// Log human readable versions of json log entries
+/datum/config_entry/flag/log_as_human_readable
+ default = TRUE
+
// FIXME: Unused
///datum/config_entry/string/nudge_script_path // where the nudge.py script is located
// default = "nudge.py"
@@ -194,6 +209,22 @@
config_entry_value = 15
min_val = 0
+/datum/config_entry/number/error_cooldown // The "cooldown" time for each occurrence of a unique error
+ default = 600
+ integer = FALSE
+ min_val = 0
+
+/datum/config_entry/number/error_limit // How many occurrences before the next will silence them
+ default = 50
+
+/datum/config_entry/number/error_silence_time // How long a unique error will be silenced for
+ default = 6000
+ integer = FALSE
+
+/datum/config_entry/number/error_msg_delay // How long to wait between messaging admins about occurrences of a unique error
+ default = 50
+ integer = FALSE
+
/datum/config_entry/number/fps
default = 20
integer = FALSE
@@ -850,3 +881,6 @@
/// If admins with +DEBUG can queue byond-tracy to run the next round.
/datum/config_entry/flag/allow_tracy_queue
protection = CONFIG_ENTRY_LOCKED
+
+/// log vore interactions
+/datum/config_entry/flag/log_vore
diff --git a/code/controllers/globals.dm b/code/controllers/globals.dm
index 8a5580ec40..86cda2893c 100644
--- a/code/controllers/globals.dm
+++ b/code/controllers/globals.dm
@@ -53,7 +53,7 @@ GLOBAL_REAL(GLOB, /datum/controller/global_vars)
var/list/global_procs = typesof(/datum/controller/global_vars/proc)
var/expected_len = vars.len - gvars_datum_in_built_vars.len
if(global_procs.len != expected_len)
- warning("Unable to detect all global initialization procs! Expected [expected_len] got [global_procs.len]!")
+ WARNING("Unable to detect all global initialization procs! Expected [expected_len] got [global_procs.len]!")
if(global_procs.len)
var/list/expected_global_procs = vars - gvars_datum_in_built_vars
for(var/I in global_procs)
@@ -65,6 +65,6 @@ GLOBAL_REAL(GLOB, /datum/controller/global_vars)
call(src, I)()
var/end_tick = world.time
if(end_tick - start_tick)
- warning("Global [replacetext("[I]", "InitGlobal", "")] slept during initialization!")
+ WARNING("Global [replacetext("[I]", "InitGlobal", "")] slept during initialization!")
//populate_legacy_globals()
diff --git a/code/controllers/hooks.dm b/code/controllers/hooks.dm
index 20ba87735d..8cfaa59294 100644
--- a/code/controllers/hooks.dm
+++ b/code/controllers/hooks.dm
@@ -26,14 +26,14 @@
/proc/callHook(hook, list/arguments=null)
var/hook_path = text2path("/hook/[hook]")
if(!hook_path)
- error("Invalid hook '/hook/[hook]' called.")
+ log_world("## ERROR Invalid hook '/hook/[hook]' called.")
return 0
var/requester = new hook_path
var/status = 1
for(var/P in typesof("[hook_path]/proc"))
if(!call(requester, P)(arglist(arguments)))
- error("Hook '[P]' failed or runtimed.")
+ log_world("## ERROR Hook '[P]' failed or runtimed.")
status = 0
return status
diff --git a/code/controllers/master.dm b/code/controllers/master.dm
index 8730d0c27f..12c767a8f8 100644
--- a/code/controllers/master.dm
+++ b/code/controllers/master.dm
@@ -506,11 +506,11 @@ ADMIN_VERB(cmd_controller_view_ui, R_SERVER|R_DEBUG, "Controller Overview", "Vie
// Gave invalid return value.
if(result && !(result in valid_results))
- warning("[subsystem.name] subsystem initialized, returning invalid result [result]. This is a bug.")
+ WARNING("[subsystem.name] subsystem initialized, returning invalid result [result]. This is a bug.")
// just returned ..() or didn't implement Initialize() at all
if(result == SS_INIT_NONE)
- warning("[subsystem.name] subsystem does not implement Initialize() or it returns ..(). If the former is true, the SS_NO_INIT flag should be set for this subsystem.")
+ WARNING("[subsystem.name] subsystem does not implement Initialize() or it returns ..(). If the former is true, the SS_NO_INIT flag should be set for this subsystem.")
if(result != SS_INIT_FAILURE)
// Some form of success, implicit failure, or the SS in unused.
diff --git a/code/controllers/master_controller.dm b/code/controllers/master_controller.dm
index 6f157b7bcf..6fcf3e8596 100644
--- a/code/controllers/master_controller.dm
+++ b/code/controllers/master_controller.dm
@@ -16,7 +16,7 @@ var/global/last_tick_duration = 0
/datum/controller/game_controller/New()
//There can be only one master_controller. Out with the old and in with the new.
if(master_controller != src)
- log_debug("Rebuilding Master Controller")
+ log_world("Rebuilding Master Controller")
if(istype(master_controller))
qdel(master_controller)
master_controller = src
diff --git a/code/controllers/subsystems/air.dm b/code/controllers/subsystems/air.dm
index e2f8432da2..1d5cf94623 100644
--- a/code/controllers/subsystems/air.dm
+++ b/code/controllers/subsystems/air.dm
@@ -167,7 +167,7 @@ Total Unsimulated Turfs: [world.maxx*world.maxy*world.maxz - simulated_turf_coun
for(var/turf/T in E.connecting_turfs)
edge_log += "+--- Connecting Turf [T] ([T.type]) @ [T.x], [T.y], [T.z] ([T.loc])"
- log_debug("Active Edges on ZAS Startup\n" + edge_log.Join("\n"))
+ log_mapping("Active Edges on ZAS Startup\n" + edge_log.Join("\n"))
startup_active_edge_log = edge_log.Copy()
return SS_INIT_SUCCESS
diff --git a/code/controllers/subsystems/chemistry.dm b/code/controllers/subsystems/chemistry.dm
index 6de865b9fd..158b413b5d 100644
--- a/code/controllers/subsystems/chemistry.dm
+++ b/code/controllers/subsystems/chemistry.dm
@@ -15,7 +15,6 @@ SUBSYSTEM_DEF(chemistry)
var/list/chemical_reagents = list()
/datum/controller/subsystem/chemistry/Recover()
- log_debug("[name] subsystem Recover().")
chemical_reactions = SSchemistry.chemical_reactions
chemical_reagents = SSchemistry.chemical_reagents
diff --git a/code/controllers/subsystems/dbcore.dm b/code/controllers/subsystems/dbcore.dm
index b8acc18c9b..aaafbb0282 100644
--- a/code/controllers/subsystems/dbcore.dm
+++ b/code/controllers/subsystems/dbcore.dm
@@ -84,7 +84,7 @@ SUBSYSTEM_DEF(dbcore)
var/datum/db_query/query = popleft(processing_queries)
if(world.time - query.last_activity_time > (5 MINUTES))
stack_trace("Found undeleted query, check the sql.log for the undeleted query and add a delete call to the query datum.")
- log_debug("Undeleted query: \"[query.sql]\" LA: [query.last_activity] LAT: [query.last_activity_time]")
+ log_sql("Undeleted query: \"[query.sql]\" LA: [query.last_activity] LAT: [query.last_activity_time]")
qdel(query)
if(MC_TICK_CHECK)
return
@@ -141,7 +141,7 @@ SUBSYSTEM_DEF(dbcore)
/datum/controller/subsystem/dbcore/Shutdown()
shutting_down = TRUE
- log_debug("Clearing DB queries standby:[length(queries_standby)] active: [length(queries_active)] all: [length(all_queries)]")
+ log_sql("Clearing DB queries standby:[length(queries_standby)] active: [length(queries_active)] all: [length(all_queries)]")
//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())
//Execute all waiting queries
@@ -162,7 +162,7 @@ SUBSYSTEM_DEF(dbcore)
query_round_shutdown.Execute(FALSE)
qdel(query_round_shutdown)
- log_debug("Done clearing DB queries standby:[length(queries_standby)] active: [length(queries_active)] all: [length(all_queries)]")
+ log_sql("Done clearing DB queries standby:[length(queries_standby)] active: [length(queries_active)] all: [length(all_queries)]")
if(IsConnected())
Disconnect()
//stop_db_daemon()
@@ -237,7 +237,7 @@ SUBSYSTEM_DEF(dbcore)
else
connection = null
last_error = result["data"]
- log_debug("Connect() failed | [last_error]")
+ log_sql("Connect() failed | [last_error]")
++failed_connections
/datum/controller/subsystem/dbcore/proc/CheckSchemaVersion()
@@ -245,9 +245,9 @@ SUBSYSTEM_DEF(dbcore)
if(Connect())
log_world("Database connection established.")
else
- log_debug("Your server failed to establish a connection with the database.")
+ log_sql("Your server failed to establish a connection with the database.")
else
- log_debug("Database is not enabled in configuration.")
+ log_sql("Database is not enabled in configuration.")
/datum/controller/subsystem/dbcore/proc/InitializeRound()
if(!Connect())
@@ -539,12 +539,12 @@ Ignore_errors instructes mysql to continue inserting rows if some of them have e
. = (status != DB_QUERY_BROKEN)
var/timed_out = !. && findtext(last_error, "Operation timed out")
if(!. && log_error)
- log_debug("[last_error] | Query used: [sql] | Arguments: [json_encode(arguments)]")
+ log_sql("[last_error] | Query used: [sql] | Arguments: [json_encode(arguments)]")
if(!async && timed_out)
- log_debug("Query execution started at [start_time]")
- log_debug("Query execution ended at [REALTIMEOFDAY]")
- log_debug("Slow query timeout detected.")
- log_debug("Query used: [sql]")
+ log_sql("Query execution started at [start_time]")
+ log_sql("Query execution ended at [REALTIMEOFDAY]")
+ log_sql("Slow query timeout detected.")
+ log_sql("Query used: [sql]")
slow_query_check()
/// Sleeps until execution of the query has finished.
diff --git a/code/controllers/subsystems/events.dm b/code/controllers/subsystems/events.dm
index f5b495b8a3..cc5e950913 100644
--- a/code/controllers/subsystems/events.dm
+++ b/code/controllers/subsystems/events.dm
@@ -58,7 +58,7 @@ SUBSYSTEM_DEF(events)
active_events -= E
if(!E.event_meta || !E.severity) // datum/event is used here and there for random reasons, maintaining "backwards compatibility"
- log_debug("Event of '[E.type]' with missing meta-data has completed.")
+ log_game("Event of '[E.type]' with missing meta-data has completed.")
return
finished_events += E
@@ -69,7 +69,7 @@ SUBSYSTEM_DEF(events)
if(EM.add_to_queue)
EC.available_events += EM
- log_debug("Event '[EM.name]' has completed at [stationtime2text()].")
+ log_game("Event '[EM.name]' has completed at [stationtime2text()].")
/datum/controller/subsystem/events/proc/delay_events(var/severity, var/delay)
var/datum/event_container/EC = event_containers[severity]
diff --git a/code/controllers/subsystems/events2.dm b/code/controllers/subsystems/events2.dm
index a30d2a970a..8f9f8bb1d8 100644
--- a/code/controllers/subsystems/events2.dm
+++ b/code/controllers/subsystems/events2.dm
@@ -30,10 +30,10 @@ SUBSYSTEM_DEF(event_ticker)
event_started(E)
/datum/controller/subsystem/event_ticker/proc/event_started(datum/event2/event/E)
- log_debug("Event [E.type] is now being ran.")
+ log_game("Event [E.type] is now being ran.")
active_events += E
/datum/controller/subsystem/event_ticker/proc/event_finished(datum/event2/event/E)
- log_debug("Event [E.type] has finished.")
+ log_game("Event [E.type] has finished.")
active_events -= E
finished_events += E
diff --git a/code/controllers/subsystems/game_master.dm b/code/controllers/subsystems/game_master.dm
index ae0a268741..0ea110c074 100644
--- a/code/controllers/subsystems/game_master.dm
+++ b/code/controllers/subsystems/game_master.dm
@@ -21,7 +21,7 @@ SUBSYSTEM_DEF(game_master)
var/next_event = 0 // Minimum amount of time of nothingness until the GM can pick something again.
- var/debug_messages = FALSE // If true, debug information is written to `log_debug()`.
+ var/debug_messages = FALSE // If true, debug information is written to `log_world()`.
/datum/controller/subsystem/game_master/Initialize()
var/list/subtypes = subtypesof(/datum/event2/meta)
@@ -116,7 +116,7 @@ SUBSYSTEM_DEF(game_master)
// if(hours < 1 && mins <= 20) // Don't do anything for the first twenty minutes of the round.
// if(!quiet)
-// log_debug("Game Master unable to start event: It is too early.")
+// log_game_master("Game Master unable to start event: It is too early.")
// return FALSE
if(hours >= 2 && mins >= 40) // Don't do anything in the last twenty minutes of the round, as well.
if(!quiet)
@@ -133,7 +133,7 @@ SUBSYSTEM_DEF(game_master)
/datum/controller/subsystem/game_master/proc/log_game_master(message)
if(debug_messages)
- log_debug("GAME MASTER: [message]")
+ log_world("GAME MASTER: [message]")
// This object makes the actual decisions.
diff --git a/code/controllers/subsystems/garbage.dm b/code/controllers/subsystems/garbage.dm
index d00060e43c..b1d77a3fc5 100644
--- a/code/controllers/subsystems/garbage.dm
+++ b/code/controllers/subsystems/garbage.dm
@@ -117,7 +117,7 @@ SUBSYSTEM_DEF(garbage)
if(LAZYLEN(I.extra_details))
entry["Deleted Metadata"] = I.extra_details
- log_debug("", del_log)
+ log_qdel("", del_log)
/datum/controller/subsystem/garbage/fire()
//the fact that this resets its processing each fire (rather then resume where it left off) is intentional.
diff --git a/code/controllers/subsystems/job.dm b/code/controllers/subsystems/job.dm
index 9cb94996b5..03b6fc3490 100644
--- a/code/controllers/subsystems/job.dm
+++ b/code/controllers/subsystems/job.dm
@@ -149,7 +149,7 @@ SUBSYSTEM_DEF(job)
/datum/controller/subsystem/job/proc/job_debug_message(message)
if(debug_messages)
- log_debug("JOB DEBUG: [message]")
+ log_world("JOB DEBUG: [message]")
//CHOMPadd start
/datum/controller/subsystem/job/proc/load_camp_lists()
@@ -163,11 +163,11 @@ SUBSYSTEM_DEF(job)
fdel(savepath)
var/json_to_file = json_encode(shift_keys)
if(!json_to_file)
- log_debug("Saving: [savepath] failed jsonencode")
+ log_world("Saving: [savepath] failed jsonencode")
return
//Write it out
rustg_file_write(json_to_file, savepath)
if(!fexists(savepath))
- log_debug("Saving: failed to save [savepath]")
+ log_world("Saving: failed to save [savepath]")
//CHOMPadd end
diff --git a/code/controllers/subsystems/machines.dm b/code/controllers/subsystems/machines.dm
index 991fac53f1..80ee1e4fc4 100644
--- a/code/controllers/subsystems/machines.dm
+++ b/code/controllers/subsystems/machines.dm
@@ -192,19 +192,19 @@ SUBSYSTEM_DEF(machines)
/datum/controller/subsystem/machines/Recover()
for(var/datum/D as anything in SSmachines.networks)
if(!istype(D, /datum/pipe_network))
- error("Found wrong type during SSmachinery recovery: list=SSmachines.networks, item=[D], type=[D?.type]")
+ log_world("## ERROR Found wrong type during SSmachinery recovery: list=SSmachines.networks, item=[D], type=[D?.type]")
SSmachines.networks -= D
for(var/datum/D as anything in SSmachines.processing_machines)
if(!istype(D, /obj/machinery))
- error("Found wrong type during SSmachinery recovery: list=SSmachines.machines, item=[D], type=[D?.type]")
+ log_world("## ERROR Found wrong type during SSmachinery recovery: list=SSmachines.machines, item=[D], type=[D?.type]")
SSmachines.processing_machines -= D
for(var/datum/D as anything in SSmachines.powernets)
if(!istype(D, /datum/powernet))
- error("Found wrong type during SSmachinery recovery: list=SSmachines.powernets, item=[D], type=[D?.type]")
+ log_world("## ERROR Found wrong type during SSmachinery recovery: list=SSmachines.powernets, item=[D], type=[D?.type]")
SSmachines.powernets -= D
for(var/datum/D as anything in SSmachines.powerobjs)
if(!istype(D, /obj/item))
- error("Found wrong type during SSmachinery recovery: list=SSmachines.powerobjs, item=[D], type=[D?.type]")
+ log_world("## ERROR Found wrong type during SSmachinery recovery: list=SSmachines.powerobjs, item=[D], type=[D?.type]")
SSmachines.powerobjs -= D
all_machines = SSmachines.all_machines
diff --git a/code/controllers/subsystems/mapping.dm b/code/controllers/subsystems/mapping.dm
index f49d004998..50fb5f2bc9 100644
--- a/code/controllers/subsystems/mapping.dm
+++ b/code/controllers/subsystems/mapping.dm
@@ -59,7 +59,7 @@ SUBSYSTEM_DEF(mapping)
var/turf/T = get_turf(engine_loader)
if(!isturf(T))
- to_world_log("[log_info_line(engine_loader)] not on a turf! Cannot place engine template.")
+ log_mapping("[log_info_line(engine_loader)] not on a turf! Cannot place engine template.")
return
// Choose an engine type
@@ -68,7 +68,7 @@ SUBSYSTEM_DEF(mapping)
var/chosen_name = pick(CONFIG_GET(str_list/engine_map))
chosen_type = map_templates[chosen_name]
if(!istype(chosen_type))
- error("Configured engine map [chosen_name] is not a valid engine map name!")
+ log_mapping("Configured engine map [chosen_name] is not a valid engine map name!")
if(!istype(chosen_type))
var/list/engine_types = list()
for(var/map in map_templates)
@@ -76,7 +76,7 @@ SUBSYSTEM_DEF(mapping)
if(istype(MT))
engine_types += MT
chosen_type = pick(engine_types)
- to_world_log("Chose Engine Map: [chosen_type.name]")
+ log_mapping("Chose Engine Map: [chosen_type.name]")
admin_notice(span_danger("Chose Engine Map: [chosen_type.name]"), R_DEBUG)
// Annihilate movable atoms
@@ -94,12 +94,12 @@ SUBSYSTEM_DEF(mapping)
for(var/list/maplist in deffo_load)
if(!islist(maplist))
- error("Lateload Z level [maplist] is not a list! Must be in a list!")
+ log_mapping("Lateload Z level [maplist] is not a list! Must be in a list!")
continue
for(var/mapname in maplist)
var/datum/map_template/MT = map_templates[mapname]
if(!istype(MT))
- error("Lateload Z level \"[mapname]\" is not a valid map!")
+ log_mapping("Lateload Z level \"[mapname]\" is not a valid map!")
continue
admin_notice("Lateload: [MT]", R_DEBUG)
MT.load_new_z(centered = FALSE)
@@ -112,7 +112,7 @@ SUBSYSTEM_DEF(mapping)
return
if(!islist(picklist)) //So you can have a 'chain' of z-levels that make up one away mission
- error("Randompick Z level [picklist] is not a list! Must be in a list!")
+ log_mapping("Randompick Z level [picklist] is not a list! Must be in a list!")
return
for(var/map in picklist)
@@ -122,7 +122,7 @@ SUBSYSTEM_DEF(mapping)
map = pick(map)
var/datum/map_template/MT = map_templates[map]
if(!istype(MT))
- error("Randompick Z level \"[map]\" is not a valid map!")
+ log_mapping("Randompick Z level \"[map]\" is not a valid map!")
else
admin_notice("Gateway: [MT]", R_DEBUG)
MT.load_new_z(centered = FALSE)
@@ -134,7 +134,7 @@ SUBSYSTEM_DEF(mapping)
return
if(!islist(picklist)) //So you can have a 'chain' of z-levels that make up one away mission
- error("Randompick Z level [picklist] is not a list! Must be in a list!")
+ log_mapping("Randompick Z level [picklist] is not a list! Must be in a list!")
return
for(var/map in picklist)
@@ -144,7 +144,7 @@ SUBSYSTEM_DEF(mapping)
map = pick(map)
var/datum/map_template/MT = map_templates[map]
if(!istype(MT))
- error("Randompick Z level \"[map]\" is not a valid map!")
+ log_mapping("Randompick Z level \"[map]\" is not a valid map!")
else
admin_notice("OM Adventure: [MT]", R_DEBUG)
MT.load_new_z(centered = FALSE)
@@ -156,7 +156,7 @@ SUBSYSTEM_DEF(mapping)
return
if(!islist(picklist)) //So you can have a 'chain' of z-levels that make up one away mission
- error("Randompick Z level [picklist] is not a list! Must be in a list!")
+ log_mapping("Randompick Z level [picklist] is not a list! Must be in a list!")
return
for(var/map in picklist)
@@ -166,7 +166,7 @@ SUBSYSTEM_DEF(mapping)
map = pick(map)
var/datum/map_template/MT = map_templates[map]
if(!istype(MT))
- error("Randompick Z level \"[map]\" is not a valid map!")
+ log_mapping("Randompick Z level \"[map]\" is not a valid map!")
else
admin_notice("Redgate: [MT]", R_DEBUG)
MT.load_new_z(centered = FALSE)
diff --git a/code/controllers/subsystems/media_tracks.dm b/code/controllers/subsystems/media_tracks.dm
index 3f2693bc52..28c2e5ae21 100644
--- a/code/controllers/subsystems/media_tracks.dm
+++ b/code/controllers/subsystems/media_tracks.dm
@@ -23,33 +23,33 @@ SUBSYSTEM_DEF(media_tracks)
report_progress("Loading jukebox track: [filename]")
if(!fexists(filename))
- error("File not found: [filename]")
+ log_world("## ERROR File not found: [filename]")
continue
var/list/jsonData = json_decode(file2text(filename))
if(!istype(jsonData))
- error("Failed to read tracks from [filename], json_decode failed.")
+ log_world("## ERROR Failed to read tracks from [filename], json_decode failed.")
continue
for(var/entry in jsonData)
// Critical problems that will prevent the track from working
if(!istext(entry["url"]))
- error("Jukebox entry in [filename]: bad or missing 'url'. Tracks must have a URL.")
+ log_world("## ERROR Jukebox entry in [filename]: bad or missing 'url'. Tracks must have a URL.")
continue
if(!istext(entry["title"]))
- error("Jukebox entry in [filename]: bad or missing 'title'. Tracks must have a title.")
+ log_world("## ERROR Jukebox entry in [filename]: bad or missing 'title'. Tracks must have a title.")
continue
if(!isnum(entry["duration"]))
- error("Jukebox entry in [filename]: bad or missing 'duration'. Tracks must have a duration (in deciseconds).")
+ log_world("## ERROR Jukebox entry in [filename]: bad or missing 'duration'. Tracks must have a duration (in deciseconds).")
continue
// Noncritical problems, we can keep going anyway, but warn so it can be fixed
if(!istext(entry["artist"]))
- warning("Jukebox entry in [filename], [entry["title"]]: bad or missing 'artist'. Please consider crediting the artist.")
+ WARNING("Jukebox entry in [filename], [entry["title"]]: bad or missing 'artist'. Please consider crediting the artist.")
if(!istext(entry["genre"]))
- warning("Jukebox entry in [filename], [entry["title"]]: bad or missing 'genre'. Please consider adding a genre.")
+ WARNING("Jukebox entry in [filename], [entry["title"]]: bad or missing 'genre'. Please consider adding a genre.")
var/datum/track/T = new(entry["url"], entry["title"], entry["duration"], entry["artist"], entry["genre"])
diff --git a/code/controllers/subsystems/overmap_renamer_vr.dm b/code/controllers/subsystems/overmap_renamer_vr.dm
index 4880dbbdc9..5004a24944 100644
--- a/code/controllers/subsystems/overmap_renamer_vr.dm
+++ b/code/controllers/subsystems/overmap_renamer_vr.dm
@@ -28,8 +28,8 @@ if we end up with multiple renamable lateload overmap objects.*/
V.modify_descriptors()
if(V.visitable_renamed) //could just if(D.modify_descriptors()), but having a var recording renaming is useful for debugging and stuff!
if(V.known)
- to_world_log("##Overmap Renamer: Renamed Debris Field as: [V.name]")
+ log_mapping("##Overmap Renamer: Renamed Debris Field as: [V.name]")
admin_notice(span_danger("Debris Field name chosen as [V.name]"), R_DEBUG)
else
- to_world_log("##Overmap Renamer: Renamed Debris Field as: [V.real_name]")
+ log_mapping("##Overmap Renamer: Renamed Debris Field as: [V.real_name]")
admin_notice(span_danger("Debris Field name chosen as [V.real_name]"), R_DEBUG)
diff --git a/code/controllers/subsystems/pathfinder_ch.dm b/code/controllers/subsystems/pathfinder_ch.dm
index 3c74e284ea..9bda44d372 100644
--- a/code/controllers/subsystems/pathfinder_ch.dm
+++ b/code/controllers/subsystems/pathfinder_ch.dm
@@ -63,21 +63,21 @@ SUBSYSTEM_DEF(pathfinder)
stoplag(1)
if(world.time > started + PATHFINDER_TIMEOUT)
stack_trace("pathfinder timeout; check debug logs.")
- log_debug("pathfinder timeout of instance with debug variables [instance.debug_log_string()]")
+ log_runtime("pathfinder timeout of instance with debug variables [instance.debug_log_string()]")
return
else
while(pathfinding_mutex)
stoplag(3)
if(world.time > started + PATHFINDER_TIMEOUT)
stack_trace("pathfinder timeout; check debug logs.")
- log_debug("pathfinder timeout of instance with debug variables [instance.debug_log_string()]")
+ log_runtime("pathfinder timeout of instance with debug variables [instance.debug_log_string()]")
return
--pathfinding_blocked
pathfinding_mutex = TRUE
. = instance.search()
if(world.time > started + PATHFINDER_TIMEOUT)
stack_trace("pathfinder timeout; check debug logs.")
- log_debug("pathfinder timeout of instance with debug variables [instance.debug_log_string()]")
+ log_runtime("pathfinder timeout of instance with debug variables [instance.debug_log_string()]")
pathfinding_mutex = FALSE
#undef PATHFINDER_TIMEOUT
diff --git a/code/controllers/subsystems/pois.dm b/code/controllers/subsystems/pois.dm
index 053e6abfc1..f63f19d152 100644
--- a/code/controllers/subsystems/pois.dm
+++ b/code/controllers/subsystems/pois.dm
@@ -12,7 +12,7 @@ SUBSYSTEM_DEF(points_of_interest)
/datum/controller/subsystem/points_of_interest/Initialize()
while (poi_queue.len)
load_next_poi()
- to_world_log("Initializing POIs")
+ log_mapping("Initializing POIs")
admin_notice(span_danger("Initializing POIs"), R_DEBUG)
return SS_INIT_SUCCESS
@@ -50,7 +50,7 @@ SUBSYSTEM_DEF(points_of_interest)
return
var/turf/T = get_turf(poi_to_load)
if(!isturf(T))
- to_world_log("[log_info_line(poi_to_load)] not on a turf! Cannot place poi template.")
+ log_mapping("[log_info_line(poi_to_load)] not on a turf! Cannot place poi template.")
return
// Choose a poi
diff --git a/code/controllers/subsystems/processing/bellies_vr.dm b/code/controllers/subsystems/processing/bellies_vr.dm
index ad2a3e23e8..11b49b570c 100644
--- a/code/controllers/subsystems/processing/bellies_vr.dm
+++ b/code/controllers/subsystems/processing/bellies_vr.dm
@@ -9,12 +9,12 @@ PROCESSING_SUBSYSTEM_DEF(bellies)
runlevels = RUNLEVEL_GAME|RUNLEVEL_POSTGAME
/datum/controller/subsystem/processing/bellies/Recover()
- log_debug("[name] subsystem Recover().")
+ log_runtime("[name] subsystem Recover().")
if(SSbellies.current_thing)
- log_debug("current_thing was: (\ref[SSbellies.current_thing])[SSbellies.current_thing]([SSbellies.current_thing.type]) - currentrun: [SSbellies.currentrun.len] vs total: [SSbellies.processing.len]")
+ log_runtime("current_thing was: (\ref[SSbellies.current_thing])[SSbellies.current_thing]([SSbellies.current_thing.type]) - currentrun: [SSbellies.currentrun.len] vs total: [SSbellies.processing.len]")
var/list/old_processing = SSbellies.processing.Copy()
for(var/datum/D in old_processing)
if(!isbelly(D))
- log_debug("[name] subsystem Recover() found inappropriate item in list: [D.type]")
+ log_runtime("[name] subsystem Recover() found inappropriate item in list: [D.type]")
if(CHECK_BITFIELD(D.datum_flags, DF_ISPROCESSING))
processing |= D
diff --git a/code/controllers/subsystems/processing/fastprocess.dm b/code/controllers/subsystems/processing/fastprocess.dm
index 407477f9b0..91e0de8775 100644
--- a/code/controllers/subsystems/processing/fastprocess.dm
+++ b/code/controllers/subsystems/processing/fastprocess.dm
@@ -7,9 +7,9 @@ PROCESSING_SUBSYSTEM_DEF(fastprocess)
flags = SS_NO_INIT
/datum/controller/subsystem/processing/fastprocess/Recover()
- log_debug("[name] subsystem Recover().")
+ log_runtime("[name] subsystem Recover().")
if(SSfastprocess.current_thing)
- log_debug("current_thing was: (\ref[SSfastprocess.current_thing])[SSfastprocess.current_thing]([SSfastprocess.current_thing.type]) - currentrun: [SSfastprocess.currentrun.len] vs total: [SSfastprocess.processing.len]")
+ log_runtime("current_thing was: (\ref[SSfastprocess.current_thing])[SSfastprocess.current_thing]([SSfastprocess.current_thing.type]) - currentrun: [SSfastprocess.currentrun.len] vs total: [SSfastprocess.processing.len]")
var/list/old_processing = SSfastprocess.processing.Copy()
for(var/datum/D in old_processing)
if(CHECK_BITFIELD(D.datum_flags, DF_ISPROCESSING))
diff --git a/code/controllers/subsystems/processing/obj.dm b/code/controllers/subsystems/processing/obj.dm
index 8812a59663..8f4f562e1d 100644
--- a/code/controllers/subsystems/processing/obj.dm
+++ b/code/controllers/subsystems/processing/obj.dm
@@ -5,12 +5,12 @@ PROCESSING_SUBSYSTEM_DEF(obj)
wait = 20
/datum/controller/subsystem/processing/obj/Recover()
- log_debug("[name] subsystem Recover().")
+ log_runtime("[name] subsystem Recover().")
if(SSobj.current_thing)
- log_debug("current_thing was: (\ref[SSobj.current_thing])[SSobj.current_thing]([SSobj.current_thing.type]) - currentrun: [SSobj.currentrun.len] vs total: [SSobj.processing.len]")
+ log_runtime("current_thing was: (\ref[SSobj.current_thing])[SSobj.current_thing]([SSobj.current_thing.type]) - currentrun: [SSobj.currentrun.len] vs total: [SSobj.processing.len]")
var/list/old_processing = SSobj.processing.Copy()
for(var/datum/D in old_processing)
if(!isobj(D))
- log_debug("[name] subsystem Recover() found inappropriate item in list: [D.type]")
+ log_runtime("[name] subsystem Recover() found inappropriate item in list: [D.type]")
if(CHECK_BITFIELD(D.datum_flags, DF_ISPROCESSING))
processing |= D
diff --git a/code/controllers/subsystems/processing/processing.dm b/code/controllers/subsystems/processing/processing.dm
index 42ebfba08c..fb9d6d16e6 100644
--- a/code/controllers/subsystems/processing/processing.dm
+++ b/code/controllers/subsystems/processing/processing.dm
@@ -16,9 +16,9 @@ SUBSYSTEM_DEF(processing)
var/datum/current_thing
/datum/controller/subsystem/processing/Recover()
- log_debug("[name] subsystem Recover().")
+ log_runtime("[name] subsystem Recover().")
if(SSprocessing.current_thing)
- log_debug("current_thing was: (\ref[SSprocessing.current_thing])[SSprocessing.current_thing]([SSprocessing.current_thing.type]) - currentrun: [SSprocessing.currentrun.len] vs total: [SSprocessing.processing.len]")
+ log_runtime("current_thing was: (\ref[SSprocessing.current_thing])[SSprocessing.current_thing]([SSprocessing.current_thing.type]) - currentrun: [SSprocessing.currentrun.len] vs total: [SSprocessing.processing.len]")
var/list/old_processing = SSprocessing.processing.Copy()
for(var/datum/D in old_processing)
if(CHECK_BITFIELD(D.datum_flags, DF_ISPROCESSING))
@@ -66,7 +66,6 @@ SUBSYSTEM_DEF(processing)
msg += "- Process subsystems are processed tail-first -\n"
if(!currentrun || !processing)
msg += "ERROR: A critical list [currentrun ? "processing" : "currentrun"] is gone!"
- log_game(msg)
log_world(msg)
return
msg += "Lists: current_run: [currentrun.len], processing: [processing.len]\n"
@@ -93,7 +92,6 @@ SUBSYSTEM_DEF(processing)
for(var/i in start to end)
msg += "[describeThis(processing[i])][i == position ? " << TAIL" : ""]\n"
msg += "---\n"
- log_game(msg)
log_world(msg)
/datum/proc/DebugSubsystemProcess(var/wait, var/times_fired, var/datum/controller/subsystem/processing/subsystem)
diff --git a/code/controllers/subsystems/processing/projectiles.dm b/code/controllers/subsystems/processing/projectiles.dm
index 3e5e1b2127..f901b3125a 100644
--- a/code/controllers/subsystems/processing/projectiles.dm
+++ b/code/controllers/subsystems/processing/projectiles.dm
@@ -9,9 +9,9 @@ PROCESSING_SUBSYSTEM_DEF(projectiles)
var/global_iterations_per_move = 16
/datum/controller/subsystem/processing/projectiles/Recover()
- log_debug("[name] subsystem Recover().")
+ log_runtime("[name] subsystem Recover().")
if(SSprojectiles.current_thing)
- log_debug("current_thing was: (\ref[SSprojectiles.current_thing])[SSprojectiles.current_thing]([SSprojectiles.current_thing.type]) - currentrun: [SSprojectiles.currentrun.len] vs total: [SSprojectiles.processing.len]")
+ log_runtime("current_thing was: (\ref[SSprojectiles.current_thing])[SSprojectiles.current_thing]([SSprojectiles.current_thing.type]) - currentrun: [SSprojectiles.currentrun.len] vs total: [SSprojectiles.processing.len]")
var/list/old_processing = SSprojectiles.processing.Copy()
for(var/datum/D in old_processing)
if(CHECK_BITFIELD(D.datum_flags, DF_ISPROCESSING))
diff --git a/code/controllers/subsystems/processing/turfs.dm b/code/controllers/subsystems/processing/turfs.dm
index 509ec4f17b..bb1044bc43 100644
--- a/code/controllers/subsystems/processing/turfs.dm
+++ b/code/controllers/subsystems/processing/turfs.dm
@@ -4,12 +4,12 @@ PROCESSING_SUBSYSTEM_DEF(turfs)
flags = SS_NO_INIT
/datum/controller/subsystem/processing/turfs/Recover()
- log_debug("[name] subsystem Recover().")
+ log_runtime("[name] subsystem Recover().")
if(SSturfs.current_thing)
- log_debug("current_thing was: (\ref[SSturfs.current_thing])[SSturfs.current_thing]([SSturfs.current_thing.type]) - currentrun: [SSturfs.currentrun.len] vs total: [SSturfs.processing.len]")
+ log_runtime("current_thing was: (\ref[SSturfs.current_thing])[SSturfs.current_thing]([SSturfs.current_thing.type]) - currentrun: [SSturfs.currentrun.len] vs total: [SSturfs.processing.len]")
var/list/old_processing = SSturfs.processing.Copy()
for(var/datum/D in old_processing)
if(!isturf(D))
- log_debug("[name] subsystem Recover() found inappropriate item in list: [D.type]")
+ log_runtime("[name] subsystem Recover() found inappropriate item in list: [D.type]")
if(CHECK_BITFIELD(D.datum_flags, DF_ISPROCESSING))
processing |= D
diff --git a/code/controllers/subsystems/reflect_ch.dm b/code/controllers/subsystems/reflect_ch.dm
index 0c8fcfa394..da3e4f80e3 100644
--- a/code/controllers/subsystems/reflect_ch.dm
+++ b/code/controllers/subsystems/reflect_ch.dm
@@ -14,9 +14,9 @@ SUBSYSTEM_DEF(reflector)
var/obj/structure/reflector/current_thing
/datum/controller/subsystem/reflector/Recover()
- log_debug("[name] subsystem Recover().")
+ log_runtime("[name] subsystem Recover().")
if(SSreflector.current_thing)
- log_debug("current_thing was: (\ref[SSreflector.current_thing])[SSreflector.current_thing]([SSreflector.current_thing.type]) - currentrun: [SSreflector.currentrun.len] vs total: [SSreflector.processing.len]")
+ log_runtime("current_thing was: (\ref[SSreflector.current_thing])[SSreflector.current_thing]([SSreflector.current_thing.type]) - currentrun: [SSreflector.currentrun.len] vs total: [SSreflector.processing.len]")
var/list/old_processing = SSreflector.processing.Copy()
for(var/datum/D in old_processing)
if(CHECK_BITFIELD(D.datum_flags, DF_ISPROCESSING))
diff --git a/code/controllers/subsystems/shuttles.dm b/code/controllers/subsystems/shuttles.dm
index ac8825feb4..ded9b4c462 100644
--- a/code/controllers/subsystems/shuttles.dm
+++ b/code/controllers/subsystems/shuttles.dm
@@ -58,7 +58,7 @@ SUBSYSTEM_DEF(shuttles)
var/datum/shuttle/S = working_shuttles[working_shuttles.len]
working_shuttles.len--
if(!istype(S) || QDELETED(S))
- error("Bad entry in SSshuttles.process_shuttles - [log_info_line(S)] ")
+ log_world("## ERROR Bad entry in SSshuttles.process_shuttles - [log_info_line(S)] ")
process_shuttles -= S
continue
// NOTE - In old system, /datum/shuttle/ferry was processed only if (F.process_state || F.always_process)
@@ -147,7 +147,7 @@ SUBSYSTEM_DEF(shuttles)
if(initial(shuttle.category) != shuttle_type) // Skip if its an "abstract class" datum
shuttle = new shuttle()
shuttle_areas |= shuttle.shuttle_area
- log_debug("Initialized shuttle [shuttle] ([shuttle.type])")
+ log_world("Initialized shuttle [shuttle] ([shuttle.type])")
return shuttle
// Historical note: No need to call shuttle.init_docking_controllers(), controllers register themselves
// and shuttles fetch refs in New(). Shuttles also dock() themselves in new if they want.
@@ -161,7 +161,7 @@ SUBSYSTEM_DEF(shuttles)
S.motherdock = S.current_location.landmark_tag
mothership.shuttle_area |= S.shuttle_area
else
- error("Shuttle [S] was unable to find mothership [mothership]!")
+ log_world("## ERROR Shuttle [S] was unable to find mothership [mothership]!")
// Let shuttles scan their owned areas for objects they want to configure (Called after mothership hookup)
/datum/controller/subsystem/shuttles/proc/hook_up_shuttle_objects(shuttles_list)
diff --git a/code/controllers/subsystems/sqlite.dm b/code/controllers/subsystems/sqlite.dm
index bb2da0b118..1857a7db6f 100644
--- a/code/controllers/subsystems/sqlite.dm
+++ b/code/controllers/subsystems/sqlite.dm
@@ -24,10 +24,10 @@ SUBSYSTEM_DEF(sqlite)
if(!sqlite_db)
- to_world_log("Failed to load or create a SQLite database.")
- log_debug("ERROR: SQLite database is active in config but failed to load.")
+ log_sql("Failed to load or create a SQLite database.")
+ log_sql("ERROR: SQLite database is active in config but failed to load.")
else
- to_world_log("Sqlite database connected.")
+ log_sql("Sqlite database connected.")
// Makes the tables, if they do not already exist in the sqlite file.
/datum/controller/subsystem/sqlite/proc/init_schema(database/sqlite_object)
@@ -66,7 +66,7 @@ SUBSYSTEM_DEF(sqlite)
// The desc parameter should be unique for each call, to make it easier to track down where the error occured.
/datum/controller/subsystem/sqlite/proc/sqlite_check_for_errors(var/database/query/query_used, var/desc)
if(query_used && query_used.ErrorMsg())
- log_debug("SQLite Error: [desc] : [query_used.ErrorMsg()]")
+ log_sql("SQLite Error: [desc] : [query_used.ErrorMsg()]")
return TRUE
return FALSE
@@ -171,7 +171,7 @@ SUBSYSTEM_DEF(sqlite)
// This stops mods/admins/etc from guessing the author by shoving names in an MD5 hasher until they pick the right one.
// Don't use this for things needing actual security.
/datum/controller/subsystem/sqlite/proc/get_feedback_pepper()
- var/pepper_file = file2list("config/sqlite_feedback_pepper.txt")
+ var/pepper_file = world.file2list("config/sqlite_feedback_pepper.txt")
var/pepper = null
for(var/line in pepper_file)
if(!line)
diff --git a/code/controllers/subsystems/supply.dm b/code/controllers/subsystems/supply.dm
index 1d07c787d0..d3788fbfe4 100644
--- a/code/controllers/subsystems/supply.dm
+++ b/code/controllers/subsystems/supply.dm
@@ -170,7 +170,7 @@ SUBSYSTEM_DEF(supply)
A.req_access = L.Copy()
LAZYCLEARLIST(A.req_one_access)
else
- log_debug(span_danger("Supply pack with invalid access restriction [SP.access] encountered!"))
+ log_runtime(span_danger("Supply pack with invalid access restriction [SP.access] encountered!"))
//supply manifest generation begin
var/obj/item/paper/manifest/slip
diff --git a/code/controllers/subsystems/ticker.dm b/code/controllers/subsystems/ticker.dm
index d25a8aa500..5f94f93234 100644
--- a/code/controllers/subsystems/ticker.dm
+++ b/code/controllers/subsystems/ticker.dm
@@ -176,7 +176,7 @@ SUBSYSTEM_DEF(ticker)
end_game_state = END_GAME_MODE_FINISHED // Only do this cleanup once!
mode.cleanup()
//call a transfer shuttle vote
- to_world(span_boldannounce("The round has ended!"))
+ to_chat(world, span_boldannounce("The round has ended!"))
SSvote.start_vote(new /datum/vote/crew_transfer)
// FIXME: IMPROVE THIS LATER!
@@ -184,7 +184,7 @@ SUBSYSTEM_DEF(ticker)
post_game_tick()
if (world.time - last_restart_notify >= 1 MINUTE && !delay_end)
- to_world(span_boldannounce("Restarting in [round(restart_timeleft/600, 1)] minute\s."))
+ to_chat(world, span_boldannounce("Restarting in [round(restart_timeleft/600, 1)] minute\s."))
last_restart_notify = world.time
/datum/controller/subsystem/ticker/proc/setup()
@@ -276,7 +276,7 @@ SUBSYSTEM_DEF(ticker)
var/list/runnable_modes = config.get_runnable_modes()
if((GLOB.master_mode == "random") || (GLOB.master_mode == "secret"))
if(!runnable_modes.len)
- to_world(span_filter_system(span_bold("Unable to choose playable game mode.") + " Reverting to pregame lobby."))
+ to_chat(world, span_filter_system(span_bold("Unable to choose playable game mode.") + " Reverting to pregame lobby."))
return 0
if(GLOB.secret_force_mode != "secret")
src.mode = config.pick_mode(GLOB.secret_force_mode)
@@ -289,7 +289,7 @@ SUBSYSTEM_DEF(ticker)
src.mode = config.pick_mode(GLOB.master_mode)
if(!src.mode)
- to_world(span_boldannounce("Serious error in mode setup! Reverting to pregame lobby.")) //Uses setup instead of set up due to computational context.
+ to_chat(world, span_boldannounce("Serious error in mode setup! Reverting to pregame lobby.")) //Uses setup instead of set up due to computational context.
return 0
job_master.ResetOccupations()
@@ -298,21 +298,21 @@ SUBSYSTEM_DEF(ticker)
job_master.DivideOccupations() // Apparently important for new antagonist system to register specific job antags properly.
if(!src.mode.can_start())
- to_world(span_filter_system(span_bold("Unable to start [mode.name].") + " Not enough players readied, [CONFIG_GET(keyed_list/player_requirements)[mode.config_tag]] players needed. Reverting to pregame lobby."))
+ to_chat(world, span_filter_system(span_bold("Unable to start [mode.name].") + " Not enough players readied, [CONFIG_GET(keyed_list/player_requirements)[mode.config_tag]] players needed. Reverting to pregame lobby."))
mode.fail_setup()
mode = null
job_master.ResetOccupations()
return 0
if(hide_mode)
- to_world(span_world(span_notice("The current game mode is - Secret!")))
+ to_chat(world, span_world(span_notice("The current game mode is - Secret!")))
if(runnable_modes.len)
var/list/tmpmodes = list()
for (var/datum/game_mode/M in runnable_modes)
tmpmodes+=M.name
tmpmodes = sortList(tmpmodes)
if(tmpmodes.len)
- to_world(span_filter_system(span_bold("Possibilities:") + " [english_list(tmpmodes, and_text= "; ", comma_text = "; ")]"))
+ to_chat(world, span_filter_system(span_bold("Possibilities:") + " [english_list(tmpmodes, and_text= "; ", comma_text = "; ")]"))
else
src.mode.announce()
return 1
@@ -327,7 +327,7 @@ SUBSYSTEM_DEF(ticker)
feedback_set_details("end_proper", "nuke")
restart_timeleft = 1 MINUTE // No point waiting five minutes if everyone's dead.
if(!delay_end)
- to_world(span_boldannounce("Rebooting due to destruction of [station_name()] in [round(restart_timeleft/600)] minute\s."))
+ to_chat(world, span_boldannounce("Rebooting due to destruction of [station_name()] in [round(restart_timeleft/600)] minute\s."))
last_restart_notify = world.time
else
feedback_set_details("end_proper", "proper completion")
diff --git a/code/controllers/subsystems/time_track.dm b/code/controllers/subsystems/time_track.dm
index 239e99c0b6..eed18d3e27 100644
--- a/code/controllers/subsystems/time_track.dm
+++ b/code/controllers/subsystems/time_track.dm
@@ -1,7 +1,6 @@
SUBSYSTEM_DEF(time_track)
name = "Time Tracking"
- wait = 600
- flags = SS_NO_INIT|SS_NO_TICK_CHECK
+ wait = 100
runlevels = RUNLEVEL_LOBBY | RUNLEVELS_DEFAULT
var/time_dilation_current = 0
@@ -15,6 +14,70 @@ SUBSYSTEM_DEF(time_track)
var/last_tick_realtime = 0
var/last_tick_byond_time = 0
var/last_tick_tickcount = 0
+ var/list/sendmaps_names_map = list(
+ "SendMaps" = "send_maps",
+ "SendMaps: Initial housekeeping" = "initial_house",
+ "SendMaps: Cleanup" = "cleanup",
+ "SendMaps: Client loop" = "client_loop",
+ "SendMaps: Per client" = "per_client",
+ "SendMaps: Per client: Deleted images" = "deleted_images",
+ "SendMaps: Per client: HUD update" = "hud_update",
+ "SendMaps: Per client: Statpanel update" = "statpanel_update",
+ "SendMaps: Per client: Map data" = "map_data",
+ "SendMaps: Per client: Map data: Check eye position" = "check_eye_pos",
+ "SendMaps: Per client: Map data: Update chunks" = "update_chunks",
+ "SendMaps: Per client: Map data: Send turfmap updates" = "turfmap_updates",
+ "SendMaps: Per client: Map data: Send changed turfs" = "changed_turfs",
+ "SendMaps: Per client: Map data: Send turf chunk info" = "turf_chunk_info",
+ "SendMaps: Per client: Map data: Send obj changes" = "obj_changes",
+ "SendMaps: Per client: Map data: Send mob changes" = "mob_changes",
+ "SendMaps: Per client: Map data: Send notable turf visual contents" = "send_turf_vis_conts",
+ "SendMaps: Per client: Map data: Send pending animations" = "pending_animations",
+ "SendMaps: Per client: Map data: Look for movable changes" = "look_for_movable_changes",
+ "SendMaps: Per client: Map data: Look for movable changes: Check notable turf visual contents" = "check_turf_vis_conts",
+ "SendMaps: Per client: Map data: Look for movable changes: Check HUD/image visual contents" = "check_hud/image_vis_contents",
+ "SendMaps: Per client: Map data: Look for movable changes: Loop through turfs in range" = "turfs_in_range",
+ "SendMaps: Per client: Map data: Look for movable changes: Movables examined" = "movables_examined",
+ )
+
+/datum/controller/subsystem/time_track/Initialize()
+ //GLOB.perf_log = "[GLOB.log_directory]/perf-[GLOB.round_id ? GLOB.round_id : "NULL"]-[SSmapping.current_map.map_name].csv"
+ GLOB.perf_log = "[GLOB.log_directory]/perf-[GLOB.round_id ? GLOB.round_id : "NULL"]-[using_map.name].csv"
+ world.Profile(PROFILE_RESTART, type = "sendmaps")
+ //Need to do the sendmaps stuff in its own file, since it works different then everything else
+ var/list/sendmaps_headers = list()
+ for(var/proper_name in sendmaps_names_map)
+ sendmaps_headers += sendmaps_names_map[proper_name]
+ sendmaps_headers += "[sendmaps_names_map[proper_name]]_count"
+ log_perf(
+ list(
+ "time",
+ "players",
+ "tidi",
+ "tidi_fastavg",
+ "tidi_avg",
+ "tidi_slowavg",
+ "maptick",
+ "num_timers",
+ "air_turf_cost",
+ "air_eg_cost",
+ "air_highpressure_cost",
+ "air_hotspots_cost",
+ "air_superconductivity_cost",
+ "air_pipenets_cost",
+ "air_rebuilds_cost",
+ "air_turf_count",
+ "air_eg_count",
+ "air_hotspot_count",
+ "air_network_count",
+ "air_delta_count",
+ "air_superconductive_count",
+ "all_queries",
+ "queries_active",
+ "queries_standby"
+ ) + sendmaps_headers
+ )
+ return SS_INIT_SUCCESS
/datum/controller/subsystem/time_track/fire()
@@ -30,11 +93,64 @@ SUBSYSTEM_DEF(time_track)
time_dilation_avg_fast = MC_AVERAGE_FAST(time_dilation_avg_fast, time_dilation_current)
time_dilation_avg = MC_AVERAGE(time_dilation_avg, time_dilation_avg_fast)
time_dilation_avg_slow = MC_AVERAGE_SLOW(time_dilation_avg_slow, time_dilation_avg)
-
- log_game("TIDI: [time_dilation_current];[time_dilation_avg_fast];[time_dilation_avg];[time_dilation_avg_slow]")
+ //GLOB.glide_size_multiplier = (current_byondtime - last_tick_byond_time) / (current_realtime - last_tick_realtime)
else
first_run = FALSE
- log_debug("TiDi Starting Log")
last_tick_realtime = current_realtime
last_tick_byond_time = current_byondtime
last_tick_tickcount = current_tickcount
+
+ var/sendmaps_json = world.Profile(PROFILE_REFRESH, type = "sendmaps", format="json")
+ var/list/send_maps_data = null
+ try
+ send_maps_data = json_decode(sendmaps_json)
+ catch
+ text2file(sendmaps_json,"bad_sendmaps.json")
+ can_fire = FALSE
+ return
+ var/send_maps_sort = send_maps_data.Copy() //Doing it like this guarantees us a properly sorted list
+
+ for(var/list/packet in send_maps_data)
+ send_maps_sort[packet["name"]] = packet
+
+ var/list/send_maps_values = list()
+ for(var/entry_name in sendmaps_names_map)
+ var/list/packet = send_maps_sort[entry_name]
+ if(!packet) //If the entry does not have a value for us, just put in 0 for both
+ send_maps_values += 0
+ send_maps_values += 0
+ continue
+ send_maps_values += packet["value"]
+ send_maps_values += packet["calls"]
+
+ //SSblackbox.record_feedback("associative", "time_dilation_current", 1, list("[ISOtime()]" = list("current" = "[time_dilation_current]", "avg_fast" = "[time_dilation_avg_fast]", "avg" = "[time_dilation_avg]", "avg_slow" = "[time_dilation_avg_slow]")))
+ log_perf(
+ list(
+ world.time,
+ length(GLOB.clients),
+ time_dilation_current,
+ time_dilation_avg_fast,
+ time_dilation_avg,
+ time_dilation_avg_slow,
+ MAPTICK_LAST_INTERNAL_TICK_USAGE,
+ length(SStimer.timer_id_dict),
+ SSair.cost_turfs,
+ //SSair.cost_groups,
+ //SSair.cost_highpressure,
+ SSair.cost_hotspots,
+ //SSair.cost_superconductivity,
+ //SSair.cost_pipenets,
+ //SSair.cost_rebuilds,
+ //length(SSair.active_turfs),
+ //length(SSair.excited_groups),
+ //length(SSair.hotspots),
+ //length(SSair.networks),
+ //length(SSair.high_pressure_delta),
+ //length(SSair.active_super_conductivity),
+ SSdbcore.all_queries_num,
+ SSdbcore.queries_active_num,
+ SSdbcore.queries_standby_num
+ ) + send_maps_values
+ )
+
+ SSdbcore.reset_tracking()
diff --git a/code/controllers/subsystems/transcore_vr.dm b/code/controllers/subsystems/transcore_vr.dm
index 1b52b1fbb8..f218669b0f 100644
--- a/code/controllers/subsystems/transcore_vr.dm
+++ b/code/controllers/subsystems/transcore_vr.dm
@@ -35,7 +35,7 @@ SUBSYSTEM_DEF(transcore)
for(var/t in subtypesof(/datum/transcore_db))
var/datum/transcore_db/db = new t()
if(!db.key)
- warning("Instantiated transcore DB without a key: [t]")
+ WARNING("Instantiated transcore DB without a key: [t]")
continue
databases[db.key] = db
return SS_INIT_SUCCESS
@@ -105,7 +105,7 @@ SUBSYSTEM_DEF(transcore)
//Invalid record
if(!curr_MR)
- log_debug("Tried to process [name] in transcore w/o a record!")
+ log_runtime("Tried to process [name] in transcore w/o a record!")
db.backed_up -= curr_MR.mindname
continue
@@ -147,7 +147,7 @@ SUBSYSTEM_DEF(transcore)
/datum/controller/subsystem/transcore/Recover()
for(var/key in SStranscore.databases)
if(!SStranscore.databases[key])
- warning("SStranscore recovery found missing database value for key: [key]")
+ WARNING("SStranscore recovery found missing database value for key: [key]")
continue
if(key == "default")
default_db = SStranscore.databases[key]
@@ -156,10 +156,10 @@ SUBSYSTEM_DEF(transcore)
/datum/controller/subsystem/transcore/proc/leave_round(var/mob/M)
if(!istype(M))
- warning("Non-mob asked to be removed from transcore: [M] [M?.type]")
+ WARNING("Non-mob asked to be removed from transcore: [M] [M?.type]")
return
if(!M.mind)
- warning("No mind mob asked to be removed from transcore: [M] [M?.type]")
+ WARNING("No mind mob asked to be removed from transcore: [M] [M?.type]")
return
for(var/key in databases)
@@ -175,7 +175,7 @@ SUBSYSTEM_DEF(transcore)
if(isnull(key))
return default_db
if(!databases[key])
- warning("Tried to find invalid transcore database: [key]")
+ WARNING("Tried to find invalid transcore database: [key]")
return default_db
return databases[key]
@@ -271,7 +271,6 @@ SUBSYSTEM_DEF(transcore)
ASSERT(MR)
backed_up[MR.mindname] = MR
backed_up = sortAssoc(backed_up)
- log_debug("Added [MR.mindname] to transcore DB.")
// Remove a mind_record from the backup-checking list. Keeps track of it in has_left // Why do we do that? ~Leshana
/datum/transcore_db/proc/stop_backup(var/datum/transhuman/mind_record/MR)
@@ -279,7 +278,6 @@ SUBSYSTEM_DEF(transcore)
has_left[MR.mindname] = MR
backed_up.Remove("[MR.mindname]")
MR.cryo_at = world.time
- log_debug("Put [MR.mindname] in transcore suspended DB.")
// Called from body_record to add itself to the transcore.
/datum/transcore_db/proc/add_body(var/datum/transhuman/body_record/BR)
@@ -288,13 +286,11 @@ SUBSYSTEM_DEF(transcore)
qdel(body_scans[BR.mydna.name])
body_scans[BR.mydna.name] = BR
body_scans = sortAssoc(body_scans)
- log_debug("Added [BR.mydna.name] to transcore body DB.")
// Remove a body record from the database (Usually done when someone cryos) // Why? ~Leshana
/datum/transcore_db/proc/remove_body(var/datum/transhuman/body_record/BR)
ASSERT(BR)
body_scans.Remove("[BR.mydna.name]")
- log_debug("Removed [BR.mydna.name] from transcore body DB.")
// Moves all mind records from the databaes into the disk and shuts down all backup canary processing.
/datum/transcore_db/proc/core_dump(var/obj/item/disk/transcore/disk)
diff --git a/code/controllers/subsystems/vote.dm b/code/controllers/subsystems/vote.dm
index 02cad13531..e06984b3f7 100644
--- a/code/controllers/subsystems/vote.dm
+++ b/code/controllers/subsystems/vote.dm
@@ -46,16 +46,16 @@ SUBSYSTEM_DEF(vote)
break
if(!players_are_in_round)
- log_debug("The crew transfer shuttle would have been called at vote time due to no players being present.") //YW Edit
-// init_shift_change(null, 1) //YW Edit
+ log_game("The crew transfer shuttle was automatically called at vote time due to no players being present.")
+ init_shift_change(null, 1)
return
initiate_vote(VOTE_CREW_TRANSFER, "the server", 1)
- log_debug("The server has called a crew transfer vote.")
+ log_game("The server has called a crew transfer vote.")
/datum/controller/subsystem/vote/proc/autogamemode()
initiate_vote(VOTE_GAMEMODE, "the server", 1)
- log_debug("The server has called a gamemode vote.")
+ log_game("The server has called a gamemode vote.")
/datum/controller/subsystem/vote/proc/reset()
initiator = null
diff --git a/code/controllers/subsystems/webhooks.dm b/code/controllers/subsystems/webhooks.dm
index 17a12f6f77..9b9d53bbe3 100644
--- a/code/controllers/subsystems/webhooks.dm
+++ b/code/controllers/subsystems/webhooks.dm
@@ -13,7 +13,7 @@ SUBSYSTEM_DEF(webhooks)
/datum/controller/subsystem/webhooks/proc/load_webhooks()
if(!fexists(HTTP_POST_DLL_LOCATION))
- to_world_log("Unable to locate HTTP POST lib at [HTTP_POST_DLL_LOCATION], webhooks will not function on this run.")
+ log_world("Unable to locate HTTP POST lib at [HTTP_POST_DLL_LOCATION], webhooks will not function on this run.")
return
var/list/all_webhooks_by_id = list()
@@ -32,7 +32,7 @@ SUBSYSTEM_DEF(webhooks)
var/list/wmention = webhook_data["mentions"]
if(wmention && !islist(wmention))
wmention = list(wmention)
- to_world_log("Setting up webhook [wid].")
+ log_world("Setting up webhook [wid].")
if(wid && wurl && all_webhooks_by_id[wid])
var/decl/webhook/webhook = all_webhooks_by_id[wid]
webhook.urls = islist(wurl) ? wurl : list(wurl)
@@ -44,19 +44,19 @@ SUBSYSTEM_DEF(webhooks)
if(wmention)
webhook.mentions = wmention?.Copy()
webhook_decls[wid] = webhook
- to_world_log("Webhook [wid] ready.")
+ log_world("Webhook [wid] ready.")
else
- to_world_log("Failed to set up webhook [wid].")
+ log_world("Failed to set up webhook [wid].")
/datum/controller/subsystem/webhooks/proc/send(var/wid, var/wdata)
var/decl/webhook/webhook = webhook_decls[wid]
if(webhook)
if(webhook.send(wdata))
- to_world_log("Sent webhook [webhook.id].")
- log_debug("Webhook sent: [webhook.id].")
+ log_world("Sent webhook [webhook.id].")
+ // to_chat(world, "Webhook sent: [webhook.id].")
else
- to_world_log("Failed to send webhook [webhook.id].")
- log_debug("Webhook failed to send: [webhook.id].")
+ log_world("Failed to send webhook [webhook.id].")
+ // to_chat(world, "Webhook failed to send: [webhook.id].")
/client/proc/reload_webhooks()
set name = "Reload Webhooks"
@@ -69,7 +69,7 @@ SUBSYSTEM_DEF(webhooks)
to_chat(usr, span_warning("Let the webhook subsystem initialize before trying to reload it."))
return
- to_world_log("[usr.key] has reloaded webhooks.")
+ log_world("[usr.key] has reloaded webhooks.")
log_and_message_admins("has reloaded webhooks.")
SSwebhooks.load_webhooks()
@@ -88,7 +88,7 @@ SUBSYSTEM_DEF(webhooks)
if(choice && SSwebhooks.webhook_decls[choice])
var/decl/webhook/webhook = SSwebhooks.webhook_decls[choice]
log_and_message_admins("has pinged webhook [choice].", usr)
- to_world_log("[usr.key] has pinged webhook [choice].")
+ log_world("[usr.key] has pinged webhook [choice].")
webhook.send()
/hook/roundstart/proc/run_webhook()
diff --git a/code/datums/api.dm b/code/datums/api.dm
index fd3aea4fa9..98f0fbe27b 100644
--- a/code/datums/api.dm
+++ b/code/datums/api.dm
@@ -47,13 +47,13 @@ var/list/topic_commands_names = list()
var/list/param = params[key]
if(queryparams[key] == null)
if(param["req"] == 0)
- log_debug("API: The following parameter is OPTIONAL and missing: [param["name"]] - [param["desc"]]")
+ log_world("API: The following parameter is OPTIONAL and missing: [param["name"]] - [param["desc"]]")
else
- log_debug("API: The following parameter is REQUIRED but missing: [param["name"]] - [param["desc"]]")
+ log_world("API: The following parameter is REQUIRED but missing: [param["name"]] - [param["desc"]]")
errorcount ++
missing_params += param["name"]
if(errorcount)
- log_debug("API: Request aborted. Required parameters missing")
+ log_world("API: Request aborted. Required parameters missing")
statuscode = 400
response = "Required params missing"
data = missing_params
diff --git a/code/datums/autolathe/autolathe.dm b/code/datums/autolathe/autolathe.dm
index 6684c9404d..d24e49f291 100644
--- a/code/datums/autolathe/autolathe.dm
+++ b/code/datums/autolathe/autolathe.dm
@@ -5,7 +5,7 @@
I = new path()
if(!isitem(I)) // Something has gone horribly wrong, or right.
- log_debug("[name] created an Autolathe design without an assigned path or illegal item. Item = [I]")
+ log_runtime("[name] created an Autolathe design without an assigned path or illegal item. Item = [I]")
return
if(I.matter && !resources)
diff --git a/code/datums/components/antags/changeling/changeling.dm b/code/datums/components/antags/changeling/changeling.dm
index 8ade0ecd92..1fd9b870bf 100644
--- a/code/datums/components/antags/changeling/changeling.dm
+++ b/code/datums/components/antags/changeling/changeling.dm
@@ -228,7 +228,7 @@ var/list/datum/power/changeling/powerinstances = list()
var/datum/component/antag/changeling/comp = is_changeling(src)
if(!comp)
- to_world_log("[src] used a changeling verb but is not a changeling.")
+ log_world("[src] used a changeling verb but is not a changeling.")
return
if(src.stat > max_stat)
diff --git a/code/datums/components/recursive_move.dm b/code/datums/components/recursive_move.dm
index a3e1b70d44..e76a0cdc4f 100644
--- a/code/datums/components/recursive_move.dm
+++ b/code/datums/components/recursive_move.dm
@@ -25,11 +25,11 @@
var/recursion = 0 // safety check - max iterations
while(istype(cur_parent) && (recursion < 64))
if(cur_parent == cur_parent.loc) //safety check incase a thing is somehow inside itself, cancel
- log_debug("RECURSIVE_MOVE: Parent is inside itself. ([holder]) ([holder.type])")
+ log_runtime("RECURSIVE_MOVE: Parent is inside itself. ([holder]) ([holder.type])")
reset_parents()
break
if(cur_parent in parents) //safety check incase of circular contents. (A inside B, B inside C, C inside A), cancel
- log_debug("RECURSIVE_MOVE: Parent is inside a circular inventory. ([holder]) ([holder.type])")
+ log_runtime("RECURSIVE_MOVE: Parent is inside a circular inventory. ([holder]) ([holder.type])")
reset_parents()
break
recursion++
@@ -40,7 +40,7 @@
cur_parent = cur_parent.loc
if(recursion >= 64) // If we escaped due to iteration limit, cancel
- log_debug("RECURSIVE_MOVE: Parent hit recursion limit. ([holder]) ([holder.type])")
+ log_runtime("RECURSIVE_MOVE: Parent hit recursion limit. ([holder]) ([holder.type])")
reset_parents()
parents.Cut()
@@ -109,15 +109,15 @@
parents.Cut()
//the banana peel of testing stays
-/obj/item/bananapeel/testing
+/obj/item/bananapeel/test
name = "banana peel of testing"
desc = "spams world log with debugging information"
-/obj/item/bananapeel/testing/proc/shmove(var/atom/source, var/atom/old_loc, var/atom/new_loc)
+/obj/item/bananapeel/test/proc/shmove(var/atom/source, var/atom/old_loc, var/atom/new_loc)
SIGNAL_HANDLER
world.log << "the [source] moved from [old_loc]([old_loc.x],[old_loc.y],[old_loc.z]) to [new_loc]([new_loc.x],[new_loc.y],[new_loc.z])"
-/obj/item/bananapeel/testing/Initialize(mapload)
+/obj/item/bananapeel/test/Initialize(mapload)
. = ..()
AddComponent(/datum/component/recursive_move)
RegisterSignal(src, COMSIG_OBSERVER_MOVED, PROC_REF(shmove))
diff --git a/code/datums/components/species/shadekin/powers/phase_shift.dm b/code/datums/components/species/shadekin/powers/phase_shift.dm
index f7f2966818..8c96379bd0 100644
--- a/code/datums/components/species/shadekin/powers/phase_shift.dm
+++ b/code/datums/components/species/shadekin/powers/phase_shift.dm
@@ -76,7 +76,7 @@
ability_cost = ability_cost + ( 15 * watcher )
/*
if(!(SK.in_phase))
- log_debug("[src] attempted to shift with [watcher] visible Carbons with a cost of [ability_cost] in a darkness level of [darkness]")
+ to_chat(world, "[src] attempted to shift with [watcher] visible Carbons with a cost of [ability_cost] in a darkness level of [darkness]")
*/
if(SK.doing_phase)
diff --git a/code/datums/datacore.dm b/code/datums/datacore.dm
index a66d8e175a..6d11727d79 100644
--- a/code/datums/datacore.dm
+++ b/code/datums/datacore.dm
@@ -439,7 +439,7 @@ GLOBAL_LIST_EMPTY(PDA_Manifest)
return
/proc/generate_record_id()
- return add_zero(num2hex(rand(1, 65535)), 4) //no point generating higher numbers because of the limitations of num2hex
+ return add_zero(num2hex(rand(1, 65535), 5), 4) //no point generating higher numbers because of the limitations of num2hex
/datum/datacore/proc/CreateGeneralRecord(var/mob/living/carbon/human/H, var/id, var/hidden)
ResetPDAManifest()
@@ -454,7 +454,7 @@ GLOBAL_LIST_EMPTY(PDA_Manifest)
side = icon('html/images/no_image32.png')
if(!id)
- id = text("[]", add_zero(num2hex(rand(1, 65536)), 4))
+ id = text("[]", add_zero(num2hex(rand(1, 65536), 5), 4))
var/datum/data/record/G = new /datum/data/record()
G.name = "Employee Record #[id]"
G.fields["name"] = "New Record"
diff --git a/code/datums/datum.dm b/code/datums/datum.dm
index 334502de2d..8a2f0d7b72 100644
--- a/code/datums/datum.dm
+++ b/code/datums/datum.dm
@@ -168,6 +168,16 @@
for(var/target in _signal_procs)
UnregisterSignal(target, _signal_procs[target])
+/// Return a list of data which can be used to investigate the datum, also ensure that you set the semver in the options list
+/datum/proc/serialize_list(list/options, list/semvers)
+ SHOULD_CALL_PARENT(TRUE)
+
+ . = list()
+ .["tag"] = tag
+
+ SET_SERIALIZATION_SEMVER(semvers, "1.0.0")
+ return .
+
/**
* Callback called by a timer to end an associative-list-indexed cooldown.
*
diff --git a/code/datums/elements/turf_transparency.dm b/code/datums/elements/turf_transparency.dm
index 8b2ac8f918..bb105080c3 100644
--- a/code/datums/elements/turf_transparency.dm
+++ b/code/datums/elements/turf_transparency.dm
@@ -73,7 +73,7 @@
if(!ispath(path))
path = text2path(path)
if(!ispath(path))
- warning("Z-level [our_turf] has invalid baseturf '[get_base_turf_by_area(our_turf)]' in area '[get_area(our_turf)]'")
+ WARNING("Z-level [our_turf] has invalid baseturf '[get_base_turf_by_area(our_turf)]' in area '[get_area(our_turf)]'")
path = /turf/space
var/do_plane = ispath(path, /turf/space) ? SPACE_PLANE : null
diff --git a/code/datums/helper_datums/getrev.dm b/code/datums/helper_datums/getrev.dm
index 1ecd7da806..51da2c6e56 100644
--- a/code/datums/helper_datums/getrev.dm
+++ b/code/datums/helper_datums/getrev.dm
@@ -23,7 +23,7 @@
/datum/getrev/proc/get_log_message()
var/list/msg = list()
- msg += "Running /tg/ revision: [date]"
+ msg += "Running VOREStation revision: [date]"
if(originmastercommit)
msg += "origin/master: [originmastercommit]"
diff --git a/code/datums/mind.dm b/code/datums/mind.dm
index 4b7939478d..072de4d747 100644
--- a/code/datums/mind.dm
+++ b/code/datums/mind.dm
@@ -76,7 +76,7 @@
/datum/mind/proc/transfer_to(mob/living/new_character, force = FALSE)
if(!istype(new_character))
- to_world_log("## DEBUG: transfer_to(): Some idiot has tried to transfer_to() a non mob/living mob. Please inform Carn")
+ log_world("## DEBUG: transfer_to(): Some idiot has tried to transfer_to() a non mob/living mob. Please inform Carn")
var/datum/component/antag/changeling/comp
if(current)
comp = is_changeling(current) //remove ourself from our old body's mind variable
@@ -512,7 +512,7 @@
if(SSticker)
SSticker.minds += mind
else
- to_world_log("## DEBUG: mind_initialize(): No ticker ready yet! Please inform Carn")
+ log_world("## DEBUG: mind_initialize(): No ticker ready yet! Please inform Carn")
if(!mind.name) mind.name = real_name
mind.current = src
if(player_is_antag(mind))
diff --git a/code/datums/repositories/unique.dm b/code/datums/repositories/unique.dm
index a53111cb24..bd7b58cb8b 100644
--- a/code/datums/repositories/unique.dm
+++ b/code/datums/repositories/unique.dm
@@ -51,7 +51,7 @@ var/repository/unique/uniqueness_repository = new()
ids_by_key[key] = ids
if(ids.len >= (max - min) + 1)
- error("Random ID limit reached for key [key].")
+ log_world("## ERROR Random ID limit reached for key [key].")
ids.Cut()
if(ids.len >= 0.6 * ((max-min) + 1)) // if more than 60% of possible ids used
diff --git a/code/defines/procs/announce.dm b/code/defines/procs/announce.dm
index 9974955b8d..9bcc37b213 100644
--- a/code/defines/procs/announce.dm
+++ b/code/defines/procs/announce.dm
@@ -62,14 +62,14 @@
// You'll need to update these to_world usages if you want to make these z-level specific ~Aro
/datum/announcement/minor/Message(message as text, message_title as text)
- to_world(span_bold("[message]"))
+ to_chat(world, span_bold("[message]"))
/datum/announcement/priority/Message(message as text, message_title as text)
- to_world("