Changeset - r24069:49625df81342
[Not reviewed]
docs/logging_and_performance_metrics.md
Show inline comments
 
@@ -99,3 +99,43 @@ The following is an explanation of the d
 
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
 
@@ -583,6 +583,7 @@
 
    <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" />
 
@@ -1236,6 +1237,7 @@
 
    <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" />
projects/openttd_vs140.vcxproj.filters
Show inline comments
 
@@ -837,6 +837,9 @@
 
    <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>
 
@@ -2796,6 +2799,9 @@
 
    <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>
projects/openttd_vs141.vcxproj
Show inline comments
 
@@ -583,6 +583,7 @@
 
    <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" />
 
@@ -1236,6 +1237,7 @@
 
    <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" />
projects/openttd_vs141.vcxproj.filters
Show inline comments
 
@@ -837,6 +837,9 @@
 
    <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>
 
@@ -2796,6 +2799,9 @@
 
    <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>
projects/openttd_vs142.vcxproj
Show inline comments
 
@@ -583,6 +583,7 @@
 
    <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" />
 
@@ -1236,6 +1237,7 @@
 
    <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" />
projects/openttd_vs142.vcxproj.filters
Show inline comments
 
@@ -837,6 +837,9 @@
 
    <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>
 
@@ -2796,6 +2799,9 @@
 
    <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>
source.list
Show inline comments
 
@@ -270,6 +270,7 @@ newgrf_house.h
 
newgrf_industries.h
 
newgrf_industrytiles.h
 
newgrf_object.h
 
newgrf_profiling.h
 
newgrf_properties.h
 
newgrf_railtype.h
 
newgrf_roadtype.h
 
@@ -986,6 +987,7 @@ newgrf_house.cpp
 
newgrf_industries.cpp
 
newgrf_industrytiles.cpp
 
newgrf_object.cpp
 
newgrf_profiling.cpp
 
newgrf_railtype.cpp
 
newgrf_roadtype.cpp
 
newgrf_sound.cpp
src/console_cmds.cpp
Show inline comments
 
@@ -33,6 +33,7 @@
 
#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"
 
@@ -1877,6 +1878,135 @@ DEF_CONSOLE_CMD(ConNewGRFReload)
 
	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
 
@@ -2056,4 +2186,5 @@ void IConsoleStdLibRegister()
 

	
 
	/* NewGRF development stuff */
 
	IConsoleCmdRegister("reload_newgrfs",  ConNewGRFReload, ConHookNewGRFDeveloperTool);
 
	IConsoleCmdRegister("newgrf_profile",  ConNewGRFProfile, ConHookNewGRFDeveloperTool);
 
}
src/date.cpp
Show inline comments
 
@@ -18,6 +18,7 @@
 
#include "rail_gui.h"
 
#include "linkgraph/linkgraph.h"
 
#include "saveload/saveload.h"
 
#include "newgrf_profiling.h"
 

	
 
#include "safeguards.h"
 

	
 
@@ -245,6 +246,10 @@ static void OnNewMonth()
 
 */
 
static void OnNewDay()
 
