Changeset - r24069:49625df81342
[Not reviewed]
docs/logging_and_performance_metrics.md
Show inline comments
 
@@ -96,6 +96,46 @@ The following is an explanation of the d
 
  this should be very fast (in the range of 0-3 ms), if it is slow, consider
 
  switching to the NoSound set.
 

	
 
If the frame rate window is shaded, the title bar will instead show just the
 
current simulation rate and the game speed factor.
 

	
 
## 3.0) NewGRF callback profiling
 

	
 
NewGRF developers can profile callback chains via the `newgrf_profile`
 
console command. The command controls a profiling mode where every sprite
 
request is measured and logged, and written to a CSV file in the end.
 

	
 
The NewGRF developer tools need to be enabled for the command to function.
 

	
 
View the syntax for the command in-game with the console command
 
`help newgrf_profile`.
 

	
 
Profiling only works during game or in the editor, it's not possible to
 
profile across the main menu, world generation, or loading savegames.
 

	
 
The CSV files contain one line per sprite request during the profiling.
 
They can get very large, especially on large games with many objects from
 
the GRF. Start profiling short periods such as 3 or 7 days, and watch the
 
file sizes.
 

	
 
The produced CSV file contains the following fields:
 

	
 
- *Tick* - Game tick counter, this may wrap to zero during recording.
 
  Mainly useful to distinguish events from separate ticks.
 
- *Sprite* - Index of the root Action 2 sprite in the GRF file. This is
 
  the sprite group being resolved.
 
- *Feature* - NewGRF feature number the sprite group is being resolved for.
 
  This will be 0xFF for AI purchase selection and ambient sound callbacks.
 
- *Item* - The id of the item within the GRF. For cargotypes, railtypes,
 
  roadtypes, and tramtypes, this is the integer representation of the label.
 
- *CallbackID* - The type of callback being resolved. ID 0 is regular graphics
 
  lookup. See the `newgrf_callbacks.h` file in the OpenTTD source code for the
 
  full list of callback IDs.
 
- *Microseconds* - Total time spent to resolve the Action 2, in microseconds.
 
- *Depth* - Number of recursive Action 2 lookups were made during resolution.
 
  Value zero means the sprite group resolved directly.
 
- *Result* - Result of the callback resolution. For lookups that result in
 
  a sprite, this is the index of the base action 2 in the GRF file. For
 
  callbacks that give a numeric result, this is the callback result value.
 
  For lookups that result in an industry production or tilelayout, this
 
  is the sprite index of the action 2 defining the production/tilelayout.
projects/openttd_vs140.vcxproj
Show inline comments
 
@@ -580,12 +580,13 @@
 
    <ClInclude Include="..\src\newgrf_engine.h" />
 
    <ClInclude Include="..\src\newgrf_generic.h" />
 
    <ClInclude Include="..\src\newgrf_house.h" />
 
    <ClInclude Include="..\src\newgrf_industries.h" />
 
    <ClInclude Include="..\src\newgrf_industrytiles.h" />
 
    <ClInclude Include="..\src\newgrf_object.h" />
 
    <ClInclude Include="..\src\newgrf_profiling.h" />
 
    <ClInclude Include="..\src\newgrf_properties.h" />
 
    <ClInclude Include="..\src\newgrf_railtype.h" />
 
    <ClInclude Include="..\src\newgrf_roadtype.h" />
 
    <ClInclude Include="..\src\newgrf_sound.h" />
 
    <ClInclude Include="..\src\newgrf_spritegroup.h" />
 
    <ClInclude Include="..\src\newgrf_station.h" />
 
@@ -1233,12 +1234,13 @@
 
    <ClCompile Include="..\src\newgrf_engine.cpp" />
 
    <ClCompile Include="..\src\newgrf_generic.cpp" />
 
    <ClCompile Include="..\src\newgrf_house.cpp" />
 
    <ClCompile Include="..\src\newgrf_industries.cpp" />
 
    <ClCompile Include="..\src\newgrf_industrytiles.cpp" />
 
    <ClCompile Include="..\src\newgrf_object.cpp" />
 
    <ClCompile Include="..\src\newgrf_profiling.cpp" />
 
    <ClCompile Include="..\src\newgrf_railtype.cpp" />
 
    <ClCompile Include="..\src\newgrf_roadtype.cpp" />
 
    <ClCompile Include="..\src\newgrf_sound.cpp" />
 
    <ClCompile Include="..\src\newgrf_spritegroup.cpp" />
 
    <ClCompile Include="..\src\newgrf_station.cpp" />
 
    <ClCompile Include="..\src\newgrf_storage.cpp" />
projects/openttd_vs140.vcxproj.filters
Show inline comments
 
@@ -834,12 +834,15 @@
 
    <ClInclude Include="..\src\newgrf_industrytiles.h">
 
      <Filter>Header Files</Filter>
 
    </ClInclude>
 
    <ClInclude Include="..\src\newgrf_object.h">
 
      <Filter>Header Files</Filter>
 
    </ClInclude>
 
    <ClInclude Include="..\src\newgrf_profiling.h">
 
      <Filter>Header Files</Filter>
 
    </ClInclude>
 
    <ClInclude Include="..\src\newgrf_properties.h">
 
      <Filter>Header Files</Filter>
 
    </ClInclude>
 
    <ClInclude Include="..\src\newgrf_railtype.h">
 
      <Filter>Header Files</Filter>
 
    </ClInclude>
 
@@ -2793,12 +2796,15 @@
 
    <ClCompile Include="..\src\newgrf_industrytiles.cpp">
 
      <Filter>NewGRF</Filter>
 
    </ClCompile>
 
    <ClCompile Include="..\src\newgrf_object.cpp">
 
      <Filter>NewGRF</Filter>
 
    </ClCompile>
 
    <ClCompile Include="..\src\newgrf_profiling.cpp">
 
      <Filter>NewGRF</Filter>
 
    </ClCompile>
 
    <ClCompile Include="..\src\newgrf_railtype.cpp">
 
      <Filter>NewGRF</Filter>
 
    </ClCompile>
 
    <ClCompile Include="..\src\newgrf_roadtype.cpp">
 
      <Filter>NewGRF</Filter>
 
    </ClCompile>
projects/openttd_vs141.vcxproj
Show inline comments
 
@@ -580,12 +580,13 @@
 
    <ClInclude Include="..\src\newgrf_engine.h" />
 
    <ClInclude Include="..\src\newgrf_generic.h" />
 
    <ClInclude Include="..\src\newgrf_house.h" />
 
    <ClInclude Include="..\src\newgrf_industries.h" />
 
    <ClInclude Include="..\src\newgrf_industrytiles.h" />
 
    <ClInclude Include="..\src\newgrf_object.h" />
 
    <ClInclude Include="..\src\newgrf_profiling.h" />
 
    <ClInclude Include="..\src\newgrf_properties.h" />
 
    <ClInclude Include="..\src\newgrf_railtype.h" />
 
    <ClInclude Include="..\src\newgrf_roadtype.h" />
 
    <ClInclude Include="..\src\newgrf_sound.h" />
 
    <ClInclude Include="..\src\newgrf_spritegroup.h" />
 
    <ClInclude Include="..\src\newgrf_station.h" />
 
@@ -1233,12 +1234,13 @@
 
    <ClCompile Include="..\src\newgrf_engine.cpp" />
 
    <ClCompile Include="..\src\newgrf_generic.cpp" />
 
    <ClCompile Include="..\src\newgrf_house.cpp" />
 
    <ClCompile Include="..\src\newgrf_industries.cpp" />
 
    <ClCompile Include="..\src\newgrf_industrytiles.cpp" />
 
    <ClCompile Include="..\src\newgrf_object.cpp" />
 
    <ClCompile Include="..\src\newgrf_profiling.cpp" />
 
    <ClCompile Include="..\src\newgrf_railtype.cpp" />
 
    <ClCompile Include="..\src\newgrf_roadtype.cpp" />
 
    <ClCompile Include="..\src\newgrf_sound.cpp" />
 
    <ClCompile Include="..\src\newgrf_spritegroup.cpp" />
 
    <ClCompile Include="..\src\newgrf_station.cpp" />
 
    <ClCompile Include="..\src\newgrf_storage.cpp" />
projects/openttd_vs141.vcxproj.filters
Show inline comments
 
@@ -834,12 +834,15 @@
 
    <ClInclude Include="..\src\newgrf_industrytiles.h">
 
      <Filter>Header Files</Filter>
 
    </ClInclude>
 
    <ClInclude Include="..\src\newgrf_object.h">
 
      <Filter>Header Files</Filter>
 
    </ClInclude>
 
    <ClInclude Include="..\src\newgrf_profiling.h">
 
      <Filter>Header Files</Filter>
 
    </ClInclude>
 
    <ClInclude Include="..\src\newgrf_properties.h">
 
      <Filter>Header Files</Filter>
 
    </ClInclude>
 
    <ClInclude Include="..\src\newgrf_railtype.h">
 
      <Filter>Header Files</Filter>
 
    </ClInclude>
 
@@ -2793,12 +2796,15 @@
 
    <ClCompile Include="..\src\newgrf_industrytiles.cpp">
 
      <Filter>NewGRF</Filter>
 
    </ClCompile>
 
    <ClCompile Include="..\src\newgrf_object.cpp">
 
      <Filter>NewGRF</Filter>
 
    </ClCompile>
 
    <ClCompile Include="..\src\newgrf_profiling.cpp">
 
      <Filter>NewGRF</Filter>
 
    </ClCompile>
 
    <ClCompile Include="..\src\newgrf_railtype.cpp">
 
      <Filter>NewGRF</Filter>
 
    </ClCompile>
 
    <ClCompile Include="..\src\newgrf_roadtype.cpp">
 
      <Filter>NewGRF</Filter>
 
    </ClCompile>
projects/openttd_vs142.vcxproj
Show inline comments
 
