diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 4454aa1770..4b3bf4810d 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -284,6 +284,7 @@ add_files(
newgrf_config.h
newgrf_debug.h
newgrf_debug_gui.cpp
+ newgrf_dump.h
newgrf_engine.cpp
newgrf_engine.h
newgrf_extension.cpp
diff --git a/src/newgrf_debug_gui.cpp b/src/newgrf_debug_gui.cpp
index 894bb6b2e9..216506d81a 100644
--- a/src/newgrf_debug_gui.cpp
+++ b/src/newgrf_debug_gui.cpp
@@ -38,6 +38,7 @@
#include "newgrf_airport.h"
#include "newgrf_airporttiles.h"
#include "newgrf_debug.h"
+#include "newgrf_dump.h"
#include "newgrf_object.h"
#include "newgrf_spritegroup.h"
#include "newgrf_station.h"
diff --git a/src/newgrf_dump.h b/src/newgrf_dump.h
new file mode 100644
index 0000000000..62dba33028
--- /dev/null
+++ b/src/newgrf_dump.h
@@ -0,0 +1,59 @@
+/*
+ * This file is part of OpenTTD.
+ * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
+ * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see .
+ */
+
+/** @file newgrf_dump.h Functions/types related to NewGRF sprite group dumping. */
+
+#ifndef NEWGRF_DUMP_H
+#define NEWGRF_DUMP_H
+
+#include "3rdparty/robin_hood/robin_hood.h"
+#include
+
+enum DumpSpriteGroupPrintOp {
+ DSGPO_PRINT,
+ DSGPO_START,
+ DSGPO_END,
+ DSGPO_NFO_LINE,
+};
+
+using DumpSpriteGroupPrinter = std::function;
+
+struct SpriteGroupDumper {
+ bool use_shadows = false;
+ bool more_details = false;
+
+private:
+ char buffer[1024];
+ DumpSpriteGroupPrinter print_fn;
+
+ const SpriteGroup *top_default_group = nullptr;
+ const SpriteGroup *top_graphics_group = nullptr;
+ robin_hood::unordered_flat_set seen_dsgs;
+
+ enum SpriteGroupDumperFlags {
+ SGDF_DEFAULT = 1 << 0,
+ SGDF_RANGE = 1 << 1,
+ };
+
+ char *DumpSpriteGroupAdjust(char *p, const char *last, const struct DeterministicSpriteGroupAdjust &adjust, const char *padding, uint32_t &highlight_tag, uint &conditional_indent);
+ void DumpSpriteGroup(const struct SpriteGroup *sg, const char *prefix, uint flags);
+
+public:
+ SpriteGroupDumper(DumpSpriteGroupPrinter print) : print_fn(print) {}
+
+ void DumpSpriteGroup(const SpriteGroup *sg, uint flags)
+ {
+ this->DumpSpriteGroup(sg, "", flags);
+ }
+
+ void Print(const char *msg)
+ {
+ this->print_fn(nullptr, DSGPO_PRINT, 0, msg);
+ }
+};
+
+#endif /* NEWGRF_DEBUG_H */
diff --git a/src/newgrf_engine.cpp b/src/newgrf_engine.cpp
index a79a83336d..e01a781e22 100644
--- a/src/newgrf_engine.cpp
+++ b/src/newgrf_engine.cpp
@@ -28,6 +28,7 @@
#include "scope_info.h"
#include "newgrf_extension.h"
#include "newgrf_analysis.h"
+#include "newgrf_dump.h"
#include "safeguards.h"
diff --git a/src/newgrf_generic.cpp b/src/newgrf_generic.cpp
index 1caffc7273..4fe50d0b67 100644
--- a/src/newgrf_generic.cpp
+++ b/src/newgrf_generic.cpp
@@ -17,6 +17,7 @@
#include "newgrf_extension.h"
#include "water_map.h"
#include "string_func.h"
+#include "newgrf_dump.h"
#include
#include "safeguards.h"
diff --git a/src/newgrf_industries.cpp b/src/newgrf_industries.cpp
index bcecca8262..6779c9b51e 100644
--- a/src/newgrf_industries.cpp
+++ b/src/newgrf_industries.cpp
@@ -18,6 +18,7 @@
#include "company_base.h"
#include "error.h"
#include "strings_func.h"
+#include "newgrf_dump.h"
#include "core/random_func.hpp"
#include "table/strings.h"
diff --git a/src/newgrf_newlandscape.cpp b/src/newgrf_newlandscape.cpp
index af207736da..bba54f4699 100644
--- a/src/newgrf_newlandscape.cpp
+++ b/src/newgrf_newlandscape.cpp
@@ -15,6 +15,7 @@
#include "clear_map.h"
#include "core/hash_func.hpp"
#include "string_func.h"
+#include "newgrf_dump.h"
#include "safeguards.h"
diff --git a/src/newgrf_newsignals.cpp b/src/newgrf_newsignals.cpp
index a0fba65139..136d836c34 100644
--- a/src/newgrf_newsignals.cpp
+++ b/src/newgrf_newsignals.cpp
@@ -14,6 +14,7 @@
#include "map_func.h"
#include "tracerestrict.h"
#include "string_func.h"
+#include "newgrf_dump.h"
#include "safeguards.h"
diff --git a/src/newgrf_object.cpp b/src/newgrf_object.cpp
index b97622739b..cad7ca7b4a 100644
--- a/src/newgrf_object.cpp
+++ b/src/newgrf_object.cpp
@@ -23,6 +23,7 @@
#include "clear_func.h"
#include "newgrf_animation_base.h"
#include "newgrf_extension.h"
+#include "newgrf_dump.h"
#include "safeguards.h"
diff --git a/src/newgrf_railtype.cpp b/src/newgrf_railtype.cpp
index 695f2674a8..f09f329d6f 100644
--- a/src/newgrf_railtype.cpp
+++ b/src/newgrf_railtype.cpp
@@ -18,6 +18,7 @@
#include "town.h"
#include "signal_func.h"
#include "road.h"
+#include "newgrf_dump.h"
#include "safeguards.h"
diff --git a/src/newgrf_roadstop.cpp b/src/newgrf_roadstop.cpp
index 91651be514..f980b55bad 100644
--- a/src/newgrf_roadstop.cpp
+++ b/src/newgrf_roadstop.cpp
@@ -25,6 +25,7 @@
#include "newgrf_animation_base.h"
#include "newgrf_sound.h"
#include "newgrf_extension.h"
+#include "newgrf_dump.h"
#include "safeguards.h"
diff --git a/src/newgrf_roadtype.cpp b/src/newgrf_roadtype.cpp
index c310cf62d3..0a8868ad1b 100644
--- a/src/newgrf_roadtype.cpp
+++ b/src/newgrf_roadtype.cpp
@@ -14,6 +14,7 @@
#include "date_func.h"
#include "depot_base.h"
#include "town.h"
+#include "newgrf_dump.h"
#include "safeguards.h"
diff --git a/src/newgrf_spritegroup.cpp b/src/newgrf_spritegroup.cpp
index 1c46180f01..ee9cab2f82 100644
--- a/src/newgrf_spritegroup.cpp
+++ b/src/newgrf_spritegroup.cpp
@@ -20,6 +20,7 @@
#include "scope.h"
#include "debug_settings.h"
#include "newgrf_engine.h"
+#include "newgrf_dump.h"
#include
#include "safeguards.h"
diff --git a/src/newgrf_spritegroup.h b/src/newgrf_spritegroup.h
index a5d0056bd0..d77f6ff2f8 100644
--- a/src/newgrf_spritegroup.h
+++ b/src/newgrf_spritegroup.h
@@ -20,8 +20,6 @@
#include "newgrf_storage.h"
#include "newgrf_commons.h"
-#include "3rdparty/robin_hood/robin_hood.h"
-
#include