{
 
	if (!_newgrf_profilers.empty() && _newgrf_profile_end_date <= _date) {
 
		NewGRFProfiler::FinishAll();
 
	}
 

	
 
	if (_network_server) NetworkServerDailyLoop();
 

	
 
	DisasterDailyLoop();
src/misc.cpp
Show inline comments
 
@@ -29,6 +29,7 @@
 
#include "station_kdtree.h"
 
#include "town_kdtree.h"
 
#include "viewport_kdtree.h"
 
#include "newgrf_profiling.h"
 

	
 
#include "safeguards.h"
 

	
 
@@ -69,6 +70,8 @@ void InitializeGame(uint size_x, uint si
 
	_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();
src/newgrf.cpp
Show inline comments
 
@@ -66,6 +66,11 @@
 
/** 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;
 

	
 
@@ -5000,6 +5005,7 @@ static void NewSpriteGroup(ByteReader *b
 

	
 
			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;
 

	
 
@@ -5116,6 +5122,7 @@ static void NewSpriteGroup(ByteReader *b
 
		{
 
			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;
 

	
 
@@ -5164,6 +5171,7 @@ static void NewSpriteGroup(ByteReader *b
 

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

	
 
					group->num_loaded  = num_loaded;
 
@@ -5197,6 +5205,7 @@ static void NewSpriteGroup(ByteReader *b
 

	
 
					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 */
 
@@ -5212,6 +5221,7 @@ static void NewSpriteGroup(ByteReader *b
 

	
 
					assert(IndustryProductionSpriteGroup::CanAllocateItem());
 
					IndustryProductionSpriteGroup *group = new IndustryProductionSpriteGroup();
 
					group->nfo_line = _cur.nfo_line;
 
					act_group = group;
 
					group->version = type;
 
					if (type == 0) {
src/newgrf_airport.cpp
Show inline comments
 
@@ -58,6 +58,9 @@ struct AirportResolverObject : public Re
 
	}
 

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

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

	
 
/**
 
@@ -226,6 +229,16 @@ void AirportOverrideManager::SetEntitySp
 
	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
 
@@ -220,6 +220,16 @@ AirportTileResolverObject::AirportTileRe
 
	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);
src/newgrf_airporttiles.h
Show inline comments
 
@@ -22,6 +22,7 @@ struct AirportTileScopeResolver : public
 
	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.
 
@@ -30,7 +31,7 @@ struct AirportTileScopeResolver : public
 
	 * @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;
 
@@ -54,6 +55,9 @@ struct AirportTileResolverObject : publi
 
			default: return ResolverObject::GetScope(scope, relative);
 
		}
 
	}
 

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

	
 
/**
src/newgrf_canal.cpp
Show inline comments
 
@@ -13,6 +13,7 @@
 
#include "newgrf_canal.h"
 
#include "water.h"
 
#include "water_map.h"
 
#include "spritecache.h"
 

	
 
#include "safeguards.h"
 

	
 
@@ -35,6 +36,7 @@ struct CanalScopeResolver : public Scope
 
/** 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);
 
@@ -48,6 +50,9 @@ struct CanalResolverObject : public Reso
 
	}
 

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

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

	
 
/* virtual */ uint32 CanalScopeResolver::GetRandomBits() const
 
@@ -111,6 +116,16 @@ struct CanalResolverObject : public Reso
 
	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.
 
@@ -121,7 +136,7 @@ struct CanalResolverObject : public Reso
 
 */
 
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;
 
}
src/newgrf_cargo.cpp
Show inline comments
 
@@ -15,9 +15,14 @@
 

	
 
/** 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
 
@@ -30,6 +35,16 @@ struct CargoResolverObject : public Reso
 
	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.
 
@@ -38,7 +53,7 @@ struct CargoResolverObject : public Reso
 
 * @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;
 
}
src/newgrf_engine.cpp
Show inline comments
 
@@ -946,6 +946,22 @@ static uint32 VehicleGetVariable(Vehicle
 
	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.
src/newgrf_engine.h
Show inline comments
 
@@ -65,6 +65,9 @@ struct VehicleResolverObject : public Re
 
	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;
src/newgrf_generic.cpp
Show inline comments
 
@@ -29,6 +29,8 @@ struct GenericScopeResolver : public Sco
 
	uint8 count;
 
	uint8 station_size;
 

	
 
	uint8 feature;
 

	
 
	/**
 
	 * Generic scope resolver.
 
	 * @param ro Surrounding resolver.
 
@@ -36,7 +38,7 @@ struct GenericScopeResolver : public Sco
 
	 */
 
	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)
 
	{
 
	}
 

	
 
@@ -62,6 +64,16 @@ struct GenericResolverObject : public Re
 
	}
 

	
 
	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 {
 
@@ -226,6 +238,7 @@ uint16 GetAiPurchaseCallbackResult(uint8
 
	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);
 
@@ -247,6 +260,7 @@ void AmbientSoundEffectCallback(TileInde
 

	
 
	/* 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);
src/newgrf_house.cpp
Show inline comments
 
@@ -62,6 +62,16 @@ HouseResolverObject::HouseResolverObject
 
	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. */
src/newgrf_house.h
Show inline comments
 
@@ -64,6 +64,9 @@ struct HouseResolverObject : public Reso
 
			default: return ResolverObject::GetScope(scope, relative);
 
		}
 
	}
 

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

	
 