@@ -580,12 +580,13 @@
 
    <ClInclude Include="..\src\newgrf_engine.h" />
 
    <ClInclude Include="..\src\newgrf_generic.h" />
 
    <ClInclude Include="..\src\newgrf_house.h" />
 
    <ClInclude Include="..\src\newgrf_industries.h" />
 
    <ClInclude Include="..\src\newgrf_industrytiles.h" />
 
    <ClInclude Include="..\src\newgrf_object.h" />
 
    <ClInclude Include="..\src\newgrf_profiling.h" />
 
    <ClInclude Include="..\src\newgrf_properties.h" />
 
    <ClInclude Include="..\src\newgrf_railtype.h" />
 
    <ClInclude Include="..\src\newgrf_roadtype.h" />
 
    <ClInclude Include="..\src\newgrf_sound.h" />
 
    <ClInclude Include="..\src\newgrf_spritegroup.h" />
 
    <ClInclude Include="..\src\newgrf_station.h" />
 
@@ -1233,12 +1234,13 @@
 
    <ClCompile Include="..\src\newgrf_engine.cpp" />
 
    <ClCompile Include="..\src\newgrf_generic.cpp" />
 
    <ClCompile Include="..\src\newgrf_house.cpp" />
 
    <ClCompile Include="..\src\newgrf_industries.cpp" />
 
    <ClCompile Include="..\src\newgrf_industrytiles.cpp" />
 
    <ClCompile Include="..\src\newgrf_object.cpp" />
 
    <ClCompile Include="..\src\newgrf_profiling.cpp" />
 
    <ClCompile Include="..\src\newgrf_railtype.cpp" />
 
    <ClCompile Include="..\src\newgrf_roadtype.cpp" />
 
    <ClCompile Include="..\src\newgrf_sound.cpp" />
 
    <ClCompile Include="..\src\newgrf_spritegroup.cpp" />
 
    <ClCompile Include="..\src\newgrf_station.cpp" />
 
    <ClCompile Include="..\src\newgrf_storage.cpp" />
projects/openttd_vs142.vcxproj.filters
Show inline comments
 
@@ -834,12 +834,15 @@
 
    <ClInclude Include="..\src\newgrf_industrytiles.h">
 
      <Filter>Header Files</Filter>
 
    </ClInclude>
 
    <ClInclude Include="..\src\newgrf_object.h">
 
      <Filter>Header Files</Filter>
 
    </ClInclude>
 
    <ClInclude Include="..\src\newgrf_profiling.h">
 
      <Filter>Header Files</Filter>
 
    </ClInclude>
 
    <ClInclude Include="..\src\newgrf_properties.h">
 
      <Filter>Header Files</Filter>
 
    </ClInclude>
 
    <ClInclude Include="..\src\newgrf_railtype.h">
 
      <Filter>Header Files</Filter>
 
    </ClInclude>
 
@@ -2793,12 +2796,15 @@
 
    <ClCompile Include="..\src\newgrf_industrytiles.cpp">
 
      <Filter>NewGRF</Filter>
 
    </ClCompile>
 
    <ClCompile Include="..\src\newgrf_object.cpp">
 
      <Filter>NewGRF</Filter>
 
    </ClCompile>
 
    <ClCompile Include="..\src\newgrf_profiling.cpp">
 
      <Filter>NewGRF</Filter>
 
    </ClCompile>
 
    <ClCompile Include="..\src\newgrf_railtype.cpp">
 
      <Filter>NewGRF</Filter>
 
    </ClCompile>
 
    <ClCompile Include="..\src\newgrf_roadtype.cpp">
 
      <Filter>NewGRF</Filter>
 
    </ClCompile>
source.list
Show inline comments
 
@@ -267,12 +267,13 @@ newgrf_debug.h
 
newgrf_engine.h
 
newgrf_generic.h
 
newgrf_house.h
 
newgrf_industries.h
 
newgrf_industrytiles.h
 
newgrf_object.h
 
newgrf_profiling.h
 
newgrf_properties.h
 
newgrf_railtype.h
 
newgrf_roadtype.h
 
newgrf_sound.h
 
newgrf_spritegroup.h
 
newgrf_station.h
 
@@ -983,12 +984,13 @@ newgrf_config.cpp
 
newgrf_engine.cpp
 
newgrf_generic.cpp
 
newgrf_house.cpp
 
newgrf_industries.cpp
 
newgrf_industrytiles.cpp
 
newgrf_object.cpp
 
newgrf_profiling.cpp
 
newgrf_railtype.cpp
 
newgrf_roadtype.cpp
 
newgrf_sound.cpp
 
newgrf_spritegroup.cpp
 
newgrf_station.cpp
 
newgrf_storage.cpp
src/console_cmds.cpp
Show inline comments
 
@@ -30,12 +30,13 @@
 
#include "date_func.h"
 
#include "company_func.h"
 
#include "gamelog.h"
 
#include "ai/ai.hpp"
 
#include "ai/ai_config.hpp"
 
#include "newgrf.h"
 
#include "newgrf_profiling.h"
 
#include "console_func.h"
 
#include "engine_base.h"
 
#include "game/game.hpp"
 
#include "table/strings.h"
 
#include <time.h>
 

	
 
@@ -1874,12 +1875,141 @@ DEF_CONSOLE_CMD(ConNewGRFReload)
 
	}
 

	
 
	ReloadNewGRFData();
 
	return true;
 
}
 

	
 
DEF_CONSOLE_CMD(ConNewGRFProfile)
 
{
 
	if (argc == 0) {
 
		IConsoleHelp("Collect performance data about NewGRF sprite requests and callbacks. Sub-commands can be abbreviated.");
 
		IConsoleHelp("Usage: newgrf_profile [list]");
 
		IConsoleHelp("  List all NewGRFs that can be profiled, and their status.");
 
		IConsoleHelp("Usage: newgrf_profile select <grf-num>...");
 
		IConsoleHelp("  Select one or more GRFs for profiling.");
 
		IConsoleHelp("Usage: newgrf_profile unselect <grf-num>...");
 
		IConsoleHelp("  Unselect one or more GRFs from profiling. Use the keyword \"all\" instead of a GRF number to unselect all. Removing an active profiler aborts data collection.");
 
		IConsoleHelp("Usage: newgrf_profile start [<num-days>]");
 
		IConsoleHelp("  Begin profiling all selected GRFs. If a number of days is provided, profiling stops after that many in-game days.");
 
		IConsoleHelp("Usage: newgrf_profile stop");
 
		IConsoleHelp("  End profiling and write the collected data to CSV files.");
 
		IConsoleHelp("Usage: newgrf_profile abort");
 
		IConsoleHelp("  End profiling and discard all collected data.");
 
		return true;
 
	}
 

	
 
	extern const std::vector<GRFFile *> &GetAllGRFFiles();
 
	const std::vector<GRFFile *> &files = GetAllGRFFiles();
 

	
 
	/* "list" sub-command */
 
	if (argc == 1 || strncasecmp(argv[1], "lis", 3) == 0) {
 
		IConsolePrint(CC_INFO, "Loaded GRF files:");
 
		int i = 1;
 
		for (GRFFile *grf : files) {
 
			auto profiler = std::find_if(_newgrf_profilers.begin(), _newgrf_profilers.end(), [&](NewGRFProfiler &pr) { return pr.grffile == grf; });
 
			bool selected = profiler != _newgrf_profilers.end();
 
			bool active = selected && profiler->active;
 
			TextColour tc = active ? TC_LIGHT_BLUE : selected ? TC_GREEN : CC_INFO;
 
			const char *statustext = active ? " (active)" : selected ? " (selected)" : "";
 
			IConsolePrintF(tc, "%d: [%08X] %s%s", i, BSWAP32(grf->grfid), grf->filename, statustext);
 
			i++;
 
		}
 
		return true;
 
	}
 

	
 
	/* "select" sub-command */
 
	if (strncasecmp(argv[1], "sel", 3) == 0 && argc >= 3) {
 
		for (size_t argnum = 2; argnum < argc; ++argnum) {
 
			int grfnum = atoi(argv[argnum]);
 
			if (grfnum < 1 || grfnum > (int)files.size()) { // safe cast, files.size() should not be larger than a few hundred in the most extreme cases
 
				IConsolePrintF(CC_WARNING, "GRF number %d out of range, not added.", grfnum);
 
				continue;
 
			}
 
			GRFFile *grf = files[grfnum - 1];
 
			if (std::any_of(_newgrf_profilers.begin(), _newgrf_profilers.end(), [&](NewGRFProfiler &pr) { return pr.grffile == grf; })) {
 
				IConsolePrintF(CC_WARNING, "GRF number %d [%08X] is already selected for profiling.", grfnum, BSWAP32(grf->grfid));
 
				continue;
 
			}
 
			_newgrf_profilers.emplace_back(grf);
 
		}
 
		return true;
 
	}
 

	
 
	/* "unselect" sub-command */
 
	if (strncasecmp(argv[1], "uns", 3) == 0 && argc >= 3) {
 
		for (size_t argnum = 2; argnum < argc; ++argnum) {
 
			if (strcasecmp(argv[argnum], "all") == 0) {
 
				_newgrf_profilers.clear();
 
				break;
 
			}
 
			int grfnum = atoi(argv[argnum]);
 
			if (grfnum < 1 || grfnum > (int)files.size()) {
 
				IConsolePrintF(CC_WARNING, "GRF number %d out of range, not removing.", grfnum);
 
				continue;
 
			}
 
			GRFFile *grf = files[grfnum - 1];
 
			auto pos = std::find_if(_newgrf_profilers.begin(), _newgrf_profilers.end(), [&](NewGRFProfiler &pr) { return pr.grffile == grf; });
 
			if (pos != _newgrf_profilers.end()) _newgrf_profilers.erase(pos);
 
		}
 
		return true;
 
	}
 

	
 
	/* "start" sub-command */
 
	if (strncasecmp(argv[1], "sta", 3) == 0) {
 
		std::string grfids;
 
		size_t started = 0;
 
		for (NewGRFProfiler &pr : _newgrf_profilers) {
 
			if (!pr.active) {
 
				pr.Start();
 
				started++;
 

	
 
				if (!grfids.empty()) grfids += ", ";
 
				char grfidstr[12]{ 0 };
 
				seprintf(grfidstr, lastof(grfidstr), "[%08X]", BSWAP32(pr.grffile->grfid));
 
				grfids += grfidstr;
 
			}
 
		}
 
		if (started > 0) {
 
			IConsolePrintF(CC_DEBUG, "Started profiling for GRFID%s %s", (started > 1) ? "s" : "", grfids.c_str());
 
			if (argc >= 3) {
 
				int days = max(atoi(argv[2]), 1);
 
				_newgrf_profile_end_date = _date + days;
 

	
 
				char datestrbuf[32]{ 0 };
 
				SetDParam(0, _newgrf_profile_end_date);
 
				GetString(datestrbuf, STR_JUST_DATE_ISO, lastof(datestrbuf));
 
				IConsolePrintF(CC_DEBUG, "Profiling will automatically stop on game date %s", datestrbuf);
 
			} else {
 
				_newgrf_profile_end_date = MAX_DAY;
 
			}
 
		} else if (_newgrf_profilers.empty()) {
 
			IConsolePrintF(CC_WARNING, "No GRFs selected for profiling, did not start.");
 
		} else {
 
			IConsolePrintF(CC_WARNING, "Did not start profiling for any GRFs, all selected GRFs are already profiling.");
 
		}
 
		return true;
 
	}
 

	
 
	/* "stop" sub-command */
 
	if (strncasecmp(argv[1], "sto", 3) == 0) {
 
		NewGRFProfiler::FinishAll();
 
		return true;
 
	}
 

	
 
	/* "abort" sub-command */
 
	if (strncasecmp(argv[1], "abo", 3) == 0) {
 
		for (NewGRFProfiler &pr : _newgrf_profilers) {
 
			pr.Abort();
 
		}
 
		_newgrf_profile_end_date = MAX_DAY;
 
		return true;
 
	}
 

	
 
	return false;
 
}
 

	
 
