Merge branch 'master' into jgrpp

# Conflicts:
#	src/console_cmds.cpp
#	src/date.cpp
#	src/economy.cpp
#	src/misc.cpp
#	src/newgrf_house.cpp
This commit is contained in:
Jonathan G Rennison
2020-01-29 19:32:06 +00:00
52 changed files with 787 additions and 84 deletions

View File

@@ -1,6 +1,6 @@
#!/bin/sh #!/bin/sh
tag=$(git describe --tags 2>/dev/null) tag=$(git name-rev --name-only --tags --no-undefined HEAD 2>/dev/null | sed 's@\^0$@@')
# If we are a tag, show the part of the changelog till (but excluding) the last stable # If we are a tag, show the part of the changelog till (but excluding) the last stable
if [ -n "$tag" ]; then if [ -n "$tag" ]; then
@@ -12,5 +12,5 @@ fi
# In all other cases, show the git log of the last 7 days # In all other cases, show the git log of the last 7 days
revdate=$(git log -1 --pretty=format:"%ci") revdate=$(git log -1 --pretty=format:"%ci")
last_week=$(date -u -d "$revdate -7days" +"%Y-%m-%d %H:%M") last_week=$(date -d "$revdate -7days" +"%Y-%m-%d %H:%M")
git log --after="${last_week}" --pretty=fuller git log --after="${last_week}" --pretty=fuller

View File

@@ -99,3 +99,43 @@ The following is an explanation of the different statistics:
If the frame rate window is shaded, the title bar will instead show just the If the frame rate window is shaded, the title bar will instead show just the
current simulation rate and the game speed factor. 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.

View File

@@ -602,6 +602,7 @@
<ClInclude Include="..\src\newgrf_industries.h" /> <ClInclude Include="..\src\newgrf_industries.h" />
<ClInclude Include="..\src\newgrf_industrytiles.h" /> <ClInclude Include="..\src\newgrf_industrytiles.h" />
<ClInclude Include="..\src\newgrf_object.h" /> <ClInclude Include="..\src\newgrf_object.h" />
<ClInclude Include="..\src\newgrf_profiling.h" />
<ClInclude Include="..\src\newgrf_properties.h" /> <ClInclude Include="..\src\newgrf_properties.h" />
<ClInclude Include="..\src\newgrf_railtype.h" /> <ClInclude Include="..\src\newgrf_railtype.h" />
<ClInclude Include="..\src\newgrf_roadtype.h" /> <ClInclude Include="..\src\newgrf_roadtype.h" />
@@ -1291,6 +1292,7 @@
<ClCompile Include="..\src\newgrf_industries.cpp" /> <ClCompile Include="..\src\newgrf_industries.cpp" />
<ClCompile Include="..\src\newgrf_industrytiles.cpp" /> <ClCompile Include="..\src\newgrf_industrytiles.cpp" />
<ClCompile Include="..\src\newgrf_object.cpp" /> <ClCompile Include="..\src\newgrf_object.cpp" />
<ClCompile Include="..\src\newgrf_profiling.cpp" />
<ClCompile Include="..\src\newgrf_railtype.cpp" /> <ClCompile Include="..\src\newgrf_railtype.cpp" />
<ClCompile Include="..\src\newgrf_roadtype.cpp" /> <ClCompile Include="..\src\newgrf_roadtype.cpp" />
<ClCompile Include="..\src\newgrf_sound.cpp" /> <ClCompile Include="..\src\newgrf_sound.cpp" />

View File

@@ -900,6 +900,9 @@
<ClInclude Include="..\src\newgrf_object.h"> <ClInclude Include="..\src\newgrf_object.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\src\newgrf_profiling.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\src\newgrf_properties.h"> <ClInclude Include="..\src\newgrf_properties.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
@@ -2967,6 +2970,9 @@
<ClCompile Include="..\src\newgrf_object.cpp"> <ClCompile Include="..\src\newgrf_object.cpp">
<Filter>NewGRF</Filter> <Filter>NewGRF</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\src\newgrf_profiling.cpp">
<Filter>NewGRF</Filter>
</ClCompile>
<ClCompile Include="..\src\newgrf_railtype.cpp"> <ClCompile Include="..\src\newgrf_railtype.cpp">
<Filter>NewGRF</Filter> <Filter>NewGRF</Filter>
</ClCompile> </ClCompile>

View File

@@ -602,6 +602,7 @@
<ClInclude Include="..\src\newgrf_industries.h" /> <ClInclude Include="..\src\newgrf_industries.h" />
<ClInclude Include="..\src\newgrf_industrytiles.h" /> <ClInclude Include="..\src\newgrf_industrytiles.h" />
<ClInclude Include="..\src\newgrf_object.h" /> <ClInclude Include="..\src\newgrf_object.h" />
<ClInclude Include="..\src\newgrf_profiling.h" />
<ClInclude Include="..\src\newgrf_properties.h" /> <ClInclude Include="..\src\newgrf_properties.h" />
<ClInclude Include="..\src\newgrf_railtype.h" /> <ClInclude Include="..\src\newgrf_railtype.h" />
<ClInclude Include="..\src\newgrf_roadtype.h" /> <ClInclude Include="..\src\newgrf_roadtype.h" />
@@ -1291,6 +1292,7 @@
<ClCompile Include="..\src\newgrf_industries.cpp" /> <ClCompile Include="..\src\newgrf_industries.cpp" />
<ClCompile Include="..\src\newgrf_industrytiles.cpp" /> <ClCompile Include="..\src\newgrf_industrytiles.cpp" />
<ClCompile Include="..\src\newgrf_object.cpp" /> <ClCompile Include="..\src\newgrf_object.cpp" />
<ClCompile Include="..\src\newgrf_profiling.cpp" />
<ClCompile Include="..\src\newgrf_railtype.cpp" /> <ClCompile Include="..\src\newgrf_railtype.cpp" />
<ClCompile Include="..\src\newgrf_roadtype.cpp" /> <ClCompile Include="..\src\newgrf_roadtype.cpp" />
<ClCompile Include="..\src\newgrf_sound.cpp" /> <ClCompile Include="..\src\newgrf_sound.cpp" />

View File

@@ -900,6 +900,9 @@
<ClInclude Include="..\src\newgrf_object.h"> <ClInclude Include="..\src\newgrf_object.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\src\newgrf_profiling.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\src\newgrf_properties.h"> <ClInclude Include="..\src\newgrf_properties.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
@@ -2967,6 +2970,9 @@
<ClCompile Include="..\src\newgrf_object.cpp"> <ClCompile Include="..\src\newgrf_object.cpp">
<Filter>NewGRF</Filter> <Filter>NewGRF</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\src\newgrf_profiling.cpp">
<Filter>NewGRF</Filter>
</ClCompile>
<ClCompile Include="..\src\newgrf_railtype.cpp"> <ClCompile Include="..\src\newgrf_railtype.cpp">
<Filter>NewGRF</Filter> <Filter>NewGRF</Filter>
</ClCompile> </ClCompile>

View File

@@ -602,6 +602,7 @@
<ClInclude Include="..\src\newgrf_industries.h" /> <ClInclude Include="..\src\newgrf_industries.h" />
<ClInclude Include="..\src\newgrf_industrytiles.h" /> <ClInclude Include="..\src\newgrf_industrytiles.h" />
<ClInclude Include="..\src\newgrf_object.h" /> <ClInclude Include="..\src\newgrf_object.h" />
<ClInclude Include="..\src\newgrf_profiling.h" />
<ClInclude Include="..\src\newgrf_properties.h" /> <ClInclude Include="..\src\newgrf_properties.h" />
<ClInclude Include="..\src\newgrf_railtype.h" /> <ClInclude Include="..\src\newgrf_railtype.h" />
<ClInclude Include="..\src\newgrf_roadtype.h" /> <ClInclude Include="..\src\newgrf_roadtype.h" />
@@ -1291,6 +1292,7 @@
<ClCompile Include="..\src\newgrf_industries.cpp" /> <ClCompile Include="..\src\newgrf_industries.cpp" />
<ClCompile Include="..\src\newgrf_industrytiles.cpp" /> <ClCompile Include="..\src\newgrf_industrytiles.cpp" />
<ClCompile Include="..\src\newgrf_object.cpp" /> <ClCompile Include="..\src\newgrf_object.cpp" />
<ClCompile Include="..\src\newgrf_profiling.cpp" />
<ClCompile Include="..\src\newgrf_railtype.cpp" /> <ClCompile Include="..\src\newgrf_railtype.cpp" />
<ClCompile Include="..\src\newgrf_roadtype.cpp" /> <ClCompile Include="..\src\newgrf_roadtype.cpp" />
<ClCompile Include="..\src\newgrf_sound.cpp" /> <ClCompile Include="..\src\newgrf_sound.cpp" />

View File

@@ -900,6 +900,9 @@
<ClInclude Include="..\src\newgrf_object.h"> <ClInclude Include="..\src\newgrf_object.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\src\newgrf_profiling.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\src\newgrf_properties.h"> <ClInclude Include="..\src\newgrf_properties.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
@@ -2967,6 +2970,9 @@
<ClCompile Include="..\src\newgrf_object.cpp"> <ClCompile Include="..\src\newgrf_object.cpp">
<Filter>NewGRF</Filter> <Filter>NewGRF</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\src\newgrf_profiling.cpp">
<Filter>NewGRF</Filter>
</ClCompile>
<ClCompile Include="..\src\newgrf_railtype.cpp"> <ClCompile Include="..\src\newgrf_railtype.cpp">
<Filter>NewGRF</Filter> <Filter>NewGRF</Filter>
</ClCompile> </ClCompile>

View File

@@ -290,6 +290,7 @@ newgrf_house.h
newgrf_industries.h newgrf_industries.h
newgrf_industrytiles.h newgrf_industrytiles.h
newgrf_object.h newgrf_object.h
newgrf_profiling.h
newgrf_properties.h newgrf_properties.h
newgrf_railtype.h newgrf_railtype.h
newgrf_roadtype.h newgrf_roadtype.h
@@ -1042,6 +1043,7 @@ newgrf_house.cpp
newgrf_industries.cpp newgrf_industries.cpp
newgrf_industrytiles.cpp newgrf_industrytiles.cpp
newgrf_object.cpp newgrf_object.cpp
newgrf_profiling.cpp
newgrf_railtype.cpp newgrf_railtype.cpp
newgrf_roadtype.cpp newgrf_roadtype.cpp
newgrf_sound.cpp newgrf_sound.cpp

View File

