Changeset - r28555:1423e889f2e8
[Not reviewed]
master
0 10 0
Patric Stout - 11 months ago 2024-01-22 22:35:25
truebrain@openttd.org
Add: allow loading heightmaps from command-line (#11870)

If you want to load a file from tar, you have to give the file
inside the tar in order for it to work:

<tar-file>/<dir-in-tar>/<file>.png
10 files changed with 57 insertions and 30 deletions:
0 comments (0 inline, 0 general)
docs/openttd.6
Show inline comments
 
@@ -10,13 +10,13 @@
 
.Nm
 
.Op Fl efhQxX
 
.Op Fl b Ar blitter
 
.Op Fl c Ar config_file
 
.Op Fl d Op Ar level | Ar cat Ns = Ns Ar lvl Ns Op , Ns Ar ...
 
.Op Fl D Oo Ar host Oc Ns Op : Ns Ar port
 
.Op Fl g Op Ar savegame
 
.Op Fl g Op Ar file
 
.Op Fl G Ar seed
 
.Op Fl I Ar graphicsset
 
.Op Fl m Ar driver
 
.Op Fl M Ar musicset
 
.Op Fl n Ar host Ns Oo : Ns Ar port Oc Ns Op # Ns Ar company
 
.Op Fl p Ar password
 
@@ -59,17 +59,17 @@ after setting
 
.Fl D .
 
.It Fl e
 
Start in world editor mode.
 
.It Fl f
 
Fork into background (dedicated server only, see
 
.Fl D ) .
 
.It Fl g Op Ar savegame
 
.It Fl g Op Ar file
 
Load
 
.Ar savegame
 
at start or start a new game if omitted.
 
.Ar savegame
 
.Ar file
 
(can be either a savegame, scenario, or heightmap) at start or start a new game if omitted.
 
.Ar file
 
must be either an absolute path or one relative to the current path or one of
 
the search paths.
 
.It Fl G Ar seed
 
Seed the pseudo random number generator with
 
.Ar seed .
 
.It Fl h
src/fios.cpp
Show inline comments
 
@@ -444,15 +444,12 @@ std::tuple<FiosType, std::string> FiosGe
 
	/* Show savegame files
 
	 * .SAV OpenTTD saved game
 
	 * .SS1 Transport Tycoon Deluxe preset game
 
	 * .SV1 Transport Tycoon Deluxe (Patch) saved game
 
	 * .SV2 Transport Tycoon Deluxe (Patch) saved 2-player game */
 

	
 
	/* Don't crash if we supply no extension */
 
	if (ext.empty()) return { FIOS_TYPE_INVALID, {} };
 

	
 
	if (StrEqualsIgnoreCase(ext, ".sav")) {
 
		return { FIOS_TYPE_FILE, GetFileTitle(file, SAVE_DIR) };
 
	}
 

	
 
	if (fop == SLO_LOAD) {
 
		if (StrEqualsIgnoreCase(ext, ".ss1") || StrEqualsIgnoreCase(ext, ".sv1") ||
 
@@ -487,13 +484,13 @@ void FiosGetSavegameList(SaveLoadOperati
 
 * @param file Name of the file to check.
 
 * @param ext A pointer to the extension identifier inside file
 
 * @return a FIOS_TYPE_* type of the found file, FIOS_TYPE_INVALID if not a scenario and the title of the file (if any).
 
 * @see FiosGetFileList
 
 * @see FiosGetScenarioList
 
 */
 
static std::tuple<FiosType, std::string> FiosGetScenarioListCallback(SaveLoadOperation fop, const std::string &file, const std::string_view ext)
 
std::tuple<FiosType, std::string> FiosGetScenarioListCallback(SaveLoadOperation fop, const std::string &file, const std::string_view ext)
 
{
 
	/* Show scenario files
 
	 * .SCN OpenTTD style scenario file
 
	 * .SV0 Transport Tycoon Deluxe (Patch) scenario
 
	 * .SS0 Transport Tycoon Deluxe preset scenario */
 
	if (StrEqualsIgnoreCase(ext, ".scn")) {
 
@@ -527,13 +524,13 @@ void FiosGetScenarioList(SaveLoadOperati
 

	
 
	std::string base_path = FioFindDirectory(SCENARIO_DIR);
 
	Subdirectory subdir = (fop == SLO_LOAD && base_path == *_fios_path) ? SCENARIO_DIR : NO_DIRECTORY;
 
	FiosGetFileList(fop, &FiosGetScenarioListCallback, subdir, file_list);
 
}
 

	
 
static std::tuple<FiosType, std::string> FiosGetHeightmapListCallback(SaveLoadOperation, const std::string &file, const std::string_view ext)
 
std::tuple<FiosType, std::string> FiosGetHeightmapListCallback(SaveLoadOperation, const std::string &file, const std::string_view ext)
 
{
 
	/* Show heightmap files
 
	 * .PNG PNG Based heightmap files
 
	 * .BMP BMP Based heightmap files
 
	 */
 

	
src/fios.h
Show inline comments
 
@@ -114,12 +114,14 @@ std::string FiosGetCurrentPath();
 
std::optional<uint64_t> FiosGetDiskFreeSpace(const std::string &path);
 
bool FiosDelete(const char *name);
 
std::string FiosMakeHeightmapName(const char *name);
 
std::string FiosMakeSavegameName(const char *name);
 

	
 
std::tuple<FiosType, std::string> FiosGetSavegameListCallback(SaveLoadOperation fop, const std::string &file, const std::string_view ext);
 
std::tuple<FiosType, std::string> FiosGetScenarioListCallback(SaveLoadOperation fop, const std::string &file, const std::string_view ext);
 
std::tuple<FiosType, std::string> FiosGetHeightmapListCallback(SaveLoadOperation fop, const std::string &file, const std::string_view ext);
 

	
 
void ScanScenarios();
 
const char *FindScenario(const ContentInfo *ci, bool md5sum);
 

	
 
/**
 
 * A savegame name automatically numbered.
src/genworld.cpp
Show inline comments
 
@@ -100,14 +100,20 @@ static void _GenerateWorld()
 
		BasePersistentStorageArray::SwitchMode(PSM_ENTER_GAMELOOP);
 

	
 
		IncreaseGeneratingWorldProgress(GWP_MAP_INIT);
 
		/* Must start economy early because of the costs. */
 
		StartupEconomy();
 

	
 
		bool landscape_generated = false;
 

	
 
		/* Don't generate landscape items when in the scenario editor. */
 
		if (_gw.mode == GWM_EMPTY) {
 
		if (_gw.mode != GWM_EMPTY) {
 
			landscape_generated = GenerateLandscape(_gw.mode);
 
		}
 

	
 
		if (!landscape_generated) {
 
			SetGeneratingWorldProgress(GWP_OBJECT, 1);
 

	
 
			/* Make sure the tiles at the north border are void tiles if needed. */
 
			if (_settings_game.construction.freeform_edges) {
 
				for (uint x = 0; x < Map::SizeX(); x++) MakeVoid(TileXY(x, 0));
 
				for (uint y = 0; y < Map::SizeY(); y++) MakeVoid(TileXY(0, y));
 
@@ -118,13 +124,12 @@ static void _GenerateWorld()
 

	
 
			ConvertGroundTilesIntoWaterTiles();
 
			IncreaseGeneratingWorldProgress(GWP_OBJECT);
 

	
 
			_settings_game.game_creation.snow_line_height = DEF_SNOWLINE_HEIGHT;
 
		} else {
 
			GenerateLandscape(_gw.mode);
 
			GenerateClearTile();
 

	
 
			/* Only generate towns, tree and industries in newgame mode. */
 
			if (_game_mode != GM_EDITOR) {
 
				if (!GenerateTowns(_settings_game.economy.town_layout)) {
 
					HandleGeneratingWorldAbortion();
src/heightmap.cpp
Show inline comments
 
@@ -517,27 +517,29 @@ bool GetHeightmapDimensions(DetailedFile
 
 * Load a heightmap from file and change the map in its current dimensions
 
 *  to a landscape representing the heightmap.
 
 * It converts pixels to height. The brighter, the higher.
 
 * @param dft Type of image file.
 
 * @param filename of the heightmap file to be imported
 
 */
 
void LoadHeightmap(DetailedFileType dft, const char *filename)
 
bool LoadHeightmap(DetailedFileType dft, const char *filename)
 
{
 
	uint x, y;
 
	byte *map = nullptr;
 

	
 
	if (!ReadHeightMap(dft, filename, &x, &y, &map)) {
 
		free(map);
 
		return;
 
		return false;
 
	}
 

	
 
	GrayscaleToMapHeights(x, y, map);
 
	free(map);
 

	
 
	FixSlopes();
 
	MarkWholeScreenDirty();
 

	
 
	return true;
 
}
 

	
 
/**
 
 * Make an empty world where all tiles are of height 'tile_height'.
 
 * @param tile_height of the desired new empty world
 
 */
src/heightmap.h
Show inline comments
 
@@ -19,11 +19,11 @@
 
enum HeightmapRotation {
 
	HM_COUNTER_CLOCKWISE, ///< Rotate the map counter clockwise 45 degrees
 
	HM_CLOCKWISE,         ///< Rotate the map clockwise 45 degrees
 
};
 

	
 
bool GetHeightmapDimensions(DetailedFileType dft, const char *filename, uint *x, uint *y);
 
void LoadHeightmap(DetailedFileType dft, const char *filename);
 
bool LoadHeightmap(DetailedFileType dft, const char *filename);
 
void FlatEmptyWorld(byte tile_height);
 
void FixSlopes();
 

	
 
#endif /* HEIGHTMAP_H */
src/landscape.cpp
Show inline comments
 
@@ -1554,13 +1554,13 @@ static void CalculateSnowLine()
 
static uint8_t CalculateDesertLine()
 
{
 
	/* CalculateCoverageLine() runs from top to bottom, so we need to invert the coverage. */
 
	return CalculateCoverageLine(100 - _settings_game.game_creation.desert_coverage, 4);
 
}
 

	
 
void GenerateLandscape(byte mode)
 
bool GenerateLandscape(byte mode)
 
{
 
	/** Number of steps of landscape generation */
 
	enum GenLandscapeSteps {
 
		GLS_HEIGHTMAP    =  3, ///< Loading a heightmap
 
		GLS_TERRAGENESIS =  5, ///< Terragenesis generator
 
		GLS_ORIGINAL     =  2, ///< Original generator
 
@@ -1568,13 +1568,15 @@ void GenerateLandscape(byte mode)
 
		GLS_OTHER        =  0, ///< Extra steps for other landscapes
 
	};
 
	uint steps = (_settings_game.game_creation.landscape == LT_TROPIC) ? GLS_TROPIC : GLS_OTHER;
 

	
 
	if (mode == GWM_HEIGHTMAP) {
 
		SetGeneratingWorldProgress(GWP_LANDSCAPE, steps + GLS_HEIGHTMAP);
 
		LoadHeightmap(_file_to_saveload.detail_ftype, _file_to_saveload.name.c_str());
 
		if (!LoadHeightmap(_file_to_saveload.detail_ftype, _file_to_saveload.name.c_str())) {
 
			return false;
 
		}
 
		IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
 
	} else if (_settings_game.game_creation.land_generator == LG_TERRAGENESIS) {
 
		SetGeneratingWorldProgress(GWP_LANDSCAPE, steps + GLS_TERRAGENESIS);
 
		GenerateTerrainPerlin();
 
	} else {
 
		SetGeneratingWorldProgress(GWP_LANDSCAPE, steps + GLS_ORIGINAL);
 
@@ -1654,12 +1656,13 @@ void GenerateLandscape(byte mode)
 

	
 
		default:
 
			break;
 
	}
 

	
 
	CreateRivers();
 
	return true;
 
}
 

	
 
void OnTick_Town();
 
void OnTick_Trees();
 
void OnTick_Station();
 
void OnTick_Industry();
src/landscape.h
Show inline comments
 
@@ -136,9 +136,9 @@ bool HasFoundationNW(TileIndex tile, Slo
 
bool HasFoundationNE(TileIndex tile, Slope slope_here, uint z_here);
 

	
 
void DoClearSquare(TileIndex tile);
 
void RunTileLoop();
 

	
 
void InitializeLandscape();
 
void GenerateLandscape(byte mode);
 
bool GenerateLandscape(byte mode);
 

	
 
#endif /* LANDSCAPE_H */
src/openttd.cpp
Show inline comments
 
@@ -162,13 +162,13 @@ static void ShowHelp()
 
		"  -b drv              = Set the blitter to use (see below)\n"
 
		"  -r res              = Set resolution (for instance 800x600)\n"
 
		"  -h                  = Display this help text\n"
 
		"  -t year             = Set starting year\n"
 
		"  -d [[fac=]lvl[,...]]= Debug mode\n"
 
		"  -e                  = Start Editor\n"
 
		"  -g [savegame]       = Start new/save game immediately\n"
 
		"  -g [savegame|scenario|heightmap] = Start new/savegame/scenario/heightmap immediately\n"
 
		"  -G seed             = Set random seed\n"
 
		"  -n host[:port][#company]= Join network game\n"
 
		"  -p password         = Password to join server\n"
 
		"  -P password         = Password to join company\n"
 
		"  -D [host][:port]    = Start dedicated server\n"
 
#if !defined(_WIN32)
 
@@ -574,27 +574,43 @@ int openttd_main(int argc, char *argv[])
 
#if defined(_WIN32)
 
				CreateConsole();
 
#endif
 
				if (mgo.opt != nullptr) SetDebugString(mgo.opt, ShowInfoI);
 
				break;
 
			}
 
		case 'e': _switch_mode = (_switch_mode == SM_LOAD_GAME || _switch_mode == SM_LOAD_SCENARIO ? SM_LOAD_SCENARIO : SM_EDITOR); break;
 
		case 'e':
 
			/* Allow for '-e' before or after '-g'. */
 
			switch (_switch_mode) {
 
				case SM_MENU: _switch_mode = SM_EDITOR; break;
 
				case SM_LOAD_GAME: _switch_mode = SM_LOAD_SCENARIO; break;
 
				case SM_START_HEIGHTMAP: _switch_mode = SM_LOAD_HEIGHTMAP; break;
 
				default: break;
 
			}
 
			break;
 
		case 'g':
 
			if (mgo.opt != nullptr) {
 
				_file_to_saveload.name = mgo.opt;
 
				bool is_scenario = _switch_mode == SM_EDITOR || _switch_mode == SM_LOAD_SCENARIO;
 
				_switch_mode = is_scenario ? SM_LOAD_SCENARIO : SM_LOAD_GAME;
 
				_file_to_saveload.SetMode(SLO_LOAD, is_scenario ? FT_SCENARIO : FT_SAVEGAME, DFT_GAME_FILE);
 

	
 
				/* if the file doesn't exist or it is not a valid savegame, let the saveload code show an error */
 
				auto t = _file_to_saveload.name.find_last_of('.');
 
				if (t != std::string::npos) {
 
					auto [ft, _] = FiosGetSavegameListCallback(SLO_LOAD, _file_to_saveload.name, _file_to_saveload.name.substr(t));
 
					if (ft != FIOS_TYPE_INVALID) _file_to_saveload.SetMode(ft);
 
				std::string extension = std::filesystem::path(_file_to_saveload.name).extension().string();
 
				auto [ft, _] = FiosGetSavegameListCallback(SLO_LOAD, _file_to_saveload.name, extension);
 
				if (ft == FIOS_TYPE_INVALID) {
 
					std::tie(ft, _) = FiosGetScenarioListCallback(SLO_LOAD, _file_to_saveload.name, extension);
 
				}
 
				if (ft == FIOS_TYPE_INVALID) {
 
					std::tie(ft, _) = FiosGetHeightmapListCallback(SLO_LOAD, _file_to_saveload.name, extension);
 
				}
 

	
 
				/* Allow for '-e' before or after '-g'. */
 
				switch (GetAbstractFileType(ft)) {
 
					case FT_SAVEGAME: _switch_mode = (_switch_mode == SM_EDITOR ? SM_LOAD_SCENARIO : SM_LOAD_GAME); break;
 
					case FT_SCENARIO: _switch_mode = (_switch_mode == SM_EDITOR ? SM_LOAD_SCENARIO : SM_LOAD_GAME); break;
 
					case FT_HEIGHTMAP: _switch_mode = (_switch_mode == SM_EDITOR ? SM_LOAD_HEIGHTMAP : SM_START_HEIGHTMAP); break;
 
					default: break;
 
				}
 

	
 
				_file_to_saveload.SetMode(SLO_LOAD, GetAbstractFileType(ft), GetDetailedFileType(ft));
 
				break;
 
			}
 

	
 
			_switch_mode = SM_NEWGAME;
 
			/* Give a random map if no seed has been given */
 
			if (scanner->generation_seed == GENERATE_NEW_SEED) {
 
@@ -1128,12 +1144,14 @@ void SwitchToMode(SwitchMode new_mode)
 
			UpdateSocialIntegration(GM_NORMAL);
 
			break;
 

	
 
		case SM_LOAD_HEIGHTMAP: // Load heightmap from scenario editor
 
			SetLocalCompany(OWNER_NONE);
 

	
 
			_game_mode = GM_EDITOR;
 

	
 
			GenerateWorld(GWM_HEIGHTMAP, 1 << _settings_game.game_creation.map_x, 1 << _settings_game.game_creation.map_y);
 
			GenerateSavegameId();
 
			MarkWholeScreenDirty();
 

	
 
			UpdateSocialIntegration(GM_EDITOR);
 
			break;
src/video/dedicated_v.cpp
Show inline comments
 
@@ -201,14 +201,14 @@ void VideoDriver_Dedicated::MainLoop()
 

	
 
	/* Load the dedicated server stuff */
 
	_is_network_server = true;
 
	_network_dedicated = true;
 
	_current_company = _local_company = COMPANY_SPECTATOR;
 

	
 
	/* If SwitchMode is SM_LOAD_GAME, it means that the user used the '-g' options */
 
	if (_switch_mode != SM_LOAD_GAME) {
 
	/* If SwitchMode is SM_LOAD_GAME / SM_START_HEIGHTMAP, it means that the user used the '-g' options */
 
	if (_switch_mode != SM_LOAD_GAME && _switch_mode != SM_START_HEIGHTMAP) {
 
		StartNewGameWithoutGUI(GENERATE_NEW_SEED);
 
	}
 

	
 
	this->is_game_threaded = false;
 

	
 
	/* Done loading, start game! */
0 comments (0 inline, 0 general)