#ifdef _DEBUG
 
/******************
 
 *  debug commands
 
 ******************/
 

	
 
static void IConsoleDebugLibRegister()
 
@@ -2053,7 +2183,8 @@ void IConsoleStdLibRegister()
 
#endif
 
	IConsoleCmdRegister("fps",     ConFramerate);
 
	IConsoleCmdRegister("fps_wnd", ConFramerateWindow);
 

	
 
	/* NewGRF development stuff */
 
	IConsoleCmdRegister("reload_newgrfs",  ConNewGRFReload, ConHookNewGRFDeveloperTool);
 
	IConsoleCmdRegister("newgrf_profile",  ConNewGRFProfile, ConHookNewGRFDeveloperTool);
 
}
src/date.cpp
Show inline comments
 
@@ -15,12 +15,13 @@
 
#include "settings_type.h"
 
#include "date_func.h"
 
#include "vehicle_base.h"
 
#include "rail_gui.h"
 
#include "linkgraph/linkgraph.h"
 
#include "saveload/saveload.h"
 
#include "newgrf_profiling.h"
 

	
 
#include "safeguards.h"
 

	
 
Year      _cur_year;   ///< Current year, starting at 0
 
Month     _cur_month;  ///< Current month (0..11)
 
Date      _date;       ///< Current date in days (day counter)
 
@@ -242,12 +243,16 @@ static void OnNewMonth()
 

	
 
/**
 
 * Runs various procedures that have to be done daily
 
 */
 
static void OnNewDay()
 