@@ -33,6 +33,7 @@
#include "ai/ai.hpp" #include "ai/ai.hpp"
#include "ai/ai_config.hpp" #include "ai/ai_config.hpp"
#include "newgrf.h" #include "newgrf.h"
#include "newgrf_profiling.h"
#include "console_func.h" #include "console_func.h"
#include "engine_base.h" #include "engine_base.h"
#include "game/game.hpp" #include "game/game.hpp"
@@ -2267,6 +2268,135 @@ DEF_CONSOLE_CMD(ConDeleteCompany)
return true; 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 #ifdef _DEBUG
/****************** /******************
* debug commands * debug commands
@@ -2465,6 +2595,7 @@ void IConsoleStdLibRegister()
/* NewGRF development stuff */ /* NewGRF development stuff */
IConsoleCmdRegister("reload_newgrfs", ConNewGRFReload, ConHookNewGRFDeveloperTool); IConsoleCmdRegister("reload_newgrfs", ConNewGRFReload, ConHookNewGRFDeveloperTool);
IConsoleCmdRegister("newgrf_profile", ConNewGRFProfile, ConHookNewGRFDeveloperTool);
IConsoleCmdRegister("do_disaster", ConDoDisaster, ConHookNewGRFDeveloperTool, true); IConsoleCmdRegister("do_disaster", ConDoDisaster, ConHookNewGRFDeveloperTool, true);
IConsoleCmdRegister("bankrupt_company", ConBankruptCompany, ConHookNewGRFDeveloperTool, true); IConsoleCmdRegister("bankrupt_company", ConBankruptCompany, ConHookNewGRFDeveloperTool, true);
IConsoleCmdRegister("delete_company", ConDeleteCompany, ConHookNewGRFDeveloperTool, true); IConsoleCmdRegister("delete_company", ConDeleteCompany, ConHookNewGRFDeveloperTool, true);

View File

