diff --git a/code/__DEFINES/_profile.dm b/code/__DEFINES/_profile.dm
new file mode 100644
index 00000000000..5fc84789014
--- /dev/null
+++ b/code/__DEFINES/_profile.dm
@@ -0,0 +1,29 @@
+#define LINE_PROFILE_START ;PROFILE_STORE = list();PROFILE_SET;
+#define LINE_PROFILE_STOP ;PROFILE_STORE = null;
+
+#define PROFILE_SET ;PROFILE_TIME = TICK_USAGE_REAL; PROFILE_LINE = __LINE__; PROFILE_FILE = __FILE__; PROFILE_SLEEPCHECK = world.time;
+
+#define PROFILE_TICK ;\
+ if (PROFILE_STORE) {\
+ var/PROFILE_TICK_USAGE_REAL = TICK_USAGE_REAL;\
+ if (PROFILE_SLEEPCHECK == world.time) {\
+ var/PROFILE_STRING = "[PROFILE_FILE]:[PROFILE_LINE] - [__FILE__]:[__LINE__]";\
+ var/list/PROFILE_ITEM = PROFILE_STORE[PROFILE_STRING];\
+ if (!PROFILE_ITEM) {\
+ PROFILE_ITEM = new(PROFILE_ITEM_LEN);\
+ PROFILE_STORE[PROFILE_STRING] = PROFILE_ITEM;\
+ PROFILE_ITEM[PROFILE_ITEM_TIME] = 0;\
+ PROFILE_ITEM[PROFILE_ITEM_COUNT] = 0;\
+ };\
+ PROFILE_ITEM[PROFILE_ITEM_TIME] += TICK_DELTA_TO_MS(PROFILE_TICK_USAGE_REAL-PROFILE_TIME);\
+ var/PROFILE_INCR_AMOUNT = min(1, 2**round(PROFILE_ITEM[PROFILE_ITEM_COUNT]/SHORT_REAL_LIMIT));\
+ if (prob(100/PROFILE_INCR_AMOUNT)) {\
+ PROFILE_ITEM[PROFILE_ITEM_COUNT] += PROFILE_INCR_AMOUNT;\
+ };\
+ };\
+ PROFILE_SET;\
+ };
+
+#define PROFILE_ITEM_LEN 2
+#define PROFILE_ITEM_TIME 1
+#define PROFILE_ITEM_COUNT 2
diff --git a/code/__HELPERS/sorts/comparators.dm b/code/__HELPERS/sorts/comparators.dm
index 36484e7e2d5..9741b55b9ff 100644
--- a/code/__HELPERS/sorts/comparators.dm
+++ b/code/__HELPERS/sorts/comparators.dm
@@ -145,3 +145,15 @@ GLOBAL_VAR_INIT(cmp_field, "name")
*/
/datum/proc/compare_to(datum/D)
return cmp_text_asc("[src]", "[D]")
+
+// profile stuff
+
+/proc/cmp_profile_avg_time_dsc(list/A, list/B)
+ return (B[PROFILE_ITEM_TIME]/(B[PROFILE_ITEM_COUNT] || 1)) - (A[PROFILE_ITEM_TIME]/(A[PROFILE_ITEM_COUNT] || 1))
+
+/proc/cmp_profile_time_dsc(list/A, list/B)
+ return B[PROFILE_ITEM_TIME] - A[PROFILE_ITEM_TIME]
+
+/proc/cmp_profile_count_dsc(list/A, list/B)
+ return B[PROFILE_ITEM_COUNT] - A[PROFILE_ITEM_COUNT]
+
diff --git a/code/datums/profile.dm b/code/datums/profile.dm
new file mode 100644
index 00000000000..9f73d3d96ca
--- /dev/null
+++ b/code/datums/profile.dm
@@ -0,0 +1,17 @@
+//these are real globals so you can use profiling to profile early world init stuff.
+GLOBAL_REAL_VAR(list/PROFILE_STORE)
+GLOBAL_REAL_VAR(PROFILE_LINE)
+GLOBAL_REAL_VAR(PROFILE_FILE)
+GLOBAL_REAL_VAR(PROFILE_SLEEPCHECK)
+GLOBAL_REAL_VAR(PROFILE_TIME)
+
+/proc/profile_show(user, sort = /proc/cmp_profile_avg_time_dsc)
+ sortTim(PROFILE_STORE, sort, TRUE)
+
+ var/list/lines = list()
+
+ for (var/entry in PROFILE_STORE)
+ var/list/data = PROFILE_STORE[entry]
+ lines += "[entry] => [num2text(data[PROFILE_ITEM_TIME], 10)]ms ([data[PROFILE_ITEM_COUNT]]) (avg:[num2text(data[PROFILE_ITEM_TIME]/(data[PROFILE_ITEM_COUNT] || 1), 99)])"
+
+ user << browse("
- [lines.Join("
- ")]
", "window=[url_encode(GUID())]")
diff --git a/code/game/turfs/change_turf.dm b/code/game/turfs/change_turf.dm
index 00e05f1970e..30bde72d27e 100644
--- a/code/game/turfs/change_turf.dm
+++ b/code/game/turfs/change_turf.dm
@@ -404,10 +404,6 @@ GLOBAL_LIST_INIT(multiz_hole_baseturfs, typecacheof(list(
levelupdate()
update_vertical_turf_graphics()
-/turf/simulated/AfterChange(flags, oldType)
- ..()
- RemoveLattice()
-
/turf/proc/RemoveLattice()
for(var/obj/structure/lattice/L in src)
qdel(L)
diff --git a/code/game/turfs/simulated/floor.dm b/code/game/turfs/simulated/floor.dm
index efa4bdefdb9..e2d7ed55608 100644
--- a/code/game/turfs/simulated/floor.dm
+++ b/code/game/turfs/simulated/floor.dm
@@ -35,20 +35,50 @@
return !flooring
/turf/simulated/floor/Initialize(mapload, floortype)
+ PROFILE_SET
. = ..()
+ PROFILE_TICK
if(!floortype && initial_flooring)
floortype = initial_flooring
if(floortype)
- set_flooring(get_flooring_data(floortype))
+ set_flooring(get_flooring_data(floortype), mapload)
else
footstep_sounds = base_footstep_sounds
+ PROFILE_TICK
if(mapload && can_dirty && can_start_dirty)
if(prob(dirty_prob))
dirt += rand(50,100)
update_dirt() //5% chance to start with dirt on a floor tile- give the janitor something to do
+ if(outdoors)
+ SSplanets.addTurf(src)
+ PROFILE_TICK
-/turf/simulated/floor/proc/set_flooring(var/decl/flooring/newflooring)
- make_plating(defer_icon_update = TRUE, strip_bare = TRUE)
+/turf/simulated/floor/Destroy()
+ if(outdoors)
+ SSplanets.removeTurf(src)
+ return ..()
+
+/turf/simulated/proc/make_outdoors()
+ outdoors = TRUE
+ SSplanets.addTurf(src)
+
+/turf/simulated/proc/make_indoors()
+ outdoors = FALSE
+ SSplanets.removeTurf(src)
+
+/turf/simulated/AfterChange(flags, oldType)
+ . = ..()
+ RemoveLattice()
+ // If it was outdoors and still is, it will not get added twice when the planet controller gets around to putting it in.
+ if(flags & CHANGETURF_PRESERVE_OUTDOORS)
+ // if it didn't preserve then we don't need to recheck now do we
+ if(outdoors)
+ make_outdoors()
+ else
+ make_indoors()
+
+/turf/simulated/floor/proc/set_flooring(decl/flooring/newflooring, mapload)
+ make_plating(null, TRUE, TRUE)
flooring = newflooring
footstep_sounds = newflooring.footstep_sounds
// VOREStation Edit - We are plating switching to flooring, swap out old_decals for decals
@@ -56,28 +86,31 @@
old_decals = decals
decals = overfloor_decals
// VOREStation Edit End
+ QUEUE_SMOOTH(src)
QUEUE_SMOOTH_NEIGHBORS(src)
levelupdate()
//This proc will set floor_type to null and the update_icon() proc will then change the icon_state of the turf
//This proc auto corrects the grass tiles' siding.
-/turf/simulated/floor/proc/make_plating(place_product, defer_icon_update, strip_bare = FALSE)
+/turf/simulated/floor/proc/make_plating(place_product, defer_icon_update, strip_bare)
+ if(!defer_icon_update)
+ name = base_name
+ desc = base_desc
+ icon = base_icon
+ icon_state = base_icon_state
+ footstep_sounds = base_footstep_sounds
+ cut_overlays()
+ QUEUE_SMOOTH(src)
+ QUEUE_SMOOTH_NEIGHBORS(src)
+ levelupdate()
- cut_overlays()
- // VOREStation Edit - We are flooring switching to plating, swap out old_decals for decals.
if(flooring)
+ // VOREStation Edit - We are flooring switching to plating, swap out old_decals for decals.
var/list/underfloor_decals = old_decals
old_decals = decals
decals = underfloor_decals
- // VOREStation Edit End
+ // VOREStation Edit End
- name = base_name
- desc = base_desc
- icon = base_icon
- icon_state = base_icon_state
- footstep_sounds = base_footstep_sounds
-
- if(flooring)
if(place_product)
flooring.drop_product(src)
var/newtype = flooring.get_plating_type()
@@ -89,10 +122,6 @@
broken = null
burnt = null
flooring_override = null
- levelupdate()
-
- if(!defer_icon_update)
- QUEUE_SMOOTH_NEIGHBORS(src)
/turf/simulated/floor/levelupdate()
for(var/obj/O in src)
diff --git a/code/game/turfs/simulated/floor_icon.dm b/code/game/turfs/simulated/floor_icon.dm
index 5f9da9de279..a83927773ec 100644
--- a/code/game/turfs/simulated/floor_icon.dm
+++ b/code/game/turfs/simulated/floor_icon.dm
@@ -17,13 +17,17 @@ GLOBAL_LIST_EMPTY(turf_edge_cache)
var/list/flooring_cache = list()
/turf/simulated/floor/update_icon()
+ PROFILE_SET
cut_overlays()
+ PROFILE_TICK
if(flooring)
// Set initial icon and strings.
+ PROFILE_TICK
name = flooring.name
desc = flooring.desc
icon = flooring.icon
+ PROFILE_TICK
if(flooring_override)
icon_state = flooring_override
@@ -32,6 +36,7 @@ var/list/flooring_cache = list()
if(flooring.has_base_range)
icon_state = "[icon_state][rand(0,flooring.has_base_range)]"
flooring_override = icon_state
+ PROFILE_TICK
// Apply edges, corners, and inner corners.
if(flooring.flags & TURF_HAS_EDGES)
@@ -71,15 +76,21 @@ var/list/flooring_cache = list()
var/turf/simulated/floor/T = get_step(src, SOUTHWEST)
if(!flooring.test_link(src, T))
add_overlay(flooring.get_flooring_overlay("[flooring.icon_base]-corner-[SOUTHWEST]", "[flooring.icon_base]_corners", SOUTHWEST))
+ PROFILE_TICK
if(!isnull(broken) && (flooring.flags & TURF_CAN_BREAK))
add_overlay(flooring.get_flooring_overlay("[flooring.icon_base]-broken-[broken]","broken[broken]"))
if(!isnull(burnt) && (flooring.flags & TURF_CAN_BURN))
add_overlay(flooring.get_flooring_overlay("[flooring.icon_base]-burned-[burnt]","burned[burnt]"))
+ PROFILE_TICK
else
+ PROFILE_TICK
// no flooring - just handle plating stuff
if(is_plating() && !(isnull(broken) && isnull(burnt))) //temp, todo
icon = 'icons/turf/flooring/plating.dmi'
icon_state = "dmg[rand(1,4)]"
+ PROFILE_TICK
+
+ PROFILE_TICK
// Re-apply floor decals
if(LAZYLEN(decals))
@@ -90,8 +101,12 @@ var/list/flooring_cache = list()
if(isopenturf(above) && !istype(src, /turf/simulated/floor/outdoors)) // This won't apply to outdoor turfs since its assumed they don't have a ceiling anyways.
add_overlay(GLOB.no_ceiling_image)
+ PROFILE_TICK
+
// ..() has to be last to prevent trampling managed overlays
- return ..()
+ . = ..()
+
+ PROFILE_TICK
/**
* welcome to the less modular but more sensical and efficient way to do icon edges
diff --git a/code/game/turfs/simulated/floors/outdoors.dm b/code/game/turfs/simulated/floors/outdoors.dm
index 48466b9a99b..8e2c587a4b2 100644
--- a/code/game/turfs/simulated/floors/outdoors.dm
+++ b/code/game/turfs/simulated/floors/outdoors.dm
@@ -11,36 +11,8 @@
/turf/simulated/floor/outdoors/Initialize(mapload)
QUEUE_SMOOTH(src)
- . = ..()
-
-/turf/simulated/floor/Initialize(mapload)
- . = ..()
- if(outdoors)
- SSplanets.addTurf(src)
-
-/turf/simulated/floor/Destroy()
- if(outdoors)
- SSplanets.removeTurf(src)
return ..()
-/turf/simulated/proc/make_outdoors()
- outdoors = TRUE
- SSplanets.addTurf(src)
-
-/turf/simulated/proc/make_indoors()
- outdoors = FALSE
- SSplanets.removeTurf(src)
-
-/turf/simulated/AfterChange(flags, oldType)
- . = ..()
- // If it was outdoors and still is, it will not get added twice when the planet controller gets around to putting it in.
- if(flags & CHANGETURF_PRESERVE_OUTDOORS)
- // if it didn't preserve then we don't need to recheck now do we
- if(outdoors)
- make_outdoors()
- else
- make_indoors()
-
/turf/simulated/floor/outdoors/mud
name = "mud"
icon_state = "mud_dark"
diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm
index 15862f45ad9..fa649b3b7b6 100644
--- a/code/modules/admin/admin_verbs.dm
+++ b/code/modules/admin/admin_verbs.dm
@@ -228,6 +228,9 @@ var/list/admin_verbs_debug = list(
/client/proc/SDQL2_query,
/client/proc/Jump,
/client/proc/debug_rogueminer,
+ /client/proc/start_line_profiling,
+ /client/proc/stop_line_profiling,
+ /client/proc/show_line_profiling,
/client/proc/jumptomob,
/client/proc/jumptocoord,
/client/proc/dsay,
diff --git a/code/modules/admin/verbs/debug/profiling.dm b/code/modules/admin/verbs/debug/profiling.dm
new file mode 100644
index 00000000000..16f7915d414
--- /dev/null
+++ b/code/modules/admin/verbs/debug/profiling.dm
@@ -0,0 +1,37 @@
+/client/proc/start_line_profiling()
+ set category = "Profile"
+ set name = "Start Line Profiling"
+ set desc = "Starts tracking line by line profiling for code lines that support it"
+
+ LINE_PROFILE_START
+
+ message_admins("[key_name_admin(src)] started line by line profiling.")
+ // SSblackbox.record_feedback("tally", "admin_verb", 1, "Start Line Profiling")
+ log_admin("[key_name(src)] started line by line profiling.")
+
+/client/proc/stop_line_profiling()
+ set category = "Profile"
+ set name = "Stops Line Profiling"
+ set desc = "Stops tracking line by line profiling for code lines that support it"
+
+ LINE_PROFILE_STOP
+
+ message_admins("[key_name_admin(src)] stopped line by line profiling.")
+ // SSblackbox.record_feedback("tally", "admin_verb", 1, "Stop Line Profiling")
+ log_admin("[key_name(src)] stopped line by line profiling.")
+
+/client/proc/show_line_profiling()
+ set category = "Profile"
+ set name = "Show Line Profiling"
+ set desc = "Shows tracked profiling info from code lines that support it"
+
+ var/sortlist = list(
+ "Avg time" = /proc/cmp_profile_avg_time_dsc,
+ "Total Time" = /proc/cmp_profile_time_dsc,
+ "Call Count" = /proc/cmp_profile_count_dsc
+ )
+ var/sort = input(src, "Sort type?", "Sort Type", "Avg time") as null|anything in sortlist
+ if (!sort)
+ return
+ sort = sortlist[sort]
+ profile_show(src, sort)
diff --git a/code/modules/admin/functions/server/admin_reboot.dm b/code/modules/admin/verbs/server/admin_reboot.dm
similarity index 100%
rename from code/modules/admin/functions/server/admin_reboot.dm
rename to code/modules/admin/verbs/server/admin_reboot.dm
diff --git a/code/modules/mining/mine_turfs.dm b/code/modules/mining/mine_turfs.dm
index 0e384b79636..1786ff68dc7 100644
--- a/code/modules/mining/mine_turfs.dm
+++ b/code/modules/mining/mine_turfs.dm
@@ -90,6 +90,7 @@ turf/simulated/mineral/floor/light_corner
can_build_into_floor = TRUE
SSplanets.addTurf(src)
SSair.mark_for_update(src)
+ QUEUE_SMOOTH(src)
QUEUE_SMOOTH_NEIGHBORS(src)
/turf/simulated/mineral/proc/make_wall()
@@ -103,6 +104,7 @@ turf/simulated/mineral/floor/light_corner
can_build_into_floor = FALSE
SSplanets.removeTurf(src)
SSair.mark_for_update(src)
+ QUEUE_SMOOTH(src)
QUEUE_SMOOTH_NEIGHBORS(src)
/turf/simulated/mineral/Entered(atom/movable/M as mob|obj)
@@ -126,6 +128,7 @@ turf/simulated/mineral/floor/light_corner
else
UpdateMineral() // this'll work because we're INITIALIZED
if(!mapload)
+ QUEUE_SMOOTH(src)
QUEUE_SMOOTH_NEIGHBORS(src)
/* custom smoothing code */
diff --git a/vorestation.dme b/vorestation.dme
index 42b65b0f5a6..2c3d68a25d1 100644
--- a/vorestation.dme
+++ b/vorestation.dme
@@ -24,6 +24,7 @@
#include "code\__DEFINES\_globals.dm"
#include "code\__DEFINES\_lists.dm"
#include "code\__DEFINES\_planes+layers.dm"
+#include "code\__DEFINES\_profile.dm"
#include "code\__DEFINES\_protect.dm"
#include "code\__DEFINES\_tick.dm"
#include "code\__DEFINES\access.dm"
@@ -391,6 +392,7 @@
#include "code\datums\mutable_appearance.dm"
#include "code\datums\perspective.dm"
#include "code\datums\position_point_vector.dm"
+#include "code\datums\profile.dm"
#include "code\datums\progressbar.dm"
#include "code\datums\recipe.dm"
#include "code\datums\riding.dm"
@@ -1539,7 +1541,6 @@
#include "code\modules\admin\callproc\callproc.dm"
#include "code\modules\admin\DB ban\functions.dm"
#include "code\modules\admin\functions\modify_traits.dm"
-#include "code\modules\admin\functions\server\admin_reboot.dm"
#include "code\modules\admin\permissionverbs\permissionedit.dm"
#include "code\modules\admin\secrets\admin_secrets\admin_logs.dm"
#include "code\modules\admin\secrets\admin_secrets\alter_narsie.dm"
@@ -1609,9 +1610,11 @@
#include "code\modules\admin\verbs\striketeam.dm"
#include "code\modules\admin\verbs\ticklag.dm"
#include "code\modules\admin\verbs\tripAI.dm"
+#include "code\modules\admin\verbs\debug\profiling.dm"
#include "code\modules\admin\verbs\SDQL2\SDQL_2.dm"
#include "code\modules\admin\verbs\SDQL2\SDQL_2_parser.dm"
#include "code\modules\admin\verbs\SDQL2\SDQL_2_wrappers.dm"
+#include "code\modules\admin\verbs\server\admin_reboot.dm"
#include "code\modules\admin\view_variables\admin_delete.dm"
#include "code\modules\admin\view_variables\color_matrix_editor.dm"
#include "code\modules\admin\view_variables\debug_variables.dm"