{
 
	if (!_newgrf_profilers.empty() && _newgrf_profile_end_date <= _date) {
 
		NewGRFProfiler::FinishAll();
 
	}
 

	
 
	if (_network_server) NetworkServerDailyLoop();
 

	
 
	DisasterDailyLoop();
 
	IndustryDailyLoop();
 

	
 
	SetWindowWidgetDirty(WC_STATUS_BAR, 0, 0);
src/misc.cpp
Show inline comments
 
@@ -26,12 +26,13 @@
 
#include "core/pool_type.hpp"
 
#include "game/game.hpp"
 
#include "linkgraph/linkgraphschedule.h"
 
#include "station_kdtree.h"
 
#include "town_kdtree.h"
 
#include "viewport_kdtree.h"
 
#include "newgrf_profiling.h"
 

	
 
#include "safeguards.h"
 

	
 

	
 
extern TileIndex _cur_tileloop_tile;
 
extern void MakeNewgameSettingsLive();
 
@@ -66,12 +67,14 @@ void InitializeGame(uint size_x, uint si
 
	_fast_forward = 0;
 
	_tick_counter = 0;
 
	_cur_tileloop_tile = 1;
 
	_thd.redsq = INVALID_TILE;
 
	if (reset_settings) MakeNewgameSettingsLive();
 

	
 
	_newgrf_profilers.clear();
 

	
 
	if (reset_date) {
 
		SetDate(ConvertYMDToDate(_settings_game.game_creation.starting_year, 0, 1), 0);
 
		InitializeOldNames();
 
	}
 

	
 
	LinkGraphSchedule::Clear();
src/newgrf.cpp
Show inline comments
 
@@ -63,12 +63,17 @@
 
 * of help at #tycoon. Also thanks to Michael Blunck for his GRF files which
 
 * served as subject to the initial testing of this codec. */
 

	
 
/** List of all loaded GRF files */
 
static std::vector<GRFFile *> _grf_files;
 

	
 
const std::vector<GRFFile *> &GetAllGRFFiles()
 
{
 
	return _grf_files;
 
}
 

	
 
/** Miscellaneous GRF features, set by Action 0x0D, parameter 0x9E */
 
byte _misc_grf_features = 0;
 

	
 
/** 32 * 8 = 256 flags. Apparently TTDPatch uses this many.. */
 
static uint32 _ttdpatch_flags[8];
 

	
 
@@ -4997,12 +5002,13 @@ static void NewSpriteGroup(ByteReader *b
 
		{
 
			byte varadjust;
 
			byte varsize;
 

	
 
			assert(DeterministicSpriteGroup::CanAllocateItem());
 
			DeterministicSpriteGroup *group = new DeterministicSpriteGroup();
 
			group->nfo_line = _cur.nfo_line;
 
			act_group = group;
 
			group->var_scope = HasBit(type, 1) ? VSG_SCOPE_PARENT : VSG_SCOPE_SELF;
 

	
 
			switch (GB(type, 2, 2)) {
 
				default: NOT_REACHED();
 
				case 0: group->size = DSG_SIZE_BYTE;  varsize = 1; break;
 
@@ -5113,12 +5119,13 @@ static void NewSpriteGroup(ByteReader *b
 
		case 0x80: // Self scope
 
		case 0x83: // Parent scope
 
		case 0x84: // Relative scope
 
		{
 
			assert(RandomizedSpriteGroup::CanAllocateItem());
 
			RandomizedSpriteGroup *group = new RandomizedSpriteGroup();
 
			group->nfo_line = _cur.nfo_line;
 
			act_group = group;
 
			group->var_scope = HasBit(type, 1) ? VSG_SCOPE_PARENT : VSG_SCOPE_SELF;
 

	
 
			if (HasBit(type, 2)) {
 
				if (feature <= GSF_AIRCRAFT) group->var_scope = VSG_SCOPE_RELATIVE;
 
				group->count = buf->ReadByte();
 
@@ -5161,12 +5168,13 @@ static void NewSpriteGroup(ByteReader *b
 
						grfmsg(0, "NewSpriteGroup: No sprite set to work on! Skipping");
 
						return;
 
					}
 

	
 
					assert(RealSpriteGroup::CanAllocateItem());
 
					RealSpriteGroup *group = new RealSpriteGroup();
 
					group->nfo_line = _cur.nfo_line;
 
					act_group = group;
 

	
 
					group->num_loaded  = num_loaded;
 
					group->num_loading = num_loading;
 
					if (num_loaded  > 0) group->loaded = CallocT<const SpriteGroup*>(num_loaded);
 
					if (num_loading > 0) group->loading = CallocT<const SpriteGroup*>(num_loading);
 
@@ -5194,12 +5202,13 @@ static void NewSpriteGroup(ByteReader *b
 
				case GSF_OBJECTS:
 
				case GSF_INDUSTRYTILES: {
 
					byte num_building_sprites = max((uint8)1, type);
 

	
 
					assert(TileLayoutSpriteGroup::CanAllocateItem());
 
					TileLayoutSpriteGroup *group = new TileLayoutSpriteGroup();
 
					group->nfo_line = _cur.nfo_line;
 
					act_group = group;
 

	
 
					/* On error, bail out immediately. Temporary GRF data was already freed */
 
					if (ReadSpriteLayout(buf, num_building_sprites, true, feature, false, type == 0, &group->dts)) return;
 
					break;
 
				}
 
@@ -5209,12 +5218,13 @@ static void NewSpriteGroup(ByteReader *b
 
						grfmsg(1, "NewSpriteGroup: Unsupported industry production version %d, skipping", type);
 
						break;
 
					}
 

	
 
					assert(IndustryProductionSpriteGroup::CanAllocateItem());
 
					IndustryProductionSpriteGroup *group = new IndustryProductionSpriteGroup();
 
					group->nfo_line = _cur.nfo_line;
 
					act_group = group;
 
					group->version = type;
 
					if (type == 0) {
 
						group->num_input = 3;
 
						for (uint i = 0; i < 3; i++) {
 
							group->subtract_input[i] = (int16)buf->ReadWord(); // signed
src/newgrf_airport.cpp
Show inline comments
 
@@ -55,12 +55,15 @@ struct AirportResolverObject : public Re
 
			case VSG_SCOPE_SELF: return &this->airport_scope;
 
			default: return ResolverObject::GetScope(scope, relative);
 
		}
 
	}
 

	
 
	const SpriteGroup *ResolveReal(const RealSpriteGroup *group) const override;
 

	
 
	GrfSpecFeature GetFeature() const override;
 
	uint32 GetDebugID() const override;
 
};
 

	
 
/**
 
 * Reset airport classes to their default state.
 
 * This includes initialising the defaults classes with an empty
 
 * entry, for standard airports.
 
@@ -223,12 +226,22 @@ void AirportOverrideManager::SetEntitySp
 
	if (group->num_loaded > 0) return group->loaded[0];
 
	if (group->num_loading > 0) return group->loading[0];
 

	
 
	return nullptr;
 
}
 

	
 
GrfSpecFeature AirportResolverObject::GetFeature() const
 
{
 
	return GSF_AIRPORTS;
 
}
 

	
 
uint32 AirportResolverObject::GetDebugID() const
 
{
 
	return AirportSpec::Get(this->airport_scope.airport_id)->grf_prop.local_id;
 
}
 

	
 
/* virtual */ uint32 AirportScopeResolver::GetRandomBits() const
 
{
 
	return this->st == nullptr ? 0 : this->st->random_bits;
 
}
 

	
 
/**
src/newgrf_airporttiles.cpp
Show inline comments
 
@@ -217,12 +217,22 @@ AirportTileResolverObject::AirportTileRe
 
		CallbackID callback, uint32 callback_param1, uint32 callback_param2)
 
	: ResolverObject(ats->grf_prop.grffile, callback, callback_param1, callback_param2), tiles_scope(*this, ats, tile, st)
 
{
 
	this->root_spritegroup = ats->grf_prop.spritegroup[0];
 
}
 

	
 
GrfSpecFeature AirportTileResolverObject::GetFeature() const
 
{
 
	return GSF_AIRPORTTILES;
 
}
 

	
 
uint32 AirportTileResolverObject::GetDebugID() const
 
{
 
	return this->tiles_scope.ats->grf_prop.local_id;
 
}
 

	
 
uint16 GetAirportTileCallback(CallbackID callback, uint32 param1, uint32 param2, const AirportTileSpec *ats, Station *st, TileIndex tile, int extra_data = 0)
 
{
 
	AirportTileResolverObject object(ats, tile, st, callback, param1, param2);
 
	return object.ResolveCallback();
 
}
 

	
src/newgrf_airporttiles.h
Show inline comments
 
@@ -19,21 +19,22 @@
 

	
 
/** Scope resolver for handling the tiles of an airport. */
 
struct AirportTileScopeResolver : public ScopeResolver {
 
	struct Station *st;  ///< %Station of the airport for which the callback is run, or \c nullptr for build gui.
 
	byte airport_id;     ///< Type of airport for which the callback is run.
 
	TileIndex tile;      ///< Tile for the callback, only valid for airporttile callbacks.
 
	const AirportTileSpec *ats;
 

	
 
	/**
 
	 * Constructor of the scope resolver specific for airport tiles.
 
	 * @param ats Specification of the airport tiles.
 
	 * @param tile %Tile for the callback, only valid for airporttile callbacks.
 
	 * @param st Station of the airport for which the callback is run, or \c nullptr for build gui.
 
	 */
 
	AirportTileScopeResolver(ResolverObject &ro, const AirportTileSpec *ats, TileIndex tile, Station *st)
 
		: ScopeResolver(ro), st(st), tile(tile)
 
		: ScopeResolver(ro), st(st), tile(tile), ats(ats)
 
	{
 
		assert(st != nullptr);
 
		this->airport_id = st->airport.type;
 
	}
 

	
 
	uint32 GetRandomBits() const override;
 
@@ -51,12 +52,15 @@ struct AirportTileResolverObject : publi
 
	{
 
		switch (scope) {
 
			case VSG_SCOPE_SELF: return &tiles_scope;
 
			default: return ResolverObject::GetScope(scope, relative);
 
		}
 
	}
 

	
 
	GrfSpecFeature GetFeature() const override;
 
	uint32 GetDebugID() const override;
 
};
 

	
 
/**
 
 * Defines the data structure of each individual tile of an airport.
 
 */
 
struct AirportTileSpec {
src/newgrf_canal.cpp
Show inline comments
 
@@ -10,12 +10,13 @@
 
#include "stdafx.h"
 
#include "debug.h"
 
#include "newgrf_spritegroup.h"
 
#include "newgrf_canal.h"
 
#include "water.h"
 
#include "water_map.h"
 
#include "spritecache.h"
 

	
 
#include "safeguards.h"
 

	
 
/** Table of canal 'feature' sprite groups */
 
WaterFeature _water_feature[CF_END];
 

	
 
@@ -32,12 +33,13 @@ struct CanalScopeResolver : public Scope
 
	uint32 GetVariable(byte variable, uint32 parameter, bool *available) const override;
 
};
 

	
 
/** Resolver object for canals. */
 
struct CanalResolverObject : public ResolverObject {
 
	CanalScopeResolver canal_scope;
 
	CanalFeature feature;
 

	
 
	CanalResolverObject(CanalFeature feature, TileIndex tile,
 
			CallbackID callback = CBID_NO_CALLBACK, uint32 callback_param1 = 0, uint32 callback_param2 = 0);
 

	
 
	ScopeResolver *GetScope(VarSpriteGroupScope scope = VSG_SCOPE_SELF, byte relative = 0) override
 
	{
 
@@ -45,12 +47,15 @@ struct CanalResolverObject : public Reso
 
			case VSG_SCOPE_SELF: return &this->canal_scope;
 
			default: return ResolverObject::GetScope(scope, relative);
 
		}
 
	}
 

	
 
	const SpriteGroup *ResolveReal(const RealSpriteGroup *group) const override;
 

	
 
	GrfSpecFeature GetFeature() const override;
 
	uint32 GetDebugID() const override;
 
};
 

	
 
/* virtual */ uint32 CanalScopeResolver::GetRandomBits() const
 
{
 
	/* Return random bits only for water tiles, not station tiles */
 
	return IsTileType(this->tile, MP_WATER) ? GetWaterTileRandomBits(this->tile) : 0;
 
@@ -108,23 +113,33 @@ struct CanalResolverObject : public Reso
 
{
 
	if (group->num_loaded == 0) return nullptr;
 

	
 
	return group->loaded[0];
 
}
 

	
 
GrfSpecFeature CanalResolverObject::GetFeature() const
 
{
 
	return GSF_CANALS;
 
}
 

	
 
uint32 CanalResolverObject::GetDebugID() const
 
{
 
	return this->feature;
 
}
 

	
 
/**
 
 * Canal resolver constructor.
 
 * @param feature Which canal feature we want.
 
 * @param tile Tile index of canal.
 
 * @param callback Callback ID.
 
 * @param callback_param1 First parameter (var 10) of the callback.
 
 * @param callback_param2 Second parameter (var 18) of the callback.
 
 */
 
CanalResolverObject::CanalResolverObject(CanalFeature feature, TileIndex tile,
 
		CallbackID callback, uint32 callback_param1, uint32 callback_param2)
 
		: ResolverObject(_water_feature[feature].grffile, callback, callback_param1, callback_param2), canal_scope(*this, tile)
 
		: ResolverObject(_water_feature[feature].grffile, callback, callback_param1, callback_param2), canal_scope(*this, tile), feature(feature)
 
{
 
	this->root_spritegroup = _water_feature[feature].group;
 
}
 

	
 
/**
 
 * Lookup the base sprite to use for a canal.
src/newgrf_cargo.cpp
Show inline comments
 
@@ -12,36 +12,51 @@
 
#include "newgrf_spritegroup.h"
 

	
 
#include "safeguards.h"
 

	
 
/** Resolver of cargo. */
 
struct CargoResolverObject : public ResolverObject {
 
	const CargoSpec *cargospec;
 

	
 
	CargoResolverObject(const CargoSpec *cs, CallbackID callback = CBID_NO_CALLBACK, uint32 callback_param1 = 0, uint32 callback_param2 = 0);
 

	
 
	const SpriteGroup *ResolveReal(const RealSpriteGroup *group) const override;
 

	
 
	GrfSpecFeature GetFeature() const override;
 
	uint32 GetDebugID() const override;
 
};
 

	
 
/* virtual */ const SpriteGroup *CargoResolverObject::ResolveReal(const RealSpriteGroup *group) const
 
{
 
	/* Cargo action 2s should always have only 1 "loaded" state, but some
 
	 * times things don't follow the spec... */
 
	if (group->num_loaded > 0) return group->loaded[0];
 
	if (group->num_loading > 0) return group->loading[0];
 

	
 
	return nullptr;
 
}
 

	
 
GrfSpecFeature CargoResolverObject::GetFeature() const
 
{
 
	return GSF_CARGOES;
 
}
 

	
 
uint32 CargoResolverObject::GetDebugID() const
 
{
 
	return this->cargospec->label;
 
}
 

	
 
/**
 
 * Constructor of the cargo resolver.
 
 * @param cs Cargo being resolved.
 
 * @param callback Callback ID.
 
 * @param callback_param1 First parameter (var 10) of the callback.
 
 * @param callback_param2 Second parameter (var 18) of the callback.
 
 */
 
CargoResolverObject::CargoResolverObject(const CargoSpec *cs, CallbackID callback, uint32 callback_param1, uint32 callback_param2)
 
		: ResolverObject(cs->grffile, callback, callback_param1, callback_param2)
 
		: ResolverObject(cs->grffile, callback, callback_param1, callback_param2), cargospec(cs)
 
{
 
	this->root_spritegroup = cs->group;
 
}
 

	
 
/**
 
 * Get the custom sprite for the given cargo type.
src/newgrf_engine.cpp
Show inline comments
 
@@ -943,12 +943,28 @@ static uint32 VehicleGetVariable(Vehicle
 
	uint set = (v->cargo.StoredCount() * totalsets) / max((uint16)1, v->cargo_cap);
 
	set = min(set, totalsets - 1);
 

	
 
	return in_motion ? group->loaded[set] : group->loading[set];
 
}
 

	
 
GrfSpecFeature VehicleResolverObject::GetFeature() const
 
{
 
	switch (Engine::Get(this->self_scope.self_type)->type) {
 
		case VEH_TRAIN: return GSF_TRAINS;
 
		case VEH_ROAD: return GSF_ROADVEHICLES;
 
		case VEH_SHIP: return GSF_SHIPS;
 
		case VEH_AIRCRAFT: return GSF_AIRCRAFT;
 
		default: return GSF_INVALID;
 
	}
 
}
 

	
 
uint32 VehicleResolverObject::GetDebugID() const
 
{
 
	return Engine::Get(this->self_scope.self_type)->grf_prop.local_id;
 
}
 

	
 
/**
 
 * Get the grf file associated with an engine type.
 
 * @param engine_type Engine to query.
 
 * @return grf file associated with the engine.
 
 */
 
static const GRFFile *GetEngineGrfFile(EngineID engine_type)
src/newgrf_engine.h
Show inline comments
 
@@ -62,12 +62,15 @@ struct VehicleResolverObject : public Re
 
	VehicleResolverObject(EngineID engine_type, const Vehicle *v, WagonOverride wagon_override, bool info_view = false,
 
			CallbackID callback = CBID_NO_CALLBACK, uint32 callback_param1 = 0, uint32 callback_param2 = 0);
 

	
 
	ScopeResolver *GetScope(VarSpriteGroupScope scope = VSG_SCOPE_SELF, byte relative = 0) override;
 

	
 
	const SpriteGroup *ResolveReal(const RealSpriteGroup *group) const override;
 

	
 
	GrfSpecFeature GetFeature() const override;
 
	uint32 GetDebugID() const override;
 
};
 

	
 
static const uint TRAININFO_DEFAULT_VEHICLE_WIDTH   = 29;
 
static const uint ROADVEHINFO_DEFAULT_VEHICLE_WIDTH = 32;
 
static const uint VEHICLEINFO_FULL_VEHICLE_WIDTH    = 32;
 

	
src/newgrf_generic.cpp
Show inline comments
 
@@ -26,20 +26,22 @@ struct GenericScopeResolver : public Sco
 
	uint8 dst_industry;        ///< Destination industry substitute type. 0xFF for "town", 0xFE for "unknown".
 
	uint8 distance;
 
	AIConstructionEvent event;
 
	uint8 count;
 
	uint8 station_size;
 

	
 
	uint8 feature;
 

	
 
	/**
 
	 * Generic scope resolver.
 
	 * @param ro Surrounding resolver.
 
	 * @param ai_callback Callback comes from the AI.
 
	 */
 
	GenericScopeResolver(ResolverObject &ro, bool ai_callback)
 
		: ScopeResolver(ro), cargo_type(0), default_selection(0), src_industry(0), dst_industry(0), distance(0),
 
		event(), count(0), station_size(0), ai_callback(ai_callback)
 
		event(), count(0), station_size(0), feature(GSF_INVALID), ai_callback(ai_callback)
 
	{
 
	}
 

	
 
	uint32 GetVariable(byte variable, uint32 parameter, bool *available) const override;
 

	
 
private:
 
@@ -59,12 +61,22 @@ struct GenericResolverObject : public Re
 
			case VSG_SCOPE_SELF: return &this->generic_scope;
 
			default: return ResolverObject::GetScope(scope, relative);
 
		}
 
	}
 

	
 
	const SpriteGroup *ResolveReal(const RealSpriteGroup *group) const override;
 

	
 
	GrfSpecFeature GetFeature() const override
 
	{
 
		return (GrfSpecFeature)this->generic_scope.feature;
 
	}
 

	
 
	uint32 GetDebugID() const override
 
	{
 
		return 0;
 
	}
 
};
 

	
 
struct GenericCallback {
 
	const GRFFile *file;
 
	const SpriteGroup *group;
 

	
 
@@ -223,12 +235,13 @@ uint16 GetAiPurchaseCallbackResult(uint8
 
	object.generic_scope.src_industry      = src_industry;
 
	object.generic_scope.dst_industry      = dst_industry;
 
	object.generic_scope.distance          = distance;
 
	object.generic_scope.event             = event;
 
	object.generic_scope.count             = count;
 
	object.generic_scope.station_size      = station_size;
 
	object.generic_scope.feature           = feature;
 

	
 
	uint16 callback = GetGenericCallbackResult(feature, object, 0, 0, file);
 
	if (callback != CALLBACK_FAILED) callback = GB(callback, 0, 8);
 
	return callback;
 
}
 

	
 
@@ -244,12 +257,13 @@ void AmbientSoundEffectCallback(TileInde
 
	/* Only run every 1/200-th time. */
 
	uint32 r; // Save for later
 
	if (!Chance16R(1, 200, r) || !_settings_client.sound.ambient) return;
 

	
 
	/* Prepare resolver object. */
 
	GenericResolverObject object(false, CBID_SOUNDS_AMBIENT_EFFECT);
 
	object.generic_scope.feature = GSF_SOUNDFX;
 

	
 
	uint32 param1_v7 = GetTileType(tile) << 28 | Clamp(TileHeight(tile), 0, 15) << 24 | GB(r, 16, 8) << 16 | GetTerrainType(tile);
 
	uint32 param1_v8 = GetTileType(tile) << 24 | GetTileZ(tile) << 16 | GB(r, 16, 8) << 8 | (HasTileWaterClass(tile) ? GetWaterClass(tile) : 0) << 3 | GetTerrainType(tile);
 

	
 
	/* Run callback. */
 
	const GRFFile *grf_file;
src/newgrf_house.cpp
Show inline comments
 
@@ -59,12 +59,22 @@ HouseResolverObject::HouseResolverObject
 
	house_scope(*this, house_id, tile, town, not_yet_constructed, initial_random_bits, watched_cargo_triggers),
 
	town_scope(*this, town, not_yet_constructed) // Don't access StorePSA if house is not yet constructed.
 
{
 
	this->root_spritegroup = HouseSpec::Get(house_id)->grf_prop.spritegroup[0];
 
}
 

	
 
GrfSpecFeature HouseResolverObject::GetFeature() const
 
{
 
	return GSF_HOUSES;
 
}
 

	
 
uint32 HouseResolverObject::GetDebugID() const
 
{
 
	return HouseSpec::Get(this->house_scope.house_id)->grf_prop.local_id;
 
}
 

	
 
HouseClassID AllocateHouseClassID(byte grf_class_id, uint32 grfid)
 
{
 
	/* Start from 1 because 0 means that no class has been assigned. */
 
	for (int i = 1; i != lengthof(_class_mapping); i++) {
 
		HouseClassMapping *map = &_class_mapping[i];
 

	
src/newgrf_house.h
Show inline comments
 
@@ -61,12 +61,15 @@ struct HouseResolverObject : public Reso
 
		switch (scope) {
 
			case VSG_SCOPE_SELF:   return &this->house_scope;
 
			case VSG_SCOPE_PARENT: return &this->town_scope;
 
			default: return ResolverObject::GetScope(scope, relative);
 
		}
 
	}
 

	
 
	GrfSpecFeature GetFeature() const override;
 
	uint32 GetDebugID() const override;
 
};
 

	
 
/**
 
 * Makes class IDs unique to each GRF file.
 
 * Houses can be assigned class IDs which are only comparable within the GRF
 
 * file they were defined in. This mapping ensures that if two houses have the
src/newgrf_industries.cpp
Show inline comments
 
@@ -486,12 +486,22 @@ TownScopeResolver *IndustriesResolverObj
 
		if (t == nullptr) return nullptr;
 
		this->town_scope = new TownScopeResolver(*this, t, readonly);
 
	}
 
	return this->town_scope;
 
}
 

	
 
GrfSpecFeature IndustriesResolverObject::GetFeature() const
 
{
 
	return GSF_INDUSTRIES;
 
}
 

	
 
uint32 IndustriesResolverObject::GetDebugID() const
 
{
 
	return GetIndustrySpec(this->industries_scope.type)->grf_prop.local_id;
 
}
 

	
 
/**
 
 * Perform an industry callback.
 
 * @param callback The callback to perform.
 
 * @param param1 The first parameter.
 
 * @param param2 The second parameter.
 
 * @param industry The industry to do the callback for.
src/newgrf_industries.h
Show inline comments
 
@@ -60,12 +60,15 @@ struct IndustriesResolverObject : public
 
			FALLTHROUGH;
 

	
 
			default:
 
				return ResolverObject::GetScope(scope, relative);
 
		}
 
	}
 

	
 
	GrfSpecFeature GetFeature() const override;
 
	uint32 GetDebugID() const override;
 
};
 

	
 
/** When should the industry(tile) be triggered for random bits? */
 
enum IndustryTrigger {
 
	/** Triggered each tile loop */
 
	INDUSTRY_TRIGGER_TILELOOP_PROCESS = 1,
src/newgrf_industrytiles.cpp
Show inline comments
 
@@ -136,17 +136,28 @@ static const GRFFile *GetIndTileGrffile(
 
 * @param callback_param2 Second parameter (var 18) of the callback.
 
 */
 
IndustryTileResolverObject::IndustryTileResolverObject(IndustryGfx gfx, TileIndex tile, Industry *indus,
 
			CallbackID callback, uint32 callback_param1, uint32 callback_param2)
 
	: ResolverObject(GetIndTileGrffile(gfx), callback, callback_param1, callback_param2),
 
	indtile_scope(*this, indus, tile),
 
	ind_scope(*this, tile, indus, indus->type)
 
	ind_scope(*this, tile, indus, indus->type),
 
	gfx(gfx)
 
{
 
	this->root_spritegroup = GetIndustryTileSpec(gfx)->grf_prop.spritegroup[0];
 
}
 

	
 
GrfSpecFeature IndustryTileResolverObject::GetFeature() const
 
{
 
	return GSF_INDUSTRYTILES;
 
}
 

	
 
uint32 IndustryTileResolverObject::GetDebugID() const
 
{
 
	return GetIndustryTileSpec(gfx)->grf_prop.local_id;
 
}
 

	
 
static void IndustryDrawTileLayout(const TileInfo *ti, const TileLayoutSpriteGroup *group, byte rnd_colour, byte stage, IndustryGfx gfx)
 
{
 
	const DrawTileSprites *dts = group->ProcessRegisters(&stage);
 

	
 
	SpriteID image = dts->ground.sprite;
 
	PaletteID pal  = dts->ground.pal;
src/newgrf_industrytiles.h
Show inline comments
 
@@ -36,24 +36,28 @@ struct IndustryTileScopeResolver : publi
 
};
 

	
 
/** Resolver for industry tiles. */
 
struct IndustryTileResolverObject : public ResolverObject {
 
	IndustryTileScopeResolver indtile_scope; ///< Scope resolver for the industry tile.
 
	IndustriesScopeResolver ind_scope;       ///< Scope resolver for the industry owning the tile.
 
	IndustryGfx gfx;
 

	
 
	IndustryTileResolverObject(IndustryGfx gfx, TileIndex tile, Industry *indus,
 
			CallbackID callback = CBID_NO_CALLBACK, uint32 callback_param1 = 0, uint32 callback_param2 = 0);
 

	
 
	ScopeResolver *GetScope(VarSpriteGroupScope scope = VSG_SCOPE_SELF, byte relative = 0) override
 
	{
 
		switch (scope) {
 
			case VSG_SCOPE_SELF: return &indtile_scope;
 
			case VSG_SCOPE_PARENT: return &ind_scope;
 
			default: return ResolverObject::GetScope(scope, relative);
 
		}
 
	}
 

	
 
	GrfSpecFeature GetFeature() const override;
 
	uint32 GetDebugID() const override;
 
};
 

	
 
bool DrawNewIndustryTile(TileInfo *ti, Industry *i, IndustryGfx gfx, const IndustryTileSpec *inds);
 
uint16 GetIndustryTileCallback(CallbackID callback, uint32 param1, uint32 param2, IndustryGfx gfx_id, Industry *industry, TileIndex tile);
 
CommandCost PerformIndustryTileSlopeCheck(TileIndex ind_base_tile, TileIndex ind_tile, const IndustryTileSpec *its, IndustryType type, IndustryGfx gfx, size_t layout_index, uint16 initial_random_bits, Owner founder, IndustryAvailabilityCallType creation_type);
 

	
src/newgrf_object.cpp
Show inline comments
 
@@ -349,13 +349,13 @@ unhandled:
 
 * @param callback Callback ID.
 
 * @param param1 First parameter (var 10) of the callback.
 
 * @param param2 Second parameter (var 18) of the callback.
 
 */
 
ObjectResolverObject::ObjectResolverObject(const ObjectSpec *spec, Object *obj, TileIndex tile, uint8 view,
 
		CallbackID callback, uint32 param1, uint32 param2)
 
	: ResolverObject(spec->grf_prop.grffile, callback, param1, param2), object_scope(*this, obj, tile, view)
 
	: ResolverObject(spec->grf_prop.grffile, callback, param1, param2), object_scope(*this, obj, spec, tile, view)
 
{
 
	this->town_scope = nullptr;
 
	this->root_spritegroup = (obj == nullptr && spec->grf_prop.spritegroup[CT_PURCHASE_OBJECT] != nullptr) ?
 
			spec->grf_prop.spritegroup[CT_PURCHASE_OBJECT] : spec->grf_prop.spritegroup[0];
 
}
 

	
 
@@ -381,12 +381,22 @@ TownScopeResolver *ObjectResolverObject:
 
		if (t == nullptr) return nullptr;
 
		this->town_scope = new TownScopeResolver(*this, t, this->object_scope.obj == nullptr);
 
	}
 
	return this->town_scope;
 
}
 

	
 
GrfSpecFeature ObjectResolverObject::GetFeature() const
 
{
 
	return GSF_OBJECTS;
 
}
 

	
 
uint32 ObjectResolverObject::GetDebugID() const
 
{
 
	return this->object_scope.spec->grf_prop.local_id;
 
}
 

	
 
/**
 
 * Perform a callback for an object.
 
 * @param callback The callback to perform.
 
 * @param param1   The first parameter to pass to the NewGRF.
 
 * @param param2   The second parameter to pass to the NewGRF.
 
 * @param spec     The specification of the object / the entry point.
src/newgrf_object.h
Show inline comments
 
@@ -95,25 +95,26 @@ struct ObjectSpec {
 
	static const ObjectSpec *Get(ObjectType index);
 
	static const ObjectSpec *GetByTile(TileIndex tile);
 
};
 

	
 
/** Object scope resolver. */
 
struct ObjectScopeResolver : public ScopeResolver {
 
	struct Object *obj; ///< The object the callback is ran for.
 
	TileIndex tile;     ///< The tile related to the object.
 
	uint8 view;         ///< The view of the object.
 
	struct Object *obj;     ///< The object the callback is ran for.
 
	const ObjectSpec *spec; ///< Specification of the object type.
 
	TileIndex tile;         ///< The tile related to the object.
 
	uint8 view;             ///< The view of the object.
 

	
 
	/**
 
	 * Constructor of an object scope resolver.
 
	 * @param ro Surrounding resolver.
 
	 * @param obj Object being resolved.
 
	 * @param tile %Tile of the object.
 
	 * @param view View of the object.
 
	 */
 
	ObjectScopeResolver(ResolverObject &ro, Object *obj, TileIndex tile, uint8 view = 0)
 
		: ScopeResolver(ro), obj(obj), tile(tile), view(view)
 
	ObjectScopeResolver(ResolverObject &ro, Object *obj, const ObjectSpec *spec, TileIndex tile, uint8 view = 0)
 
		: ScopeResolver(ro), obj(obj), spec(spec), tile(tile), view(view)
 
	{
 
	}
 

	
 
	uint32 GetRandomBits() const override;
 
	uint32 GetVariable(byte variable, uint32 parameter, bool *available) const override;
 
};
 
@@ -141,12 +142,15 @@ struct ObjectResolverObject : public Res
 

	
 
			default:
 
				return ResolverObject::GetScope(scope, relative);
 
		}
 
	}
 

	
 
	GrfSpecFeature GetFeature() const override;
 
	uint32 GetDebugID() const override;
 

	
 
private:
 
	TownScopeResolver *GetTown();
 
};
 

	
 
/** Struct containing information relating to object classes. */
 
typedef NewGRFClass<ObjectSpec, ObjectClassID, OBJECT_CLASS_MAX> ObjectClass;
src/newgrf_profiling.cpp
Show inline comments
 
new file 100644
 
/*
 
 * 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 <http://www.gnu.org/licenses/>.
 
 */
 

	
 
 /** @file newgrf_profiling.cpp Profiling of NewGRF action 2 handling. */
 

	
 
#include "newgrf_profiling.h"
 
#include "date_func.h"
 
#include "fileio_func.h"
 
#include "string_func.h"
 
#include "console_func.h"
 
#include "spritecache.h"
 

	
 
#include <chrono>
 
#include <time.h>
 

	
 

	
 
std::vector<NewGRFProfiler> _newgrf_profilers;
 
Date _newgrf_profile_end_date;
 

	
 

	
 
/**
 
 * Create profiler object and begin profiling session.
 
 * @param grffile   The GRF file to collect profiling data on
 
 * @param end_date  Game date to end profiling on
 
 */
 
NewGRFProfiler::NewGRFProfiler(const GRFFile *grffile) : grffile{ grffile }, active{ false }, cur_call{}
 
{
 
}
 

	
 
/**
 
 * Complete profiling session and write data to file
 
 */
 
NewGRFProfiler::~NewGRFProfiler()
 
{
 
}
 

	
 
/**
 
 * Capture the start of a sprite group resolution.
 
 * @param resolver  Data about sprite group being resolved
 
 */
 
void NewGRFProfiler::BeginResolve(const ResolverObject &resolver)
 
{
 
	using namespace std::chrono;
 
	this->cur_call.root_sprite = resolver.root_spritegroup->nfo_line;
 
	this->cur_call.subs = 0;
 
	this->cur_call.time = (uint32)time_point_cast<microseconds>(high_resolution_clock::now()).time_since_epoch().count();
 
	this->cur_call.tick = _tick_counter;
 
	this->cur_call.cb = resolver.callback;
 
	this->cur_call.feat = resolver.GetFeature();
 
	this->cur_call.item = resolver.GetDebugID();
 
}
 

	
 
/**
 
 * Capture the completion of a sprite group resolution.
 
 */
 
void NewGRFProfiler::EndResolve(const SpriteGroup *result)
 
{
 
	using namespace std::chrono;
 
	this->cur_call.time = (uint32)time_point_cast<microseconds>(high_resolution_clock::now()).time_since_epoch().count() - this->cur_call.time;
 

	
 
	if (result == nullptr) {
 
		this->cur_call.result = 0;
 
	} else if (result->type == SGT_CALLBACK) {
 
		this->cur_call.result = static_cast<const CallbackResultSpriteGroup *>(result)->result;
 
	} else if (result->type == SGT_RESULT) {
 
		this->cur_call.result = GetSpriteLocalID(static_cast<const ResultSpriteGroup *>(result)->sprite);
 
	} else {
 
		this->cur_call.result = result->nfo_line;
 
	}
 

	
 
	this->calls.push_back(this->cur_call);
 
}
 

	
 
/**
 
 * Capture a recursive sprite group resolution.
 
 */
 
void NewGRFProfiler::RecursiveResolve()
 
{
 
	this->cur_call.subs += 1;
 
}
 

	
 
void NewGRFProfiler::Start()
 
{
 
	this->Abort();
 
	this->active = true;
 
	this->start_tick = _tick_counter;
 
}
 

	
 
uint32 NewGRFProfiler::Finish()
 
{
 
	if (!this->active) return 0;
 

	
 
	if (this->calls.empty()) {
 
		IConsolePrintF(CC_DEBUG, "Finished profile of NewGRF [%08X], no events collected, not writing a file", BSWAP32(this->grffile->grfid));
 
		return 0;
 
	}
 

	
 
	std::string filename = this->GetOutputFilename();
 
	IConsolePrintF(CC_DEBUG, "Finished profile of NewGRF [%08X], writing %u events to %s", BSWAP32(this->grffile->grfid), (uint)this->calls.size(), filename.c_str());
 

	
 
	FILE *f = FioFOpenFile(filename.c_str(), "wt", Subdirectory::NO_DIRECTORY);
 
	FileCloser fcloser(f);
 

	
 
	uint32 total_microseconds = 0;
 

	
 
	fputs("Tick,Sprite,Feature,Item,CallbackID,Microseconds,Depth,Result\n", f);
 
	for (const Call &c : this->calls) {
 
		fprintf(f, "%u,%u,0x%X,%d,0x%X,%u,%u,%u\n", c.tick, c.root_sprite, c.feat, c.item, (uint)c.cb, c.time, c.subs, c.result);
 
		total_microseconds += c.time;
 
	}
 

	
 
	this->Abort();
 

	
 
	return total_microseconds;
 
}
 

	
 
void NewGRFProfiler::Abort()
 
{
 
	this->active = false;
 
	this->calls.clear();
 
}
 

	
 
/**
 
 * Get name of the file that will be written.
 
 * @return File name of profiling output file.
 
 */
 
std::string NewGRFProfiler::GetOutputFilename() const
 
{
 
	time_t write_time = time(nullptr);
 

	
 
	char timestamp[16] = {};
 
	strftime(timestamp, lengthof(timestamp), "%Y%m%d-%H%M", localtime(&write_time));
 

	
 
	char filepath[MAX_PATH] = {};
 
	seprintf(filepath, lastof(filepath), "%sgrfprofile-%s-%08X.csv", FiosGetScreenshotDir(), timestamp, BSWAP32(this->grffile->grfid));
 

	
 
	return std::string(filepath);
 
}
 

	
 
uint32 NewGRFProfiler::FinishAll()
 
{
 
	int max_ticks = 0;
 
	uint32 total_microseconds = 0;
 
	for (NewGRFProfiler &pr : _newgrf_profilers) {
 
		if (pr.active) {
 
			total_microseconds += pr.Finish();
 
			max_ticks = max(max_ticks, _tick_counter - pr.start_tick);
 
		}
 
	}
 

	
 
	if (total_microseconds > 0 && max_ticks > 0) {
 
		IConsolePrintF(CC_DEBUG, "Total NewGRF callback processing: %u microseconds over %d ticks", total_microseconds, max_ticks);
 
	}
 

	
 
	_newgrf_profile_end_date = MAX_DAY;
 

	
 
	return total_microseconds;
 
}
src/newgrf_profiling.h
Show inline comments
 
new file 100644
 
/*
 
 * 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 <http://www.gnu.org/licenses/>.
 
 */
 

	
 
 /** @file newgrf_profiling.h Profiling of NewGRF action 2 handling. */
 

	
 
#ifndef NEWGRF_PROFILING_H
 
#define NEWGRF_PROFILING_H
 

	
 
#include "stdafx.h"
 
#include "date_type.h"
 
#include "newgrf.h"
 
#include "newgrf_callbacks.h"
 
#include "newgrf_spritegroup.h"
 

	
 
#include <vector>
 
#include <string>
 
#include <memory>
 

	
 
/**
 
 * Callback profiler for NewGRF development
 
 */
 
struct NewGRFProfiler {
 
	NewGRFProfiler(const GRFFile *grffile);
 
	~NewGRFProfiler();
 

	
 
	void BeginResolve(const ResolverObject &resolver);
 
	void EndResolve(const SpriteGroup *result);
 
	void RecursiveResolve();
 

	
 
	void Start();
 
	uint32 Finish();
 
	void Abort();
 
	std::string GetOutputFilename() const;
 

	
 
	static uint32 FinishAll();
 

	
 
	/** Measurement of a single sprite group resolution */
 
	struct Call {
 
		uint32 root_sprite;  ///< Pseudo-sprite index in GRF file
 
		uint32 item;         ///< Local ID of item being resolved for
 
		uint32 result;       ///< Result of callback
 
		uint32 subs;         ///< Sub-calls to other sprite groups
 
		uint32 time;         ///< Time taken for resolution (microseconds)
 
		uint16 tick;         ///< Game tick
 
		CallbackID cb;       ///< Callback ID
 
		GrfSpecFeature feat; ///< GRF feature being resolved for
 
	};
 

	
 
	const GRFFile *grffile;  ///< Which GRF is being profiled
 
	bool active;             ///< Is this profiler collecting data
 
	uint16 start_tick;       ///< Tick number this profiler was started on
 
	Call cur_call;           ///< Data for current call in progress
 
	std::vector<Call> calls; ///< All calls collected so far
 
};
 

	
 
extern std::vector<NewGRFProfiler> _newgrf_profilers;
 
extern Date _newgrf_profile_end_date;
 

	
 
#endif /* NEWGRF_PROFILING_H */
src/newgrf_railtype.cpp
Show inline comments
 
@@ -62,23 +62,33 @@
 
{
 
	if (group->num_loading > 0) return group->loading[0];
 
	if (group->num_loaded  > 0) return group->loaded[0];
 
	return nullptr;
 
}
 

	
 
GrfSpecFeature RailTypeResolverObject::GetFeature() const
 
{
 
	return GSF_RAILTYPES;
 
}
 

	
 
uint32 RailTypeResolverObject::GetDebugID() const
 
{
 
	return this->railtype_scope.rti->label;
 
}
 

	
 
/**
 
 * Resolver object for rail types.
 
 * @param rti Railtype. nullptr in NewGRF Inspect window.
 
 * @param tile %Tile containing the track. For track on a bridge this is the southern bridgehead.
 
 * @param context Are we resolving sprites for the upper halftile, or on a bridge?
 
 * @param rtsg Railpart of interest
 
 * @param param1 Extra parameter (first parameter of the callback, except railtypes do not have callbacks).
 
 * @param param2 Extra parameter (second parameter of the callback, except railtypes do not have callbacks).
 
 */
 
RailTypeResolverObject::RailTypeResolverObject(const RailtypeInfo *rti, TileIndex tile, TileContext context, RailTypeSpriteGroup rtsg, uint32 param1, uint32 param2)
 
	: ResolverObject(rti != nullptr ? rti->grffile[rtsg] : nullptr, CBID_NO_CALLBACK, param1, param2), railtype_scope(*this, tile, context)
 
	: ResolverObject(rti != nullptr ? rti->grffile[rtsg] : nullptr, CBID_NO_CALLBACK, param1, param2), railtype_scope(*this, rti, tile, context)
 
{
 
	this->root_spritegroup = rti != nullptr ? rti->group[rtsg] : nullptr;
 
}
 

	
 
/**
 
 * Get the sprite to draw for the given tile.
src/newgrf_railtype.h
Show inline comments
 
@@ -15,21 +15,22 @@
 
#include "newgrf_spritegroup.h"
 

	
 
/** Resolver for the railtype scope. */
 
struct RailTypeScopeResolver : public ScopeResolver {
 
	TileIndex tile;      ///< Tracktile. For track on a bridge this is the southern bridgehead.
 
	TileContext context; ///< Are we resolving sprites for the upper halftile, or on a bridge?
 
	const RailtypeInfo *rti;
 

	
 
	/**
 
	 * Constructor of the railtype scope resolvers.
 
	 * @param ro Surrounding resolver.
 
	 * @param tile %Tile containing the track. For track on a bridge this is the southern bridgehead.
 
	 * @param context Are we resolving sprites for the upper halftile, or on a bridge?
 
	 */
 
	RailTypeScopeResolver(ResolverObject &ro, TileIndex tile, TileContext context)
 
		: ScopeResolver(ro), tile(tile), context(context)
 
	RailTypeScopeResolver(ResolverObject &ro, const RailtypeInfo *rti, TileIndex tile, TileContext context)
 
		: ScopeResolver(ro), tile(tile), context(context), rti(rti)
 
	{
 
	}
 

	
 
	uint32 GetRandomBits() const override;
 
	uint32 GetVariable(byte variable, uint32 parameter, bool *available) const override;
 
};
 
@@ -46,12 +47,15 @@ struct RailTypeResolverObject : public R
 
			case VSG_SCOPE_SELF: return &this->railtype_scope;
 
			default:             return ResolverObject::GetScope(scope, relative);
 
		}
 
	}
 

	
 
	const SpriteGroup *ResolveReal(const RealSpriteGroup *group) const override;
 

	
 
	GrfSpecFeature GetFeature() const override;
 
	uint32 GetDebugID() const override;
 
};
 

	
 