@@ -18,6 +18,7 @@
#include "rail_gui.h" #include "rail_gui.h"
#include "linkgraph/linkgraph.h" #include "linkgraph/linkgraph.h"
#include "saveload/saveload.h" #include "saveload/saveload.h"
#include "newgrf_profiling.h"
#include "console_func.h" #include "console_func.h"
#include "debug.h" #include "debug.h"
@@ -266,6 +267,10 @@ static void OnNewMonth()
*/ */
static void OnNewDay() static void OnNewDay()
{ {
if (!_newgrf_profilers.empty() && _newgrf_profile_end_date <= _date) {
NewGRFProfiler::FinishAll();
}
if (_network_server) NetworkServerDailyLoop(); if (_network_server) NetworkServerDailyLoop();
DisasterDailyLoop(); DisasterDailyLoop();

View File

@@ -1263,15 +1263,14 @@ void CargoPayment::PayFinalDelivery(CargoPacket *cp, uint count)
*/ */
Money CargoPayment::PayTransfer(CargoPacket *cp, uint count) Money CargoPayment::PayTransfer(CargoPacket *cp, uint count)
{ {
Money profit = GetTransportedGoodsIncome( Money profit = -cp->FeederShare(count) + GetTransportedGoodsIncome(
count, count,
/* pay transfer vehicle for only the part of transfer it has done: ie. cargo_loaded_at_xy to here */ /* pay transfer vehicle the difference between the payment for the journey from
DistanceManhattan(_settings_game.economy.feeder_payment_src_station ? cp->SourceStationXY() : cp->LoadedAtXY(), Station::Get(this->current_station)->xy), * the source to the current point, and the sum of the previous transfer payments */
DistanceManhattan(cp->SourceStationXY(), Station::Get(this->current_station)->xy),
cp->DaysInTransit(), cp->DaysInTransit(),
this->ct); this->ct);
if (_settings_game.economy.feeder_payment_src_station) profit -= cp->FeederShare(count);
profit = profit * _settings_game.economy.feeder_payment_share / 100; profit = profit * _settings_game.economy.feeder_payment_share / 100;
/* For Infrastructure patch. Handling transfers between other companies */ /* For Infrastructure patch. Handling transfers between other companies */

View File

@@ -1708,8 +1708,6 @@ STR_CONFIG_SETTING_MIN_YEARS_FOR_SHARES :Minimum company
STR_CONFIG_SETTING_MIN_YEARS_FOR_SHARES_HELPTEXT :Set the minimum age of a company for others to be able to buy and sell shares from them. STR_CONFIG_SETTING_MIN_YEARS_FOR_SHARES_HELPTEXT :Set the minimum age of a company for others to be able to buy and sell shares from them.
STR_CONFIG_SETTING_FEEDER_PAYMENT_SHARE :Percentage of leg profit to pay in feeder systems: {STRING2} STR_CONFIG_SETTING_FEEDER_PAYMENT_SHARE :Percentage of leg profit to pay in feeder systems: {STRING2}
STR_CONFIG_SETTING_FEEDER_PAYMENT_SHARE_HELPTEXT :Percentage of income given to the intermediate legs in feeder systems, giving more control over the income STR_CONFIG_SETTING_FEEDER_PAYMENT_SHARE_HELPTEXT :Percentage of income given to the intermediate legs in feeder systems, giving more control over the income
STR_CONFIG_SETTING_FEEDER_PAYMENT_SRC_STATION :Calculate leg profit relative to source station in feeder systems: {STRING2}
STR_CONFIG_SETTING_FEEDER_PAYMENT_SRC_STATION_HELPTEXT :When enabled, the calculation of leg profit in feeder systems is from the source station to the current point, minus any previous transfer payments, instead of calculating the current leg profit as an independent journey
STR_CONFIG_SETTING_SIMULATE_SIGNALS :Simulate signals in tunnels, bridges every: {STRING2} STR_CONFIG_SETTING_SIMULATE_SIGNALS :Simulate signals in tunnels, bridges every: {STRING2}
STR_CONFIG_SETTING_SIMULATE_SIGNALS_VALUE :{COMMA} tile{P 0 "" s} STR_CONFIG_SETTING_SIMULATE_SIGNALS_VALUE :{COMMA} tile{P 0 "" s}
STR_CONFIG_SETTING_DAY_LENGTH_FACTOR :Day length factor: {STRING2} STR_CONFIG_SETTING_DAY_LENGTH_FACTOR :Day length factor: {STRING2}

View File

@@ -1646,8 +1646,6 @@ STR_CONFIG_SETTING_ALLOW_SHARES :Handel mit Firm
STR_CONFIG_SETTING_ALLOW_SHARES_HELPTEXT :Erlaube das Kaufen und Verkaufen von Firmenanteilen. Firmenanteile sind nur verfügbar für Firmen, die hinreichend lange existieren STR_CONFIG_SETTING_ALLOW_SHARES_HELPTEXT :Erlaube das Kaufen und Verkaufen von Firmenanteilen. Firmenanteile sind nur verfügbar für Firmen, die hinreichend lange existieren
STR_CONFIG_SETTING_FEEDER_PAYMENT_SHARE :Prozentsatz des Profits für Teilstrecken: {STRING} STR_CONFIG_SETTING_FEEDER_PAYMENT_SHARE :Prozentsatz des Profits für Teilstrecken: {STRING}
STR_CONFIG_SETTING_FEEDER_PAYMENT_SHARE_HELPTEXT :Um das Einkommen der einzelnen Fahrzeuge einer Lieferkette ungefähr abschätzen zu können, wird vom Transporterlös bei Ablieferung einer Fracht der gewählte Prozentsatz den Zulieferfahrzeugen zugeschlagen STR_CONFIG_SETTING_FEEDER_PAYMENT_SHARE_HELPTEXT :Um das Einkommen der einzelnen Fahrzeuge einer Lieferkette ungefähr abschätzen zu können, wird vom Transporterlös bei Ablieferung einer Fracht der gewählte Prozentsatz den Zulieferfahrzeugen zugeschlagen
STR_CONFIG_SETTING_FEEDER_PAYMENT_SRC_STATION :Kalkuliere Profit für Teilstrecken relativ zur Ursprungsstation: {STRING}
STR_CONFIG_SETTING_FEEDER_PAYMENT_SRC_STATION_HELPTEXT :Wenn aktiviert, wird der Profit für Teilstrecken von der Ursprungsstation bis zum aktuellen Punkt, abzüglich der zuvor gezahlten Transfer-Einnahmen, berechnet, anstatt Teilstrecken als eigenständige Fahrten zu berechnen.
STR_CONFIG_SETTING_SIMULATE_SIGNALS :Simuliere Signale in Tunneln und Brücken aller: {STRING} STR_CONFIG_SETTING_SIMULATE_SIGNALS :Simuliere Signale in Tunneln und Brücken aller: {STRING}
STR_CONFIG_SETTING_SIMULATE_SIGNALS_VALUE :{COMMA} Kachel{P 0 "" n} STR_CONFIG_SETTING_SIMULATE_SIGNALS_VALUE :{COMMA} Kachel{P 0 "" n}
STR_CONFIG_SETTING_DAY_LENGTH_FACTOR :Faktor für Tageslänge: {STRING} STR_CONFIG_SETTING_DAY_LENGTH_FACTOR :Faktor für Tageslänge: {STRING}

View File

@@ -3297,6 +3297,7 @@ STR_COMPANY_INFRASTRUCTURE_VIEW_CAPTION :{WHITE}Infrastr
STR_COMPANY_INFRASTRUCTURE_VIEW_RAIL_SECT :{GOLD}Bagian rel: STR_COMPANY_INFRASTRUCTURE_VIEW_RAIL_SECT :{GOLD}Bagian rel:
STR_COMPANY_INFRASTRUCTURE_VIEW_SIGNALS :{WHITE}Sinyal STR_COMPANY_INFRASTRUCTURE_VIEW_SIGNALS :{WHITE}Sinyal
STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD_SECT :{GOLD}Bagian jalan: STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD_SECT :{GOLD}Bagian jalan:
STR_COMPANY_INFRASTRUCTURE_VIEW_TRAM_SECT :{GOLD}Bagian Trem:
STR_COMPANY_INFRASTRUCTURE_VIEW_WATER_SECT :{GOLD}Perairan: STR_COMPANY_INFRASTRUCTURE_VIEW_WATER_SECT :{GOLD}Perairan:
STR_COMPANY_INFRASTRUCTURE_VIEW_CANALS :{WHITE}Kanal STR_COMPANY_INFRASTRUCTURE_VIEW_CANALS :{WHITE}Kanal
STR_COMPANY_INFRASTRUCTURE_VIEW_STATION_SECT :{GOLD}Stasiun: STR_COMPANY_INFRASTRUCTURE_VIEW_STATION_SECT :{GOLD}Stasiun:

View File

@@ -1708,8 +1708,6 @@ STR_CONFIG_SETTING_MIN_YEARS_FOR_SHARES :지분 거래
STR_CONFIG_SETTING_MIN_YEARS_FOR_SHARES_HELPTEXT :지분을 사고 팔기 위해 필요한 회사의 최소 나이를 설정합니다. STR_CONFIG_SETTING_MIN_YEARS_FOR_SHARES_HELPTEXT :지분을 사고 팔기 위해 필요한 회사의 최소 나이를 설정합니다.
STR_CONFIG_SETTING_FEEDER_PAYMENT_SHARE :환승시 벌어들이는 중간 수익의 비율: {STRING} STR_CONFIG_SETTING_FEEDER_PAYMENT_SHARE :환승시 벌어들이는 중간 수익의 비율: {STRING}
STR_CONFIG_SETTING_FEEDER_PAYMENT_SHARE_HELPTEXT :더 많은 수익을 내기 위해, 수송 관계상 중간 구간에게 주어진 수익의 비율을 설정합니다. STR_CONFIG_SETTING_FEEDER_PAYMENT_SHARE_HELPTEXT :더 많은 수익을 내기 위해, 수송 관계상 중간 구간에게 주어진 수익의 비율을 설정합니다.
STR_CONFIG_SETTING_FEEDER_PAYMENT_SRC_STATION :환승시 출발 역에 대한 중간 수익을 계산: {STRING}
STR_CONFIG_SETTING_FEEDER_PAYMENT_SRC_STATION_HELPTEXT :이 설정을 켜면, 현재의 환승시 중간 수익 계산을 각 여정 별로 계산하지 않고, 이전 환승 비용을 제외하고 출발역으로부터 현 지점까지 기준으로 계산합니다.
STR_CONFIG_SETTING_SIMULATE_SIGNALS :다리와 터널에서 {STRING}마다 신호기를 설치한 것으로 계산 STR_CONFIG_SETTING_SIMULATE_SIGNALS :다리와 터널에서 {STRING}마다 신호기를 설치한 것으로 계산
STR_CONFIG_SETTING_SIMULATE_SIGNALS_VALUE :{COMMA} 칸 STR_CONFIG_SETTING_SIMULATE_SIGNALS_VALUE :{COMMA} 칸
STR_CONFIG_SETTING_DAY_LENGTH_FACTOR :1일의 길이 조절: {STRING} STR_CONFIG_SETTING_DAY_LENGTH_FACTOR :1일의 길이 조절: {STRING}

View File

@@ -938,6 +938,7 @@ STR_GAME_OPTIONS_LANGUAGE :{BLACK}மொ
STR_GAME_OPTIONS_LANGUAGE_TOOLTIP :{BLACK}பயன்படுத்தப்போகும் மொழியினை தேர்ந்தெடு STR_GAME_OPTIONS_LANGUAGE_TOOLTIP :{BLACK}பயன்படுத்தப்போகும் மொழியினை தேர்ந்தெடு
STR_GAME_OPTIONS_FULLSCREEN :{BLACK}முழு படம் STR_GAME_OPTIONS_FULLSCREEN :{BLACK}முழு படம்
STR_GAME_OPTIONS_FULLSCREEN_TOOLTIP :{BLACK}OpenTTD-ஐ முழுத்திரையில் விளையாட இந்த கட்டத்தினை சொடுக்கவும்
STR_GAME_OPTIONS_RESOLUTION :{BLACK}திரையின் அளவு STR_GAME_OPTIONS_RESOLUTION :{BLACK}திரையின் அளவு
STR_GAME_OPTIONS_RESOLUTION_TOOLTIP :{BLACK}திரை அளவினைத் தேர்ந்தெடுக்கவும் STR_GAME_OPTIONS_RESOLUTION_TOOLTIP :{BLACK}திரை அளவினைத் தேர்ந்தெடுக்கவும்
@@ -977,6 +978,7 @@ STR_CURRENCY_INCREASE_EXCHANGE_RATE_TOOLTIP :{BLACK}உங
STR_CURRENCY_SET_EXCHANGE_RATE_TOOLTIP :{BLACK}உங்களது நாணயத்தின் நாணயமாற்று விகிதத்தை ஒரு பவுண்டாக (£) அமைக்கவும் STR_CURRENCY_SET_EXCHANGE_RATE_TOOLTIP :{BLACK}உங்களது நாணயத்தின் நாணயமாற்று விகிதத்தை ஒரு பவுண்டாக (£) அமைக்கவும்
STR_CURRENCY_SEPARATOR :{LTBLUE}பிரிப்பான்: {ORANGE}{STRING} STR_CURRENCY_SEPARATOR :{LTBLUE}பிரிப்பான்: {ORANGE}{STRING}
STR_CURRENCY_SET_CUSTOM_CURRENCY_SEPARATOR_TOOLTIP :{BLACK}உங்களது நாணயத்தின் பிரியியினை அமை
STR_CURRENCY_PREFIX :{LTBLUE}முன் ஒட்டு: {ORANGE}{STRING} STR_CURRENCY_PREFIX :{LTBLUE}முன் ஒட்டு: {ORANGE}{STRING}
STR_CURRENCY_SET_CUSTOM_CURRENCY_PREFIX_TOOLTIP :{BLACK}உங்கள் நாணயத்தின் முன் ஒட்டத்தினை அமையுங்கள் STR_CURRENCY_SET_CUSTOM_CURRENCY_PREFIX_TOOLTIP :{BLACK}உங்கள் நாணயத்தின் முன் ஒட்டத்தினை அமையுங்கள்
@@ -1275,6 +1277,7 @@ STR_CONFIG_SETTING_COMMAND_PAUSE_LEVEL_ALL_NON_LANDSCAPING :அனைத்
STR_CONFIG_SETTING_COMMAND_PAUSE_LEVEL_ALL_ACTIONS :அனைத்து செயல்கள் STR_CONFIG_SETTING_COMMAND_PAUSE_LEVEL_ALL_ACTIONS :அனைத்து செயல்கள்
STR_CONFIG_SETTING_ADVANCED_VEHICLE_LISTS :வாகனப் பட்டியலினைப் பயன்படுத்தவும்: {STRING} STR_CONFIG_SETTING_ADVANCED_VEHICLE_LISTS :வாகனப் பட்டியலினைப் பயன்படுத்தவும்: {STRING}
STR_CONFIG_SETTING_LOADING_INDICATORS_HELPTEXT :வாகனங்களை ஏற்றுவதற்கு அல்லது இறக்குவதற்கு மேலே ஏற்றுதல் குறிகாட்டிகள் காட்டப்படுகிறதா என்பதைத் தேர்ந்தெடுக்கவும் STR_CONFIG_SETTING_LOADING_INDICATORS_HELPTEXT :வாகனங்களை ஏற்றுவதற்கு அல்லது இறக்குவதற்கு மேலே ஏற்றுதல் குறிகாட்டிகள் காட்டப்படுகிறதா என்பதைத் தேர்ந்தெடுக்கவும்
STR_CONFIG_SETTING_TIMETABLE_IN_TICKS :கால அட்டவணையை நாட்களில் அல்லாமல் சொடுக்குகளில் காட்டு: {STRING}
STR_CONFIG_SETTING_TIMETABLE_SHOW_ARRIVAL_DEPARTURE :கால அட்டவணைகளில் காலங்களைக் காட்டவும்: {STRING} STR_CONFIG_SETTING_TIMETABLE_SHOW_ARRIVAL_DEPARTURE :கால அட்டவணைகளில் காலங்களைக் காட்டவும்: {STRING}
STR_CONFIG_SETTING_QUICKGOTO :வாகன கட்டளைகளை விரிவாக உருவாக்கவும்: {STRING} STR_CONFIG_SETTING_QUICKGOTO :வாகன கட்டளைகளை விரிவாக உருவாக்கவும்: {STRING}
STR_CONFIG_SETTING_DEFAULT_RAIL_TYPE_FIRST :முதலில் கிடைக்கும் STR_CONFIG_SETTING_DEFAULT_RAIL_TYPE_FIRST :முதலில் கிடைக்கும்
@@ -1365,6 +1368,7 @@ STR_CONFIG_SETTING_COLOURED_NEWS_YEAR :நிற ச
STR_CONFIG_SETTING_STARTING_YEAR :தொடங்கும் வருடம்: {STRING} STR_CONFIG_SETTING_STARTING_YEAR :தொடங்கும் வருடம்: {STRING}
STR_CONFIG_SETTING_SMOOTH_ECONOMY :இயல்பான பொருளாதாரத்தினைச் செயல்படுத்தவும் (அதிகமான, சிறிய மாற்றங்கள்): {STRING} STR_CONFIG_SETTING_SMOOTH_ECONOMY :இயல்பான பொருளாதாரத்தினைச் செயல்படுத்தவும் (அதிகமான, சிறிய மாற்றங்கள்): {STRING}
STR_CONFIG_SETTING_ALLOW_SHARES :மற்ற நிறுவனங்களின் பங்குகளை வாங்குவதை அனுமதிக்கவும்: {STRING} STR_CONFIG_SETTING_ALLOW_SHARES :மற்ற நிறுவனங்களின் பங்குகளை வாங்குவதை அனுமதிக்கவும்: {STRING}
STR_CONFIG_SETTING_MIN_YEARS_FOR_SHARES :பங்குகள் பரிமாற்றத்திற்கு தேவையான குறைந்தபட்ச நிறுவன வயது: {STRING}
STR_CONFIG_SETTING_DRAG_SIGNALS_DENSITY :இழுத்தால், சிக்னல்களை இடவும், ஒவ்வொறு: {STRING} STR_CONFIG_SETTING_DRAG_SIGNALS_DENSITY :இழுத்தால், சிக்னல்களை இடவும், ஒவ்வொறு: {STRING}
STR_CONFIG_SETTING_DRAG_SIGNALS_DENSITY_VALUE :{COMMA} கட்ட{P 0 "ம்" ங்கள்} STR_CONFIG_SETTING_DRAG_SIGNALS_DENSITY_VALUE :{COMMA} கட்ட{P 0 "ம்" ங்கள்}
STR_CONFIG_SETTING_DRAG_SIGNALS_FIXED_DISTANCE :இழுக்கும்போது, சிக்னல்களுக்கு இடையே சீரான இடைவேளியினை விடவும்: {STRING} STR_CONFIG_SETTING_DRAG_SIGNALS_FIXED_DISTANCE :இழுக்கும்போது, சிக்னல்களுக்கு இடையே சீரான இடைவேளியினை விடவும்: {STRING}
@@ -1432,6 +1436,7 @@ STR_CONFIG_SETTING_CITY_SIZE_MULTIPLIER :தொடக்
STR_CONFIG_SETTING_CITY_SIZE_MULTIPLIER_HELPTEXT :ஆட்டத்தின் தொடக்கத்தில் மாநகரங்களின் அளவு நகரங்களை ஒப்பிடுகையில் STR_CONFIG_SETTING_CITY_SIZE_MULTIPLIER_HELPTEXT :ஆட்டத்தின் தொடக்கத்தில் மாநகரங்களின் அளவு நகரங்களை ஒப்பிடுகையில்
STR_CONFIG_SETTING_DISTRIBUTION_MANUAL :கைமுறை STR_CONFIG_SETTING_DISTRIBUTION_MANUAL :கைமுறை
STR_CONFIG_SETTING_DISTRIBUTION_ASYMMETRIC :சமச்சீர்மையிலா
STR_CONFIG_SETTING_DISTRIBUTION_SYMMETRIC :சமச்சீரான STR_CONFIG_SETTING_DISTRIBUTION_SYMMETRIC :சமச்சீரான
STR_CONFIG_SETTING_DISTRIBUTION_PAX :பயணிகள் பரிமாற்றம் வகை: {STRING} STR_CONFIG_SETTING_DISTRIBUTION_PAX :பயணிகள் பரிமாற்றம் வகை: {STRING}
STR_CONFIG_SETTING_DISTRIBUTION_MAIL :அஞ்சல் பரிமாற்றம் வகை: {STRING} STR_CONFIG_SETTING_DISTRIBUTION_MAIL :அஞ்சல் பரிமாற்றம் வகை: {STRING}
@@ -1470,6 +1475,7 @@ STR_CONFIG_SETTING_SOUND :{ORANGE}ஒல
STR_CONFIG_SETTING_INTERFACE :{ORANGE}Interface STR_CONFIG_SETTING_INTERFACE :{ORANGE}Interface
STR_CONFIG_SETTING_INTERFACE_GENERAL :{ORANGE} பொதுவான STR_CONFIG_SETTING_INTERFACE_GENERAL :{ORANGE} பொதுவான
STR_CONFIG_SETTING_INTERFACE_CONSTRUCTION :{ORANGE}கட்டுமானம் STR_CONFIG_SETTING_INTERFACE_CONSTRUCTION :{ORANGE}கட்டுமானம்
STR_CONFIG_SETTING_ADVISORS :{ORANGE}செய்திகள் / அறிவுரைஞர்கள்
STR_CONFIG_SETTING_COMPANY :{ORANGE}நிறுவனம் STR_CONFIG_SETTING_COMPANY :{ORANGE}நிறுவனம்
STR_CONFIG_SETTING_ACCOUNTING :{ORANGE}கணக்கியல் STR_CONFIG_SETTING_ACCOUNTING :{ORANGE}கணக்கியல்
STR_CONFIG_SETTING_VEHICLES :{ORANGE}வாகனங்கள் STR_CONFIG_SETTING_VEHICLES :{ORANGE}வாகனங்கள்
@@ -1503,6 +1509,7 @@ STR_CONFIG_ERROR_ARRAY :{WHITE}... '{ST
STR_CONFIG_ERROR_INVALID_VALUE :{WHITE}... செல்லாத மதிப்பு '{STRING}' '{STRING}' இற்கு STR_CONFIG_ERROR_INVALID_VALUE :{WHITE}... செல்லாத மதிப்பு '{STRING}' '{STRING}' இற்கு
STR_CONFIG_ERROR_INVALID_GRF :{WHITE}... பயன்படுத்த இயலாத NewGRF இனை பயன்படுத்தவில்லை '{STRING}': {STRING} STR_CONFIG_ERROR_INVALID_GRF :{WHITE}... பயன்படுத்த இயலாத NewGRF இனை பயன்படுத்தவில்லை '{STRING}': {STRING}
STR_CONFIG_ERROR_INVALID_GRF_NOT_FOUND :கிடைக்கவில்லை STR_CONFIG_ERROR_INVALID_GRF_NOT_FOUND :கிடைக்கவில்லை
STR_CONFIG_ERROR_INVALID_GRF_UNSAFE :நிலையான பயன்பாட்டிற்கு உகந்தது அல்ல
STR_CONFIG_ERROR_INVALID_GRF_SYSTEM :கணினி NewGRF STR_CONFIG_ERROR_INVALID_GRF_SYSTEM :கணினி NewGRF
STR_CONFIG_ERROR_INVALID_GRF_INCOMPATIBLE :இந்த OpenTTD பதிப்புடன் பயன்படுத்த இயலாது STR_CONFIG_ERROR_INVALID_GRF_INCOMPATIBLE :இந்த OpenTTD பதிப்புடன் பயன்படுத்த இயலாது
STR_CONFIG_ERROR_INVALID_GRF_UNKNOWN :தெரியவில்லை STR_CONFIG_ERROR_INVALID_GRF_UNKNOWN :தெரியவில்லை
@@ -2405,7 +2412,9 @@ STR_FRAMERATE_BYTES_GOOD :{LTBLUE}{BYTES}
STR_FRAMERATE_BYTES_WARN :{YELLOW}{BYTES} STR_FRAMERATE_BYTES_WARN :{YELLOW}{BYTES}
STR_FRAMERATE_BYTES_BAD :{RED}{BYTES} STR_FRAMERATE_BYTES_BAD :{RED}{BYTES}
############ Leave those lines in this order!! ############ Leave those lines in this order!!
STR_FRAMERATE_GL_LANDSCAPE :{BLACK} உலக சொடுக்குகள்:
STR_FRAMERATE_GL_LINKGRAPH :{BLACK} இணைப்பு வரைபட தாமதம்: STR_FRAMERATE_GL_LINKGRAPH :{BLACK} இணைப்பு வரைபட தாமதம்:
STR_FRAMERATE_SOUND :{BLACK}இசை இயக்கம்:
STR_FRAMERATE_ALLSCRIPTS :{BLACK} GS/AI மொத்தம்: STR_FRAMERATE_ALLSCRIPTS :{BLACK} GS/AI மொத்தம்:
############ End of leave-in-this-order ############ End of leave-in-this-order
############ Leave those lines in this order!! ############ Leave those lines in this order!!
@@ -2548,6 +2557,7 @@ STR_NEWGRF_SETTINGS_VERSION :{BLACK}பத
STR_NEWGRF_SETTINGS_MIN_VERSION :{BLACK}குறைந்த். பயன்படுத்தக்கூடிய பதிப்பு: {SILVER}{NUM} STR_NEWGRF_SETTINGS_MIN_VERSION :{BLACK}குறைந்த். பயன்படுத்தக்கூடிய பதிப்பு: {SILVER}{NUM}
STR_NEWGRF_SETTINGS_MD5SUM :{BLACK}MD5sum: {SILVER}{STRING} STR_NEWGRF_SETTINGS_MD5SUM :{BLACK}MD5sum: {SILVER}{STRING}
STR_NEWGRF_SETTINGS_PALETTE :{BLACK}தட்டு: {SILVER}{STRING} STR_NEWGRF_SETTINGS_PALETTE :{BLACK}தட்டு: {SILVER}{STRING}
STR_NEWGRF_SETTINGS_PALETTE_DEFAULT_32BPP :முதன்மை / 32 bpp
STR_NEWGRF_SETTINGS_PALETTE_LEGACY :மரபுரிமை (W) STR_NEWGRF_SETTINGS_PALETTE_LEGACY :மரபுரிமை (W)
STR_NEWGRF_SETTINGS_PARAMETER :{BLACK}குணாதிசயங்கள்: {SILVER}{STRING} STR_NEWGRF_SETTINGS_PARAMETER :{BLACK}குணாதிசயங்கள்: {SILVER}{STRING}
STR_NEWGRF_SETTINGS_PARAMETER_NONE :ஒன்றுமில்லை STR_NEWGRF_SETTINGS_PARAMETER_NONE :ஒன்றுமில்லை
@@ -2951,6 +2961,7 @@ STR_INDUSTRY_VIEW_INDUSTRY_ANNOUNCED_CLOSURE :{YELLOW}தொ
STR_INDUSTRY_VIEW_REQUIRES :{BLACK}வேண்டியவன: STR_INDUSTRY_VIEW_REQUIRES :{BLACK}வேண்டியவன:
STR_INDUSTRY_VIEW_ACCEPT_CARGO_AMOUNT :{YELLOW}{STRING}{BLACK}: {CARGO_SHORT} காத்துக்கொண்டிருக்கிறது{STRING}
STR_CONFIG_GAME_PRODUCTION :{WHITE}தயாரிப்பினை மாற்றவும் (8 இன் பெருக்கங்கள், 2040 வரை) STR_CONFIG_GAME_PRODUCTION :{WHITE}தயாரிப்பினை மாற்றவும் (8 இன் பெருக்கங்கள், 2040 வரை)
STR_CONFIG_GAME_PRODUCTION_LEVEL :{WHITE}தயாரிப்பு அளவினை மாற்றவும் (சதவிகிதம், 800% வரை) STR_CONFIG_GAME_PRODUCTION_LEVEL :{WHITE}தயாரிப்பு அளவினை மாற்றவும் (சதவிகிதம், 800% வரை)
@@ -3078,6 +3089,7 @@ STR_BUY_VEHICLE_ROAD_VEHICLE_RENAME_TOOLTIP :{BLACK}சா
STR_BUY_VEHICLE_SHIP_RENAME_TOOLTIP :{BLACK}கப்பல் வகையின் பெயரினை மாற்றவும் STR_BUY_VEHICLE_SHIP_RENAME_TOOLTIP :{BLACK}கப்பல் வகையின் பெயரினை மாற்றவும்
STR_BUY_VEHICLE_AIRCRAFT_RENAME_TOOLTIP :{BLACK}விமான வகையின் பெயரினை மாற்றவும் STR_BUY_VEHICLE_AIRCRAFT_RENAME_TOOLTIP :{BLACK}விமான வகையின் பெயரினை மாற்றவும்
STR_BUY_VEHICLE_AIRCRAFT_HIDE_TOGGLE_BUTTON :{BLACK}மறை
STR_BUY_VEHICLE_ROAD_VEHICLE_SHOW_TOGGLE_BUTTON :{BLACK}காட்சி STR_BUY_VEHICLE_ROAD_VEHICLE_SHOW_TOGGLE_BUTTON :{BLACK}காட்சி
@@ -3200,6 +3212,7 @@ STR_REPLACE_ELRAIL_VEHICLES :மின்ச
STR_REPLACE_MONORAIL_VEHICLES :மோனோ இரயில் வாகனங்கள் STR_REPLACE_MONORAIL_VEHICLES :மோனோ இரயில் வாகனங்கள்
STR_REPLACE_MAGLEV_VEHICLES :மேக்லெவ் வாகனங்கள் STR_REPLACE_MAGLEV_VEHICLES :மேக்லெவ் வாகனங்கள்
STR_REPLACE_ROAD_VEHICLES :சாலை வாகனங்கள்
STR_REPLACE_TRAM_VEHICLES :அமிழ் தண்டூர்தி வாகனங்கள் STR_REPLACE_TRAM_VEHICLES :அமிழ் தண்டூர்தி வாகனங்கள்
STR_REPLACE_REMOVE_WAGON :{BLACK}பெட்டி நீக்கம்: {ORANGE}{STRING} STR_REPLACE_REMOVE_WAGON :{BLACK}பெட்டி நீக்கம்: {ORANGE}{STRING}

View File

@@ -29,6 +29,7 @@
#include "station_kdtree.h" #include "station_kdtree.h"
#include "town_kdtree.h" #include "town_kdtree.h"
#include "viewport_kdtree.h" #include "viewport_kdtree.h"
#include "newgrf_profiling.h"
#include "tracerestrict.h" #include "tracerestrict.h"
#include "programmable_signals.h" #include "programmable_signals.h"
#include "viewport_func.h" #include "viewport_func.h"
@@ -89,6 +90,8 @@ void InitializeGame(uint size_x, uint size_y, bool reset_date, bool reset_settin
_loadgame_DBGL_data.clear(); _loadgame_DBGL_data.clear();
if (reset_settings) MakeNewgameSettingsLive(); if (reset_settings) MakeNewgameSettingsLive();
_newgrf_profilers.clear();
if (reset_date) { if (reset_date) {
SetDate(ConvertYMDToDate(_settings_game.game_creation.starting_year, 0, 1), 0); SetDate(ConvertYMDToDate(_settings_game.game_creation.starting_year, 0, 1), 0);
InitializeOldNames(); InitializeOldNames();

View File

@@ -67,6 +67,11 @@
/** List of all loaded GRF files */ /** List of all loaded GRF files */
static std::vector<GRFFile *> _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 */ /** Miscellaneous GRF features, set by Action 0x0D, parameter 0x9E */
byte _misc_grf_features = 0; byte _misc_grf_features = 0;
@@ -5107,6 +5112,7 @@ static void NewSpriteGroup(ByteReader *buf)
assert(DeterministicSpriteGroup::CanAllocateItem()); assert(DeterministicSpriteGroup::CanAllocateItem());
DeterministicSpriteGroup *group = new DeterministicSpriteGroup(); DeterministicSpriteGroup *group = new DeterministicSpriteGroup();
group->nfo_line = _cur.nfo_line;
act_group = group; act_group = group;
group->var_scope = HasBit(type, 1) ? VSG_SCOPE_PARENT : VSG_SCOPE_SELF; group->var_scope = HasBit(type, 1) ? VSG_SCOPE_PARENT : VSG_SCOPE_SELF;
@@ -5223,6 +5229,7 @@ static void NewSpriteGroup(ByteReader *buf)
{ {
assert(RandomizedSpriteGroup::CanAllocateItem()); assert(RandomizedSpriteGroup::CanAllocateItem());
RandomizedSpriteGroup *group = new RandomizedSpriteGroup(); RandomizedSpriteGroup *group = new RandomizedSpriteGroup();
group->nfo_line = _cur.nfo_line;
act_group = group; act_group = group;
group->var_scope = HasBit(type, 1) ? VSG_SCOPE_PARENT : VSG_SCOPE_SELF; group->var_scope = HasBit(type, 1) ? VSG_SCOPE_PARENT : VSG_SCOPE_SELF;
@@ -5271,6 +5278,7 @@ static void NewSpriteGroup(ByteReader *buf)
assert(RealSpriteGroup::CanAllocateItem()); assert(RealSpriteGroup::CanAllocateItem());
RealSpriteGroup *group = new RealSpriteGroup(); RealSpriteGroup *group = new RealSpriteGroup();
group->nfo_line = _cur.nfo_line;
act_group = group; act_group = group;
group->num_loaded = num_loaded; group->num_loaded = num_loaded;
@@ -5304,6 +5312,7 @@ static void NewSpriteGroup(ByteReader *buf)
assert(TileLayoutSpriteGroup::CanAllocateItem()); assert(TileLayoutSpriteGroup::CanAllocateItem());
TileLayoutSpriteGroup *group = new TileLayoutSpriteGroup(); TileLayoutSpriteGroup *group = new TileLayoutSpriteGroup();
group->nfo_line = _cur.nfo_line;
act_group = group; act_group = group;
/* On error, bail out immediately. Temporary GRF data was already freed */ /* On error, bail out immediately. Temporary GRF data was already freed */
@@ -5319,6 +5328,7 @@ static void NewSpriteGroup(ByteReader *buf)
assert(IndustryProductionSpriteGroup::CanAllocateItem()); assert(IndustryProductionSpriteGroup::CanAllocateItem());
IndustryProductionSpriteGroup *group = new IndustryProductionSpriteGroup(); IndustryProductionSpriteGroup *group = new IndustryProductionSpriteGroup();
group->nfo_line = _cur.nfo_line;
act_group = group; act_group = group;
group->version = type; group->version = type;
if (type == 0) { if (type == 0) {

View File

@@ -58,6 +58,9 @@ struct AirportResolverObject : public ResolverObject {
} }
const SpriteGroup *ResolveReal(const RealSpriteGroup *group) const override; const SpriteGroup *ResolveReal(const RealSpriteGroup *group) const override;
GrfSpecFeature GetFeature() const override;
uint32 GetDebugID() const override;
}; };
/** /**
@@ -226,6 +229,16 @@ void AirportOverrideManager::SetEntitySpec(AirportSpec *as)
return nullptr; 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 /* virtual */ uint32 AirportScopeResolver::GetRandomBits() const
{ {
return this->st == nullptr ? 0 : this->st->random_bits; return this->st == nullptr ? 0 : this->st->random_bits;

View File

@@ -220,6 +220,16 @@ AirportTileResolverObject::AirportTileResolverObject(const AirportTileSpec *ats,
this->root_spritegroup = ats->grf_prop.spritegroup[0]; 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) 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); AirportTileResolverObject object(ats, tile, st, callback, param1, param2);

View File

@@ -22,6 +22,7 @@ struct AirportTileScopeResolver : public ScopeResolver {
struct Station *st; ///< %Station of the airport for which the callback is run, or \c nullptr for build gui. 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. byte airport_id; ///< Type of airport for which the callback is run.
TileIndex tile; ///< Tile for the callback, only valid for airporttile callbacks. TileIndex tile; ///< Tile for the callback, only valid for airporttile callbacks.
const AirportTileSpec *ats;
/** /**
* Constructor of the scope resolver specific for airport tiles. * Constructor of the scope resolver specific for airport tiles.
@@ -30,7 +31,7 @@ struct AirportTileScopeResolver : public ScopeResolver {
* @param st Station of the airport for which the callback is run, or \c nullptr for build gui. * @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) 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); assert(st != nullptr);
this->airport_id = st->airport.type; this->airport_id = st->airport.type;
@@ -54,6 +55,9 @@ struct AirportTileResolverObject : public ResolverObject {
default: return ResolverObject::GetScope(scope, relative); default: return ResolverObject::GetScope(scope, relative);
} }
} }
GrfSpecFeature GetFeature() const override;
uint32 GetDebugID() const override;
}; };
/** /**

View File

@@ -13,6 +13,7 @@
#include "newgrf_canal.h" #include "newgrf_canal.h"
#include "water.h" #include "water.h"
#include "water_map.h" #include "water_map.h"
#include "spritecache.h"
#include "safeguards.h" #include "safeguards.h"
@@ -35,6 +36,7 @@ struct CanalScopeResolver : public ScopeResolver {
/** Resolver object for canals. */ /** Resolver object for canals. */
struct CanalResolverObject : public ResolverObject { struct CanalResolverObject : public ResolverObject {
CanalScopeResolver canal_scope; CanalScopeResolver canal_scope;
CanalFeature feature;
CanalResolverObject(CanalFeature feature, TileIndex tile, CanalResolverObject(CanalFeature feature, TileIndex tile,
CallbackID callback = CBID_NO_CALLBACK, uint32 callback_param1 = 0, uint32 callback_param2 = 0); CallbackID callback = CBID_NO_CALLBACK, uint32 callback_param1 = 0, uint32 callback_param2 = 0);
@@ -48,6 +50,9 @@ struct CanalResolverObject : public ResolverObject {
} }
const SpriteGroup *ResolveReal(const RealSpriteGroup *group) const override; const SpriteGroup *ResolveReal(const RealSpriteGroup *group) const override;
GrfSpecFeature GetFeature() const override;
uint32 GetDebugID() const override;
}; };
/* virtual */ uint32 CanalScopeResolver::GetRandomBits() const /* virtual */ uint32 CanalScopeResolver::GetRandomBits() const
@@ -111,6 +116,16 @@ struct CanalResolverObject : public ResolverObject {
return group->loaded[0]; return group->loaded[0];
} }
GrfSpecFeature CanalResolverObject::GetFeature() const
{
return GSF_CANALS;
}
uint32 CanalResolverObject::GetDebugID() const
{
return this->feature;
}
/** /**
* Canal resolver constructor. * Canal resolver constructor.
* @param feature Which canal feature we want. * @param feature Which canal feature we want.
@@ -121,7 +136,7 @@ struct CanalResolverObject : public ResolverObject {
*/ */
CanalResolverObject::CanalResolverObject(CanalFeature feature, TileIndex tile, CanalResolverObject::CanalResolverObject(CanalFeature feature, TileIndex tile,
CallbackID callback, uint32 callback_param1, uint32 callback_param2) 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; this->root_spritegroup = _water_feature[feature].group;
} }

View File

@@ -15,9 +15,14 @@
/** Resolver of cargo. */ /** Resolver of cargo. */
struct CargoResolverObject : public ResolverObject { struct CargoResolverObject : public ResolverObject {
const CargoSpec *cargospec;
CargoResolverObject(const CargoSpec *cs, CallbackID callback = CBID_NO_CALLBACK, uint32 callback_param1 = 0, uint32 callback_param2 = 0); 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; 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 /* virtual */ const SpriteGroup *CargoResolverObject::ResolveReal(const RealSpriteGroup *group) const
@@ -30,6 +35,16 @@ struct CargoResolverObject : public ResolverObject {
return nullptr; return nullptr;
} }
GrfSpecFeature CargoResolverObject::GetFeature() const
{
return GSF_CARGOES;
}
uint32 CargoResolverObject::GetDebugID() const
{
return this->cargospec->label;
}
/** /**
* Constructor of the cargo resolver. * Constructor of the cargo resolver.
* @param cs Cargo being resolved. * @param cs Cargo being resolved.
@@ -38,7 +53,7 @@ struct CargoResolverObject : public ResolverObject {
* @param callback_param2 Second parameter (var 18) 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) 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; this->root_spritegroup = cs->group;
} }

View File

@@ -952,6 +952,22 @@ static uint32 VehicleGetVariable(Vehicle *v, const VehicleScopeResolver *object,
return in_motion ? group->loaded[set] : group->loading[set]; 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. * Get the grf file associated with an engine type.
* @param engine_type Engine to query. * @param engine_type Engine to query.

View File

@@ -65,6 +65,9 @@ struct VehicleResolverObject : public ResolverObject {
ScopeResolver *GetScope(VarSpriteGroupScope scope = VSG_SCOPE_SELF, byte relative = 0) override; ScopeResolver *GetScope(VarSpriteGroupScope scope = VSG_SCOPE_SELF, byte relative = 0) override;
const SpriteGroup *ResolveReal(const RealSpriteGroup *group) const 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 TRAININFO_DEFAULT_VEHICLE_WIDTH = 29;

View File

@@ -29,6 +29,8 @@ struct GenericScopeResolver : public ScopeResolver {
uint8 count; uint8 count;
uint8 station_size; uint8 station_size;
uint8 feature;
/** /**
* Generic scope resolver. * Generic scope resolver.
* @param ro Surrounding resolver. * @param ro Surrounding resolver.
@@ -36,7 +38,7 @@ struct GenericScopeResolver : public ScopeResolver {
*/ */
GenericScopeResolver(ResolverObject &ro, bool ai_callback) GenericScopeResolver(ResolverObject &ro, bool ai_callback)
: ScopeResolver(ro), cargo_type(0), default_selection(0), src_industry(0), dst_industry(0), distance(0), : 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 ResolverObject {
} }
const SpriteGroup *ResolveReal(const RealSpriteGroup *group) const override; 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 { struct GenericCallback {
@@ -226,6 +238,7 @@ uint16 GetAiPurchaseCallbackResult(uint8 feature, CargoID cargo_type, uint8 defa
object.generic_scope.event = event; object.generic_scope.event = event;
object.generic_scope.count = count; object.generic_scope.count = count;
object.generic_scope.station_size = station_size; object.generic_scope.station_size = station_size;
object.generic_scope.feature = feature;
uint16 callback = GetGenericCallbackResult(feature, object, 0, 0, file); uint16 callback = GetGenericCallbackResult(feature, object, 0, 0, file);
if (callback != CALLBACK_FAILED) callback = GB(callback, 0, 8); if (callback != CALLBACK_FAILED) callback = GB(callback, 0, 8);
@@ -247,6 +260,7 @@ void AmbientSoundEffectCallback(TileIndex tile)
/* Prepare resolver object. */ /* Prepare resolver object. */
GenericResolverObject object(false, CBID_SOUNDS_AMBIENT_EFFECT); 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_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); uint32 param1_v8 = GetTileType(tile) << 24 | GetTileZ(tile) << 16 | GB(r, 16, 8) << 8 | (HasTileWaterClass(tile) ? GetWaterClass(tile) : 0) << 3 | GetTerrainType(tile);

View File

@@ -64,8 +64,8 @@ HouseResolverObject::HouseResolverObject(HouseID house_id, TileIndex tile, Town
assert(tile == INVALID_TILE || (not_yet_constructed ? IsValidTile(tile) : GetHouseType(tile) == house_id && Town::GetByTile(tile) == town)); assert(tile == INVALID_TILE || (not_yet_constructed ? IsValidTile(tile) : GetHouseType(tile) == house_id && Town::GetByTile(tile) == town));
this->house_scope = (tile != INVALID_TILE) ? this->house_scope = (tile != INVALID_TILE) ?
(ScopeResolver*)new HouseScopeResolver(*this, house_id, tile, town, not_yet_constructed, initial_random_bits, watched_cargo_triggers) : (CommonHouseScopeResolver*)new HouseScopeResolver(*this, house_id, tile, town, not_yet_constructed, initial_random_bits, watched_cargo_triggers) :
(ScopeResolver*)new FakeHouseScopeResolver(*this, house_id); (CommonHouseScopeResolver*)new FakeHouseScopeResolver(*this, house_id);
this->town_scope = (town != nullptr) ? this->town_scope = (town != nullptr) ?
(ScopeResolver*)new TownScopeResolver(*this, town, not_yet_constructed) : // Don't access StorePSA if house is not yet constructed. (ScopeResolver*)new TownScopeResolver(*this, town, not_yet_constructed) : // Don't access StorePSA if house is not yet constructed.
@@ -80,6 +80,16 @@ HouseResolverObject::HouseResolverObject(HouseID house_id, TileIndex tile, Town
delete this->town_scope; delete this->town_scope;
} }
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) HouseClassID AllocateHouseClassID(byte grf_class_id, uint32 grfid)
{ {
/* Start from 1 because 0 means that no class has been assigned. */ /* Start from 1 because 0 means that no class has been assigned. */

View File

@@ -16,9 +16,16 @@
#include "newgrf_spritegroup.h" #include "newgrf_spritegroup.h"
#include "newgrf_town.h" #include "newgrf_town.h"
/** Scope resolver for houses. */ struct CommonHouseScopeResolver : public ScopeResolver {
struct HouseScopeResolver : public ScopeResolver {
HouseID house_id; ///< Type of house being queried. HouseID house_id; ///< Type of house being queried.
CommonHouseScopeResolver(ResolverObject &ro, HouseID house_id)
: ScopeResolver(ro), house_id(house_id)
{ }
};
/** Scope resolver for houses. */
struct HouseScopeResolver : public CommonHouseScopeResolver {
TileIndex tile; ///< Tile of this house. TileIndex tile; ///< Tile of this house.
Town *town; ///< Town of this house. Town *town; ///< Town of this house.
bool not_yet_constructed; ///< True for construction check. bool not_yet_constructed; ///< True for construction check.
@@ -37,7 +44,7 @@ struct HouseScopeResolver : public ScopeResolver {
*/ */
HouseScopeResolver(ResolverObject &ro, HouseID house_id, TileIndex tile, Town *town, HouseScopeResolver(ResolverObject &ro, HouseID house_id, TileIndex tile, Town *town,
bool not_yet_constructed, uint8 initial_random_bits, CargoTypes watched_cargo_triggers) bool not_yet_constructed, uint8 initial_random_bits, CargoTypes watched_cargo_triggers)
: ScopeResolver(ro), house_id(house_id), tile(tile), town(town), not_yet_constructed(not_yet_constructed), : CommonHouseScopeResolver(ro, house_id), tile(tile), town(town), not_yet_constructed(not_yet_constructed),
initial_random_bits(initial_random_bits), watched_cargo_triggers(watched_cargo_triggers) initial_random_bits(initial_random_bits), watched_cargo_triggers(watched_cargo_triggers)
{ {
} }
@@ -58,11 +65,9 @@ struct HouseScopeResolver : public ScopeResolver {
* Since the building doesn't exists we have no real values that we can return. * Since the building doesn't exists we have no real values that we can return.
* Instead of failing, this resolver will return fake values. * Instead of failing, this resolver will return fake values.
*/ */
struct FakeHouseScopeResolver : public ScopeResolver { struct FakeHouseScopeResolver : public CommonHouseScopeResolver {
HouseID house_id; ///< Type of house being queried.
FakeHouseScopeResolver(ResolverObject &ro, HouseID house_id) FakeHouseScopeResolver(ResolverObject &ro, HouseID house_id)
: ScopeResolver(ro), house_id(house_id) : CommonHouseScopeResolver(ro, house_id)
{ } { }
/* virtual */ uint32 GetVariable(byte variable, uint32 parameter, bool *available) const; /* virtual */ uint32 GetVariable(byte variable, uint32 parameter, bool *available) const;
@@ -70,7 +75,7 @@ struct FakeHouseScopeResolver : public ScopeResolver {
/** Resolver object to be used for houses (feature 07 spritegroups). */ /** Resolver object to be used for houses (feature 07 spritegroups). */
struct HouseResolverObject : public ResolverObject { struct HouseResolverObject : public ResolverObject {
ScopeResolver *house_scope; CommonHouseScopeResolver *house_scope;
ScopeResolver *town_scope; ScopeResolver *town_scope;
HouseResolverObject(HouseID house_id, TileIndex tile = INVALID_TILE, Town *town = nullptr, HouseResolverObject(HouseID house_id, TileIndex tile = INVALID_TILE, Town *town = nullptr,
@@ -87,6 +92,9 @@ struct HouseResolverObject : public ResolverObject {
default: return ResolverObject::GetScope(scope, relative); default: return ResolverObject::GetScope(scope, relative);
} }
} }
GrfSpecFeature GetFeature() const override;
uint32 GetDebugID() const override;
}; };
/** /**

View File

@@ -489,6 +489,16 @@ TownScopeResolver *IndustriesResolverObject::GetTown()
return this->town_scope; 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. * Perform an industry callback.
* @param callback The callback to perform. * @param callback The callback to perform.

View File

@@ -63,6 +63,9 @@ struct IndustriesResolverObject : public ResolverObject {
return ResolverObject::GetScope(scope, relative); return ResolverObject::GetScope(scope, relative);
} }
} }
GrfSpecFeature GetFeature() const override;
uint32 GetDebugID() const override;
}; };
/** When should the industry(tile) be triggered for random bits? */ /** When should the industry(tile) be triggered for random bits? */

View File

@@ -139,11 +139,22 @@ IndustryTileResolverObject::IndustryTileResolverObject(IndustryGfx gfx, TileInde
CallbackID callback, uint32 callback_param1, uint32 callback_param2) CallbackID callback, uint32 callback_param1, uint32 callback_param2)
: ResolverObject(GetIndTileGrffile(gfx), callback, callback_param1, callback_param2), : ResolverObject(GetIndTileGrffile(gfx), callback, callback_param1, callback_param2),
indtile_scope(*this, indus, tile), 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]; 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) static void IndustryDrawTileLayout(const TileInfo *ti, const TileLayoutSpriteGroup *group, byte rnd_colour, byte stage, IndustryGfx gfx)
{ {
const DrawTileSprites *dts = group->ProcessRegisters(&stage); const DrawTileSprites *dts = group->ProcessRegisters(&stage);

View File

@@ -39,6 +39,7 @@ struct IndustryTileScopeResolver : public ScopeResolver {
struct IndustryTileResolverObject : public ResolverObject { struct IndustryTileResolverObject : public ResolverObject {
IndustryTileScopeResolver indtile_scope; ///< Scope resolver for the industry tile. IndustryTileScopeResolver indtile_scope; ///< Scope resolver for the industry tile.
IndustriesScopeResolver ind_scope; ///< Scope resolver for the industry owning the tile. IndustriesScopeResolver ind_scope; ///< Scope resolver for the industry owning the tile.
IndustryGfx gfx;
IndustryTileResolverObject(IndustryGfx gfx, TileIndex tile, Industry *indus, IndustryTileResolverObject(IndustryGfx gfx, TileIndex tile, Industry *indus,
CallbackID callback = CBID_NO_CALLBACK, uint32 callback_param1 = 0, uint32 callback_param2 = 0); CallbackID callback = CBID_NO_CALLBACK, uint32 callback_param1 = 0, uint32 callback_param2 = 0);
@@ -51,6 +52,9 @@ struct IndustryTileResolverObject : public ResolverObject {
default: return ResolverObject::GetScope(scope, relative); 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); bool DrawNewIndustryTile(TileInfo *ti, Industry *i, IndustryGfx gfx, const IndustryTileSpec *inds);

View File

@@ -352,7 +352,7 @@ unhandled:
*/ */
ObjectResolverObject::ObjectResolverObject(const ObjectSpec *spec, Object *obj, TileIndex tile, uint8 view, ObjectResolverObject::ObjectResolverObject(const ObjectSpec *spec, Object *obj, TileIndex tile, uint8 view,
CallbackID callback, uint32 param1, uint32 param2) 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->town_scope = nullptr;
this->root_spritegroup = (obj == nullptr && spec->grf_prop.spritegroup[CT_PURCHASE_OBJECT] != nullptr) ? this->root_spritegroup = (obj == nullptr && spec->grf_prop.spritegroup[CT_PURCHASE_OBJECT] != nullptr) ?
@@ -384,6 +384,16 @@ TownScopeResolver *ObjectResolverObject::GetTown()
return this->town_scope; 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. * Perform a callback for an object.
* @param callback The callback to perform. * @param callback The callback to perform.

View File

@@ -98,9 +98,10 @@ struct ObjectSpec {
/** Object scope resolver. */ /** Object scope resolver. */
struct ObjectScopeResolver : public ScopeResolver { struct ObjectScopeResolver : public ScopeResolver {
struct Object *obj; ///< The object the callback is ran for. struct Object *obj; ///< The object the callback is ran for.
TileIndex tile; ///< The tile related to the object. const ObjectSpec *spec; ///< Specification of the object type.
uint8 view; ///< The view of the object. TileIndex tile; ///< The tile related to the object.
uint8 view; ///< The view of the object.
/** /**
* Constructor of an object scope resolver. * Constructor of an object scope resolver.
@@ -109,8 +110,8 @@ struct ObjectScopeResolver : public ScopeResolver {
* @param tile %Tile of the object. * @param tile %Tile of the object.
* @param view View of the object. * @param view View of the object.
*/ */
ObjectScopeResolver(ResolverObject &ro, Object *obj, TileIndex tile, uint8 view = 0) ObjectScopeResolver(ResolverObject &ro, Object *obj, const ObjectSpec *spec, TileIndex tile, uint8 view = 0)
: ScopeResolver(ro), obj(obj), tile(tile), view(view) : ScopeResolver(ro), obj(obj), spec(spec), tile(tile), view(view)
{ {
} }
@@ -144,6 +145,9 @@ struct ObjectResolverObject : public ResolverObject {
} }
} }
GrfSpecFeature GetFeature() const override;
uint32 GetDebugID() const override;
private: private:
TownScopeResolver *GetTown(); TownScopeResolver *GetTown();
}; };

162
src/newgrf_profiling.cpp Normal file
View File

@@ -0,0 +1,162 @@
/*
* 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;
}

63
src/newgrf_profiling.h Normal file
View File

@@ -0,0 +1,63 @@
/*
* 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 */

View File

@@ -65,6 +65,16 @@
return nullptr; return nullptr;
} }
GrfSpecFeature RailTypeResolverObject::GetFeature() const
{
return GSF_RAILTYPES;
}
uint32 RailTypeResolverObject::GetDebugID() const
{
return this->railtype_scope.rti->label;
}
/** /**
* Resolver object for rail types. * Resolver object for rail types.
* @param rti Railtype. nullptr in NewGRF Inspect window. * @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). * @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) 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; this->root_spritegroup = rti != nullptr ? rti->group[rtsg] : nullptr;
} }

View File

@@ -18,6 +18,7 @@
struct RailTypeScopeResolver : public ScopeResolver { struct RailTypeScopeResolver : public ScopeResolver {
TileIndex tile; ///< Tracktile. For track on a bridge this is the southern bridgehead. 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? TileContext context; ///< Are we resolving sprites for the upper halftile, or on a bridge?
const RailtypeInfo *rti;
/** /**
* Constructor of the railtype scope resolvers. * Constructor of the railtype scope resolvers.
@@ -25,8 +26,8 @@ struct RailTypeScopeResolver : public ScopeResolver {
* @param tile %Tile containing the track. For track on a bridge this is the southern bridgehead. * @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 context Are we resolving sprites for the upper halftile, or on a bridge?
*/ */
RailTypeScopeResolver(ResolverObject &ro, TileIndex tile, TileContext context) RailTypeScopeResolver(ResolverObject &ro, const RailtypeInfo *rti, TileIndex tile, TileContext context)
: ScopeResolver(ro), tile(tile), context(context) : ScopeResolver(ro), tile(tile), context(context), rti(rti)
{ {
} }
@@ -49,6 +50,9 @@ struct RailTypeResolverObject : public ResolverObject {
} }
const SpriteGroup *ResolveReal(const RealSpriteGroup *group) const override; 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 GetCustomRailSprite(const RailtypeInfo *rti, TileIndex tile, RailTypeSpriteGroup rtsg, TileContext context = TCX_NORMAL, uint *num_results = nullptr);

View File

@@ -65,16 +65,32 @@
return nullptr; 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. * Constructor of the roadtype scope resolvers.
* @param ro Surrounding resolver. * @param ro Surrounding resolver.
* @param tile %Tile containing the track. For track on a bridge this is the southern bridgehead. * @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 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->tile = tile;
this->context = context; this->context = context;
this->rti = rti;
} }
/** /**
@@ -87,7 +103,7 @@ RoadTypeScopeResolver::RoadTypeScopeResolver(ResolverObject &ro, TileIndex tile,
* @param param2 Extra parameter (second 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) 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; this->root_spritegroup = rti != nullptr ? rti->group[rtsg] : nullptr;
} }

View File

@@ -18,8 +18,9 @@
struct RoadTypeScopeResolver : public ScopeResolver { struct RoadTypeScopeResolver : public ScopeResolver {
TileIndex tile; ///< Tracktile. For track on a bridge this is the southern bridgehead. 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? 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 GetRandomBits() const;
/* virtual */ uint32 GetVariable(byte variable, uint32 parameter, bool *available) const; /* virtual */ uint32 GetVariable(byte variable, uint32 parameter, bool *available) const;
@@ -31,7 +32,7 @@ struct RoadTypeResolverObject : public ResolverObject {
RoadTypeResolverObject(const RoadTypeInfo *rti, TileIndex tile, TileContext context, RoadTypeSpriteGroup rtsg, uint32 param1 = 0, uint32 param2 = 0); RoadTypeResolverObject(const RoadTypeInfo *rti, TileIndex tile, TileContext context, RoadTypeSpriteGroup rtsg, uint32 param1 = 0, uint32 param2 = 0);
/* virtual */ ScopeResolver *GetScope(VarSpriteGroupScope scope = VSG_SCOPE_SELF, byte relative = 0) ScopeResolver *GetScope(VarSpriteGroupScope scope = VSG_SCOPE_SELF, byte relative = 0) override
{ {
switch (scope) { switch (scope) {
case VSG_SCOPE_SELF: return &this->roadtype_scope; case VSG_SCOPE_SELF: return &this->roadtype_scope;
@@ -39,7 +40,10 @@ struct RoadTypeResolverObject : public ResolverObject {
} }
} }
/* virtual */ const SpriteGroup *ResolveReal(const RealSpriteGroup *group) const; const SpriteGroup *ResolveReal(const RealSpriteGroup *group) const override;
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); SpriteID GetCustomRoadSprite(const RoadTypeInfo *rti, TileIndex tile, RoadTypeSpriteGroup rtsg, TileContext context = TCX_NORMAL, uint *num_results = nullptr);

View File

@@ -11,6 +11,7 @@
#include <algorithm> #include <algorithm>
#include "debug.h" #include "debug.h"
#include "newgrf_spritegroup.h" #include "newgrf_spritegroup.h"
#include "newgrf_profiling.h"
#include "core/pool_func.hpp" #include "core/pool_func.hpp"
#include "vehicle_type.h" #include "vehicle_type.h"
@@ -35,10 +36,23 @@ TemporaryStorageArray<int32, 0x110> _temp_store;
/* static */ const SpriteGroup *SpriteGroup::Resolve(const SpriteGroup *group, ResolverObject &object, bool top_level) /* static */ const SpriteGroup *SpriteGroup::Resolve(const SpriteGroup *group, ResolverObject &object, bool top_level)
{ {
if (group == nullptr) return nullptr; 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(); _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() RealSpriteGroup::~RealSpriteGroup()

View File

@@ -56,13 +56,14 @@ extern SpriteGroupPool _spritegroup_pool;
/* Common wrapper for all the different sprite group types */ /* Common wrapper for all the different sprite group types */
struct SpriteGroup : SpriteGroupPool::PoolItem<&_spritegroup_pool> { struct SpriteGroup : SpriteGroupPool::PoolItem<&_spritegroup_pool> {
protected: protected:
SpriteGroup(SpriteGroupType type) : type(type) {} SpriteGroup(SpriteGroupType type) : nfo_line(0), type(type) {}
/** Base sprite group resolver */ /** Base sprite group resolver */
virtual const SpriteGroup *Resolve(ResolverObject &object) const { return this; }; virtual const SpriteGroup *Resolve(ResolverObject &object) const { return this; };
public: public:
virtual ~SpriteGroup() {} virtual ~SpriteGroup() {}
uint32 nfo_line;
SpriteGroupType type; SpriteGroupType type;
virtual SpriteID GetResult() const { return 0; } virtual SpriteID GetResult() const { return 0; }
@@ -398,6 +399,18 @@ struct ResolverObject {
this->used_triggers = 0; this->used_triggers = 0;
memset(this->reseed, 0, sizeof(this->reseed)); 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 */ #endif /* NEWGRF_SPRITEGROUP_H */

View File

@@ -527,6 +527,16 @@ uint32 Waypoint::GetNewGRFVariable(const ResolverObject &object, byte variable,
return group->loading[0]; 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. * Resolver for stations.
* @param statspec Station (type) specification. * @param statspec Station (type) specification.

View File

@@ -77,6 +77,9 @@ struct StationResolverObject : public ResolverObject {
} }
const SpriteGroup *ResolveReal(const RealSpriteGroup *group) const override; const SpriteGroup *ResolveReal(const RealSpriteGroup *group) const override;
GrfSpecFeature GetFeature() const override;
uint32 GetDebugID() const override;
}; };
enum StationClassID : byte { enum StationClassID : byte {

View File

@@ -729,38 +729,66 @@ static bool MakeSmallScreenshot(bool crashlog)
*/ */
void SetupScreenshotViewport(ScreenshotType t, ViewPort *vp) void SetupScreenshotViewport(ScreenshotType t, ViewPort *vp)
{ {
/* Determine world coordinates of screenshot */ switch(t) {
if (t == SC_WORLD) { case SC_VIEWPORT:
vp->zoom = ZOOM_LVL_WORLD_SCREENSHOT; case SC_CRASHLOG: {
Window *w = FindWindowById(WC_MAIN_WINDOW, 0);
vp->virtual_left = w->viewport->virtual_left;
vp->virtual_top = w->viewport->virtual_top;
vp->virtual_width = w->viewport->virtual_width;
vp->virtual_height = w->viewport->virtual_height;
TileIndex north_tile = _settings_game.construction.freeform_edges ? TileXY(1, 1) : TileXY(0, 0); /* Compute pixel coordinates */
TileIndex south_tile = MapSize() - 1; vp->left = 0;
vp->top = 0;
vp->width = _screen.width;
vp->height = _screen.height;
vp->overlay = w->viewport->overlay;
break;
}
case SC_WORLD: {
/* Determine world coordinates of screenshot */
vp->zoom = ZOOM_LVL_WORLD_SCREENSHOT;
/* We need to account for a hill or high building at tile 0,0. */ TileIndex north_tile = _settings_game.construction.freeform_edges ? TileXY(1, 1) : TileXY(0, 0);
int extra_height_top = TilePixelHeight(north_tile) + 150; TileIndex south_tile = MapSize() - 1;
/* If there is a hill at the bottom don't create a large black area. */
int reclaim_height_bottom = TilePixelHeight(south_tile);
vp->virtual_left = RemapCoords(TileX(south_tile) * TILE_SIZE, TileY(north_tile) * TILE_SIZE, 0).x; /* We need to account for a hill or high building at tile 0,0. */
vp->virtual_top = RemapCoords(TileX(north_tile) * TILE_SIZE, TileY(north_tile) * TILE_SIZE, extra_height_top).y; int extra_height_top = TilePixelHeight(north_tile) + 150;
vp->virtual_width = RemapCoords(TileX(north_tile) * TILE_SIZE, TileY(south_tile) * TILE_SIZE, 0).x - vp->virtual_left + 1; /* If there is a hill at the bottom don't create a large black area. */
vp->virtual_height = RemapCoords(TileX(south_tile) * TILE_SIZE, TileY(south_tile) * TILE_SIZE, reclaim_height_bottom).y - vp->virtual_top + 1; int reclaim_height_bottom = TilePixelHeight(south_tile);
} else {
vp->zoom = (t == SC_ZOOMEDIN) ? _settings_client.gui.zoom_min : ZOOM_LVL_VIEWPORT;
Window *w = FindWindowById(WC_MAIN_WINDOW, 0); vp->virtual_left = RemapCoords(TileX(south_tile) * TILE_SIZE, TileY(north_tile) * TILE_SIZE, 0).x;
vp->virtual_left = w->viewport->virtual_left; vp->virtual_top = RemapCoords(TileX(north_tile) * TILE_SIZE, TileY(north_tile) * TILE_SIZE, extra_height_top).y;
vp->virtual_top = w->viewport->virtual_top; vp->virtual_width = RemapCoords(TileX(north_tile) * TILE_SIZE, TileY(south_tile) * TILE_SIZE, 0).x - vp->virtual_left + 1;
vp->virtual_width = w->viewport->virtual_width; vp->virtual_height = RemapCoords(TileX(south_tile) * TILE_SIZE, TileY(south_tile) * TILE_SIZE, reclaim_height_bottom).y - vp->virtual_top + 1;
vp->virtual_height = w->viewport->virtual_height;
/* Compute pixel coordinates */
vp->left = 0;
vp->top = 0;
vp->width = UnScaleByZoom(vp->virtual_width, vp->zoom);
vp->height = UnScaleByZoom(vp->virtual_height, vp->zoom);
vp->overlay = nullptr;
break;
}
default: {
vp->zoom = (t == SC_ZOOMEDIN) ? _settings_client.gui.zoom_min : ZOOM_LVL_VIEWPORT;
Window *w = FindWindowById(WC_MAIN_WINDOW, 0);
vp->virtual_left = w->viewport->virtual_left;
vp->virtual_top = w->viewport->virtual_top;
vp->virtual_width = w->viewport->virtual_width;
vp->virtual_height = w->viewport->virtual_height;
/* Compute pixel coordinates */
vp->left = 0;
vp->top = 0;
vp->width = UnScaleByZoom(vp->virtual_width, vp->zoom);
vp->height = UnScaleByZoom(vp->virtual_height, vp->zoom);
vp->overlay = nullptr;
break;
}
} }
/* Compute pixel coordinates */
vp->left = 0;
vp->top = 0;
vp->width = UnScaleByZoom(vp->virtual_width, vp->zoom);
vp->height = UnScaleByZoom(vp->virtual_height, vp->zoom);
vp->overlay = nullptr;
} }
/** /**

View File

@@ -1778,7 +1778,6 @@ static SettingsContainer &GetSettingsTree()
accounting->Add(new SettingEntry("difficulty.max_loan")); accounting->Add(new SettingEntry("difficulty.max_loan"));
accounting->Add(new SettingEntry("difficulty.subsidy_multiplier")); accounting->Add(new SettingEntry("difficulty.subsidy_multiplier"));
accounting->Add(new SettingEntry("economy.feeder_payment_share")); accounting->Add(new SettingEntry("economy.feeder_payment_share"));
accounting->Add(new SettingEntry("economy.feeder_payment_src_station"));
accounting->Add(new SettingEntry("economy.infrastructure_maintenance")); accounting->Add(new SettingEntry("economy.infrastructure_maintenance"));
accounting->Add(new SettingEntry("difficulty.vehicle_costs")); accounting->Add(new SettingEntry("difficulty.vehicle_costs"));
accounting->Add(new SettingEntry("difficulty.construction_cost")); accounting->Add(new SettingEntry("difficulty.construction_cost"));

View File

@@ -556,7 +556,6 @@ struct EconomySettings {
bool allow_shares; ///< allow the buying/selling of shares bool allow_shares; ///< allow the buying/selling of shares
uint8 min_years_for_shares; ///< minimum age of a company for it to trade shares uint8 min_years_for_shares; ///< minimum age of a company for it to trade shares
uint8 feeder_payment_share; ///< percentage of leg payment to virtually pay in feeder systems uint8 feeder_payment_share; ///< percentage of leg payment to virtually pay in feeder systems
bool feeder_payment_src_station; ///< calculate leg payment relative to the source station, not the leg source
byte dist_local_authority; ///< distance for town local authority, default 20 byte dist_local_authority; ///< distance for town local authority, default 20
bool exclusive_rights; ///< allow buying exclusive rights bool exclusive_rights; ///< allow buying exclusive rights
bool fund_buildings; ///< allow funding new buildings bool fund_buildings; ///< allow funding new buildings

View File

@@ -196,6 +196,17 @@ uint GetOriginFileSlot(SpriteID sprite)
return GetSpriteCache(sprite)->file_slot; 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. * Count the sprites which originate from a specific file slot in a range of SpriteIDs.
* @param file_slot FIOS file slot. * @param file_slot FIOS file slot.

View File

@@ -30,6 +30,7 @@ bool SpriteExists(SpriteID sprite);
SpriteType GetSpriteType(SpriteID sprite); SpriteType GetSpriteType(SpriteID sprite);
uint GetOriginFileSlot(SpriteID sprite); uint GetOriginFileSlot(SpriteID sprite);
uint32 GetSpriteLocalID(SpriteID sprite);
uint GetSpriteCountForSlot(uint file_slot, SpriteID begin, SpriteID end); uint GetSpriteCountForSlot(uint file_slot, SpriteID begin, SpriteID end);
uint GetMaxSpriteID(); uint GetMaxSpriteID();

View File

@@ -2147,15 +2147,6 @@ strhelp = STR_CONFIG_SETTING_FEEDER_PAYMENT_SHARE_HELPTEXT
strval = STR_CONFIG_SETTING_PERCENTAGE strval = STR_CONFIG_SETTING_PERCENTAGE
cat = SC_EXPERT cat = SC_EXPERT
[SDT_BOOL]
base = GameSettings
var = economy.feeder_payment_src_station
def = false
str = STR_CONFIG_SETTING_FEEDER_PAYMENT_SRC_STATION
strhelp = STR_CONFIG_SETTING_FEEDER_PAYMENT_SRC_STATION_HELPTEXT
cat = SC_EXPERT
patxname = ""economy.feeder_payment_src_station""
[SDT_XREF] [SDT_XREF]
xref = ""economy.day_length_factor"" xref = ""economy.day_length_factor""
extver = SlXvFeatureTest(XSLFTO_AND, XSLFI_SPRINGPP) extver = SlXvFeatureTest(XSLFTO_AND, XSLFI_SPRINGPP)

View File

@@ -392,7 +392,7 @@ QueryString *Window::GetQueryString(uint widnum)
*/ */
/* virtual */ Point Window::GetCaretPosition() const /* virtual */ Point Window::GetCaretPosition() const
{ {
if (this->nested_focus != nullptr && this->nested_focus->type == WWT_EDITBOX) { if (this->nested_focus != nullptr && this->nested_focus->type == WWT_EDITBOX && !this->querystrings.empty()) {
return this->GetQueryString(this->nested_focus->index)->GetCaretPosition(this, this->nested_focus->index); return this->GetQueryString(this->nested_focus->index)->GetCaretPosition(this, this->nested_focus->index);
} }
@@ -1107,6 +1107,9 @@ Window::~Window()
/* We can't scroll the window when it's closed. */ /* We can't scroll the window when it's closed. */
if (_last_scroll_window == this) _last_scroll_window = nullptr; if (_last_scroll_window == this) _last_scroll_window = nullptr;
/* Make sure we don't try to access non-existing query strings. */
this->querystrings.clear();
/* Make sure we don't try to access this window as the focused window when it doesn't exist anymore. */ /* Make sure we don't try to access this window as the focused window when it doesn't exist anymore. */
if (_focused_window == this) { if (_focused_window == this) {
_focused_window = nullptr; _focused_window = nullptr;