/**
src/newgrf_industries.cpp
Show inline comments
 
@@ -489,6 +489,16 @@ TownScopeResolver *IndustriesResolverObj
 
	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.
src/newgrf_industries.h
Show inline comments
 
@@ -63,6 +63,9 @@ struct IndustriesResolverObject : public
 
				return ResolverObject::GetScope(scope, relative);
 
		}
 
	}
 

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

	
 
/** When should the industry(tile) be triggered for random bits? */
src/newgrf_industrytiles.cpp
Show inline comments
 
@@ -139,11 +139,22 @@ IndustryTileResolverObject::IndustryTile
 
			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);
src/newgrf_industrytiles.h
Show inline comments
 
@@ -39,6 +39,7 @@ struct IndustryTileScopeResolver : publi
 
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);
 
@@ -51,6 +52,9 @@ struct IndustryTileResolverObject : publ
 
			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);
src/newgrf_object.cpp
Show inline comments
 
@@ -352,7 +352,7 @@ unhandled:
 
 */
 
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) ?
 
@@ -384,6 +384,16 @@ TownScopeResolver *ObjectResolverObject:
 
	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.
src/newgrf_object.h
Show inline comments
 
@@ -98,9 +98,10 @@ struct ObjectSpec {
 

	
 
/** 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.
 
@@ -109,8 +110,8 @@ struct ObjectScopeResolver : public Scop
 
	 * @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)
 
	{
 
	}
 

	
 
@@ -144,6 +145,9 @@ struct ObjectResolverObject : public Res
 
		}
 
	}
 

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

	
 
private:
 
	TownScopeResolver *GetTown();
 
};
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
 
@@ -65,6 +65,16 @@
 
	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.
 
@@ -75,7 +85,7 @@
 
 * @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;
 
}
src/newgrf_railtype.h
Show inline comments
 
@@ -18,6 +18,7 @@
 
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.
 
@@ -25,8 +26,8 @@ struct RailTypeScopeResolver : public Sc
 
	 * @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)
 
	{
 
	}
 

	
 
@@ -49,6 +50,9 @@ struct RailTypeResolverObject : public R
 
	}
 

	
 
	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);
src/newgrf_roadtype.cpp
Show inline comments
 
@@ -65,16 +65,32 @@
 
	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;
 
}
 

	
 
/**
 
@@ -87,7 +103,7 @@ RoadTypeScopeResolver::RoadTypeScopeReso
 
 * @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;
 
}
src/newgrf_roadtype.h
Show inline comments
 
@@ -18,8 +18,9 @@
 
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;
 
@@ -40,6 +41,9 @@ struct RoadTypeResolverObject : public R
 
	}
 

	
 
	/* 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);
src/newgrf_spritegroup.cpp
Show inline comments
 
@@ -11,6 +11,7 @@
 
#include <algorithm>
 
#include "debug.h"
 
#include "newgrf_spritegroup.h"
 
#include "newgrf_profiling.h"
 
#include "core/pool_func.hpp"
 

	
 
#include "safeguards.h"
 
@@ -34,10 +35,23 @@ TemporaryStorageArray<int32, 0x110> _tem
 
/* 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()
src/newgrf_spritegroup.h
Show inline comments
 
@@ -56,13 +56,14 @@ 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; }
 
@@ -398,6 +399,18 @@ struct ResolverObject {
 
		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
 
@@ -527,6 +527,16 @@ 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.
src/newgrf_station.h
Show inline comments
 
@@ -75,6 +75,9 @@ struct StationResolverObject : public Re
 
	}
 

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

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

	
 
enum StationClassID : byte {
src/spritecache.cpp
Show inline comments
 
@@ -146,6 +146,17 @@ uint GetOriginFileSlot(SpriteID sprite)
 
}
 

	
 
/**
 
 * 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.
src/spritecache.h
Show inline comments
 
@@ -30,6 +30,7 @@ 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();
 

	
0 comments (0 inline, 0 general)