SpriteID GetCustomRailSprite(const RailtypeInfo *rti, TileIndex tile, RailTypeSpriteGroup rtsg, TileContext context = TCX_NORMAL, uint *num_results = nullptr);
 
SpriteID GetCustomSignalSprite(const RailtypeInfo *rti, TileIndex tile, SignalType type, SignalVariant var, SignalState state, bool gui = false);
 

	
 
uint8 GetReverseRailTypeTranslation(RailType railtype, const GRFFile *grffile);
src/newgrf_roadtype.cpp
Show inline comments
 
@@ -62,35 +62,51 @@
 
{
 
	if (group->num_loading > 0) return group->loading[0];
 
	if (group->num_loaded  > 0) return group->loaded[0];
 
	return nullptr;
 
}
 

	
 
GrfSpecFeature RoadTypeResolverObject::GetFeature() const
 
{
 
	RoadType rt = GetRoadTypeByLabel(this->roadtype_scope.rti->label, false);
 
	switch (GetRoadTramType(rt)) {
 
		case RTT_ROAD: return GSF_ROADTYPES;
 
		case RTT_TRAM: return GSF_TRAMTYPES;
 
		default: return GSF_INVALID;
 
	}
 
}
 

	
 
uint32 RoadTypeResolverObject::GetDebugID() const
 
{
 
	return this->roadtype_scope.rti->label;
 
}
 

	
 
/**
 
 * Constructor of the roadtype scope resolvers.
 
 * @param ro Surrounding resolver.
 
 * @param tile %Tile containing the track. For track on a bridge this is the southern bridgehead.
 
 * @param context Are we resolving sprites for the upper halftile, or on a bridge?
 
 */
 
RoadTypeScopeResolver::RoadTypeScopeResolver(ResolverObject &ro, TileIndex tile, TileContext context) : ScopeResolver(ro)
 
RoadTypeScopeResolver::RoadTypeScopeResolver(ResolverObject &ro, const RoadTypeInfo *rti, TileIndex tile, TileContext context) : ScopeResolver(ro)
 
{
 
	this->tile = tile;
 
	this->context = context;
 
	this->rti = rti;
 
}
 

	
 
/**
 
 * Resolver object for road types.
 
 * @param rti Roadtype. nullptr in NewGRF Inspect window.
 
 * @param tile %Tile containing the track. For track on a bridge this is the southern bridgehead.
 
 * @param context Are we resolving sprites for the upper halftile, or on a bridge?
 
 * @param rtsg Roadpart of interest
 
 * @param param1 Extra parameter (first parameter of the callback, except roadtypes do not have callbacks).
 
 * @param param2 Extra parameter (second parameter of the callback, except roadtypes do not have callbacks).
 
 */
 
RoadTypeResolverObject::RoadTypeResolverObject(const RoadTypeInfo *rti, TileIndex tile, TileContext context, RoadTypeSpriteGroup rtsg, uint32 param1, uint32 param2)
 
	: ResolverObject(rti != nullptr ? rti->grffile[rtsg] : nullptr, CBID_NO_CALLBACK, param1, param2), roadtype_scope(*this, tile, context)
 
	: ResolverObject(rti != nullptr ? rti->grffile[rtsg] : nullptr, CBID_NO_CALLBACK, param1, param2), roadtype_scope(*this, rti, tile, context)
 
{
 
	this->root_spritegroup = rti != nullptr ? rti->group[rtsg] : nullptr;
 
}
 

	
 
/**
 
 * Get the sprite to draw for the given tile.
src/newgrf_roadtype.h
Show inline comments
 
@@ -15,14 +15,15 @@
 
#include "newgrf_spritegroup.h"
 

	
 
/** Resolver for the railtype scope. */
 
struct RoadTypeScopeResolver : public ScopeResolver {
 
	TileIndex tile;      ///< Tracktile. For track on a bridge this is the southern bridgehead.
 
	TileContext context; ///< Are we resolving sprites for the upper halftile, or on a bridge?
 
	const RoadTypeInfo *rti;
 

	
 
	RoadTypeScopeResolver(ResolverObject &ro, TileIndex tile, TileContext context);
 
	RoadTypeScopeResolver(ResolverObject &ro, const RoadTypeInfo *rti, TileIndex tile, TileContext context);
 

	
 
	/* virtual */ uint32 GetRandomBits() const;
 
	/* virtual */ uint32 GetVariable(byte variable, uint32 parameter, bool *available) const;
 
};
 

	
 
/** Resolver object for road types. */
 
@@ -37,12 +38,15 @@ struct RoadTypeResolverObject : public R
 
			case VSG_SCOPE_SELF: return &this->roadtype_scope;
 
			default:             return ResolverObject::GetScope(scope, relative);
 
		}
 
	}
 

	
 
	/* virtual */ const SpriteGroup *ResolveReal(const RealSpriteGroup *group) const;
 

	
 
	GrfSpecFeature GetFeature() const override;
 
	uint32 GetDebugID() const override;
 
};
 

	
 
SpriteID GetCustomRoadSprite(const RoadTypeInfo *rti, TileIndex tile, RoadTypeSpriteGroup rtsg, TileContext context = TCX_NORMAL, uint *num_results = nullptr);
 

	
 
uint8 GetReverseRoadTypeTranslation(RoadType roadtype, const GRFFile *grffile);
 

	
src/newgrf_spritegroup.cpp
Show inline comments
 
@@ -8,12 +8,13 @@
 
/** @file newgrf_spritegroup.cpp Handling of primarily NewGRF action 2. */
 

	
 
#include "stdafx.h"
 
#include <algorithm>
 
#include "debug.h"
 
#include "newgrf_spritegroup.h"
 
#include "newgrf_profiling.h"
 
#include "core/pool_func.hpp"
 

	
 
#include "safeguards.h"
 

	
 
SpriteGroupPool _spritegroup_pool("SpriteGroup");
 
INSTANTIATE_POOL_METHODS(SpriteGroup)
 
@@ -31,16 +32,29 @@ TemporaryStorageArray<int32, 0x110> _tem
 
 * @param top_level true if this is a top-level SpriteGroup, false if used nested in another SpriteGroup.
 
 * @return the resolved group
 
 */
 
/* static */ const SpriteGroup *SpriteGroup::Resolve(const SpriteGroup *group, ResolverObject &object, bool top_level)
 
{
 
	if (group == nullptr) return nullptr;
 
	if (top_level) {
 

	
 
	const GRFFile *grf = object.grffile;
 
	auto profiler = std::find_if(_newgrf_profilers.begin(), _newgrf_profilers.end(), [&](const NewGRFProfiler &pr) { return pr.grffile == grf; });
 

	
 
	if (profiler == _newgrf_profilers.end() || !profiler->active) {
 
		if (top_level) _temp_store.ClearChanges();
 
		return group->Resolve(object);
 
	} else if (top_level) {
 
		profiler->BeginResolve(object);
 
		_temp_store.ClearChanges();
 
		const SpriteGroup *result = group->Resolve(object);
 
		profiler->EndResolve(result);
 
		return result;
 
	} else {
 
		profiler->RecursiveResolve();
 
		return group->Resolve(object);
 
	}
 
	return group->Resolve(object);
 
}
 

	
 
RealSpriteGroup::~RealSpriteGroup()
 
{
 
	free(this->loaded);
 
	free(this->loading);
src/newgrf_spritegroup.h
Show inline comments
 
@@ -53,19 +53,20 @@ struct ResolverObject;
 
typedef Pool<SpriteGroup, SpriteGroupID, 1024, 1 << 30, PT_DATA> SpriteGroupPool;
 
extern SpriteGroupPool _spritegroup_pool;
 

	
 
/* Common wrapper for all the different sprite group types */
 
struct SpriteGroup : SpriteGroupPool::PoolItem<&_spritegroup_pool> {
 
protected:
 
	SpriteGroup(SpriteGroupType type) : type(type) {}
 
	SpriteGroup(SpriteGroupType type) : nfo_line(0), type(type) {}
 
	/** Base sprite group resolver */
 
	virtual const SpriteGroup *Resolve(ResolverObject &object) const { return this; };
 

	
 
public:
 
	virtual ~SpriteGroup() {}
 

	
 
	uint32 nfo_line;
 
	SpriteGroupType type;
 

	
 
	virtual SpriteID GetResult() const { return 0; }
 
	virtual byte GetNumResults() const { return 0; }
 
	virtual uint16 GetCallbackResult() const { return CALLBACK_FAILED; }
 

	
 
@@ -395,9 +396,21 @@ struct ResolverObject {
 
	{
 
		this->last_value = 0;
 
		this->waiting_triggers = 0;
 
		this->used_triggers = 0;
 
		memset(this->reseed, 0, sizeof(this->reseed));
 
	}
 

	
 
	/**
 
	 * Get the feature number being resolved for.
 
	 * This function is mainly intended for the callback profiling feature.
 
	 */
 
	virtual GrfSpecFeature GetFeature() const { return GSF_INVALID; }
 
	/**
 
	 * Get an identifier for the item being resolved.
 
	 * This function is mainly intended for the callback profiling feature,
 
	 * and should return an identifier recognisable by the NewGRF developer.
 
	 */
 
	virtual uint32 GetDebugID() const { return 0; }
 
};
 

	
 
#endif /* NEWGRF_SPRITEGROUP_H */
src/newgrf_station.cpp
Show inline comments
 
@@ -524,12 +524,22 @@ uint32 Waypoint::GetNewGRFVariable(const
 
		}
 
	}
 

	
 
	return group->loading[0];
 
}
 

	
 
GrfSpecFeature StationResolverObject::GetFeature() const
 
{
 
	return GSF_STATIONS;
 
}
 

	
 
uint32 StationResolverObject::GetDebugID() const
 
{
 
	return this->station_scope.statspec->grf_prop.local_id;
 
}
 

	
 
/**
 
 * Resolver for stations.
 
 * @param statspec Station (type) specification.
 
 * @param st Instance of the station.
 
 * @param tile %Tile of the station.
 
 * @param callback Callback ID.
src/newgrf_station.h
Show inline comments
 
@@ -72,12 +72,15 @@ struct StationResolverObject : public Re
 
			default:
 
				return ResolverObject::GetScope(scope, relative);
 
		}
 
	}
 

	
 
	const SpriteGroup *ResolveReal(const RealSpriteGroup *group) const override;
 

	
 
	GrfSpecFeature GetFeature() const override;
 
	uint32 GetDebugID() const override;
 
};
 

	
 
enum StationClassID : byte {
 
	STAT_CLASS_BEGIN = 0,    ///< the lowest valid value
 
	STAT_CLASS_DFLT = 0,     ///< Default station class.
 
	STAT_CLASS_WAYP,         ///< Waypoint class.
src/spritecache.cpp
Show inline comments
 
@@ -143,12 +143,23 @@ uint GetOriginFileSlot(SpriteID sprite)
 
{
 
	if (!SpriteExists(sprite)) return 0;
 
	return GetSpriteCache(sprite)->file_slot;
 
}
 

	
 
/**
 
 * Get the GRF-local sprite id of a given sprite.
 
 * @param sprite The sprite to look at.
 
 * @return The GRF-local sprite id.
 
 */
 
uint32 GetSpriteLocalID(SpriteID sprite)
 
{
 
	if (!SpriteExists(sprite)) return 0;
 
	return GetSpriteCache(sprite)->id;
 
}
 

	
 
/**
 
 * Count the sprites which originate from a specific file slot in a range of SpriteIDs.
 
 * @param file_slot FIOS file slot.
 
 * @param begin First sprite in range.
 
 * @param end First sprite not in range.
 
 * @return Number of sprites.
 
 */
src/spritecache.h
Show inline comments
 
@@ -27,12 +27,13 @@ typedef void *AllocatorProc(size_t size)
 

	
 
void *GetRawSprite(SpriteID sprite, SpriteType type, AllocatorProc *allocator = nullptr);
 
bool SpriteExists(SpriteID sprite);
 

	
 
SpriteType GetSpriteType(SpriteID sprite);
 
uint GetOriginFileSlot(SpriteID sprite);
 
uint32 GetSpriteLocalID(SpriteID sprite);
 
uint GetSpriteCountForSlot(uint file_slot, SpriteID begin, SpriteID end);
 
uint GetMaxSpriteID();
 

	
 

	
 
static inline const Sprite *GetSprite(SpriteID sprite, SpriteType type)
 
{
0 comments (0 inline, 0 general)