From eee6e228c7abdcc7803e22783e7452289a513707 Mon Sep 17 00:00:00 2001 From: rubidium Date: Tue, 18 May 2010 21:44:47 +0000 Subject: [PATCH] (svn r19857) [1.0] -Backport from trunk: - Fix: If a waypoint is immediately followed by a path signal a reservation would be made from that path signal before the waypoint is marked passed. As a result the order to go to the waypoint is used to reserve the path after the waypoint and as such trains get lost [FS#3770] (r19784) - Fix: NULL pointer deference when testing relative scope *action2 on an unbuilt engine [FS#3828] (r19782) - Fix: Crash on too long paths [FS#3807] (r19780, r19779, r19778, r19777, r19776) - Fix: MP_VOID tiles shall have no tropic zone [FS#3820] (r19769) - Fix: Half-desert tiles would never revert back to clear tiles (r19768) --- src/clear_cmd.cpp | 37 +++++++++++--- src/fileio.cpp | 88 +++++++++------------------------ src/fileio_func.h | 10 +++- src/landscape.cpp | 4 ++ src/network/network_content.cpp | 4 +- src/newgrf_engine.cpp | 1 + src/os/unix/unix.cpp | 9 ++-- src/saveload/afterload.cpp | 7 +++ src/script/script_scanner.cpp | 3 -- src/stdafx.h | 8 ++- src/tile_map.h | 1 + src/train_cmd.cpp | 2 + 12 files changed, 90 insertions(+), 84 deletions(-) diff --git a/src/clear_cmd.cpp b/src/clear_cmd.cpp index 6497ed1f12..2f91f2fd0f 100644 --- a/src/clear_cmd.cpp +++ b/src/clear_cmd.cpp @@ -189,19 +189,40 @@ static void TileLoopClearAlps(TileIndex tile) MarkTileDirtyByTile(tile); } +/** + * Tests if at least one surrounding tile is desert + * @param tile tile to check + * @return does this tile have at least one desert tile around? + */ +static inline bool NeighbourIsDesert(TileIndex tile) +{ + return GetTropicZone(tile + TileDiffXY( 1, 0)) == TROPICZONE_DESERT || + GetTropicZone(tile + TileDiffXY( -1, 0)) == TROPICZONE_DESERT || + GetTropicZone(tile + TileDiffXY( 0, 1)) == TROPICZONE_DESERT || + GetTropicZone(tile + TileDiffXY( 0, -1)) == TROPICZONE_DESERT; +} + static void TileLoopClearDesert(TileIndex tile) { - if (IsClearGround(tile, CLEAR_DESERT)) return; + /* Current desert level - 0 if it is not desert */ + uint current = 0; + if (IsClearGround(tile, CLEAR_DESERT)) current = GetClearDensity(tile); + /* Expected desert level - 0 if it shouldn't be desert */ + uint expected = 0; if (GetTropicZone(tile) == TROPICZONE_DESERT) { - SetClearGroundDensity(tile, CLEAR_DESERT, 3); + expected = 3; + } else if (NeighbourIsDesert(tile)) { + expected = 1; + } + + if (current == expected) return; + + if (expected == 0) { + SetClearGroundDensity(tile, CLEAR_GRASS, 3); } else { - if (GetTropicZone(tile + TileDiffXY( 1, 0)) != TROPICZONE_DESERT && - GetTropicZone(tile + TileDiffXY(-1, 0)) != TROPICZONE_DESERT && - GetTropicZone(tile + TileDiffXY( 0, 1)) != TROPICZONE_DESERT && - GetTropicZone(tile + TileDiffXY( 0, -1)) != TROPICZONE_DESERT) - return; - SetClearGroundDensity(tile, CLEAR_DESERT, 1); + /* Transition from clear to desert is not smooth (after clearing desert tile) */ + SetClearGroundDensity(tile, CLEAR_DESERT, expected); } MarkTileDirtyByTile(tile); diff --git a/src/fileio.cpp b/src/fileio.cpp index b05e5a6486..e329571478 100644 --- a/src/fileio.cpp +++ b/src/fileio.cpp @@ -448,16 +448,21 @@ void FioCreateDirectory(const char *name) * It does not add the path separator to zero-sized strings. * @param buf string to append the separator to * @param buflen the length of the buf + * @return true iff the operation succeeded */ -void AppendPathSeparator(char *buf, size_t buflen) +bool AppendPathSeparator(char *buf, size_t buflen) { size_t s = strlen(buf); /* Length of string + path separator + '\0' */ - if (s != 0 && buf[s - 1] != PATHSEPCHAR && s + 2 < buflen) { + if (s != 0 && buf[s - 1] != PATHSEPCHAR) { + if (s + 2 >= buflen) return false; + buf[s] = PATHSEPCHAR; buf[s + 1] = '\0'; } + + return true; } /** @@ -534,7 +539,18 @@ static void SimplifyFileName(char *name) #endif } -bool TarListAddFile(const char *filename) +/* static */ uint TarScanner::DoScan() { + DEBUG(misc, 1, "Scanning for tars"); + TarScanner fs; + uint num = fs.Scan(".tar", DATA_DIR, false); + num += fs.Scan(".tar", AI_DIR, false); + num += fs.Scan(".tar", AI_LIBRARY_DIR, false); + num += fs.Scan(".tar", SCENARIO_DIR, false); + DEBUG(misc, 1, "Scan complete, found %d files", num); + return num; +} + +bool TarScanner::AddFile(const char *filename, size_t basepath_length) { /* The TAR-header, repeated for every file */ typedef struct TarHeader { @@ -820,66 +836,6 @@ bool ExtractTar(const char *tar_filename) return true; } -static int ScanPathForTarFiles(const char *path, size_t basepath_length) -{ - extern bool FiosIsValidFile(const char *path, const struct dirent *ent, struct stat *sb); - - uint num = 0; - struct stat sb; - struct dirent *dirent; - DIR *dir; - - if (path == NULL || (dir = ttd_opendir(path)) == NULL) return 0; - - while ((dirent = readdir(dir)) != NULL) { - const char *d_name = FS2OTTD(dirent->d_name); - char filename[MAX_PATH]; - - if (!FiosIsValidFile(path, dirent, &sb)) continue; - - snprintf(filename, lengthof(filename), "%s%s", path, d_name); - - if (S_ISDIR(sb.st_mode)) { - /* Directory */ - if (strcmp(d_name, ".") == 0 || strcmp(d_name, "..") == 0) continue; - AppendPathSeparator(filename, lengthof(filename)); - num += ScanPathForTarFiles(filename, basepath_length); - } else if (S_ISREG(sb.st_mode)) { - /* File */ - char *ext = strrchr(filename, '.'); - - /* If no extension or extension isn't .tar, skip the file */ - if (ext == NULL) continue; - if (strcasecmp(ext, ".tar") != 0) continue; - - if (TarListAddFile(filename)) num++; - } - } - - closedir(dir); - return num; -} - -void ScanForTarFiles() -{ - Searchpath sp; - char path[MAX_PATH]; - uint num = 0; - - DEBUG(misc, 1, "Scanning for tars"); - FOR_ALL_SEARCHPATHS(sp) { - FioAppendDirectory(path, MAX_PATH, sp, DATA_DIR); - num += ScanPathForTarFiles(path, strlen(path)); - FioAppendDirectory(path, MAX_PATH, sp, AI_DIR); - num += ScanPathForTarFiles(path, strlen(path)); - FioAppendDirectory(path, MAX_PATH, sp, AI_LIBRARY_DIR); - num += ScanPathForTarFiles(path, strlen(path)); - FioAppendDirectory(path, MAX_PATH, sp, SCENARIO_DIR); - num += ScanPathForTarFiles(path, strlen(path)); - } - DEBUG(misc, 1, "Scan complete, found %d files", num); -} - #if defined(WIN32) || defined(WINCE) /** * Determine the base (personal dir and game data dir) paths @@ -1079,7 +1035,7 @@ void DeterminePaths(const char *exe) } #endif /* ENABLE_NETWORK */ - ScanForTarFiles(); + TarScanner::DoScan(); } /** @@ -1158,7 +1114,7 @@ static uint ScanPath(FileScanner *fs, const char *extension, const char *path, s /* Directory */ if (!recursive) continue; if (strcmp(d_name, ".") == 0 || strcmp(d_name, "..") == 0) continue; - AppendPathSeparator(filename, lengthof(filename)); + if (!AppendPathSeparator(filename, lengthof(filename))) continue; num += ScanPath(fs, extension, filename, basepath_length, recursive); } else if (S_ISREG(sb.st_mode)) { /* File */ @@ -1245,6 +1201,6 @@ uint FileScanner::Scan(const char *extension, const char *directory, bool recurs { char path[MAX_PATH]; strecpy(path, directory, lastof(path)); - AppendPathSeparator(path, lengthof(path)); + if (!AppendPathSeparator(path, lengthof(path))) return 0; return ScanPath(this, extension, path, strlen(path), recursive); } diff --git a/src/fileio_func.h b/src/fileio_func.h index 53b3aa233c..e4137267c1 100644 --- a/src/fileio_func.h +++ b/src/fileio_func.h @@ -57,7 +57,7 @@ char *FioAppendDirectory(char *buf, size_t buflen, Searchpath sp, Subdirectory s char *FioGetDirectory(char *buf, size_t buflen, Subdirectory subdir); void SanitizeFilename(char *filename); -void AppendPathSeparator(char *buf, size_t buflen); +bool AppendPathSeparator(char *buf, size_t buflen); void DeterminePaths(const char *exe); void *ReadFileToMem(const char *filename, size_t *lenp, size_t maxsize); bool FileExists(const char *filename); @@ -87,6 +87,14 @@ public: virtual bool AddFile(const char *filename, size_t basepath_length) = 0; }; +/** Helper for scanning for files with tar as extension */ +class TarScanner : FileScanner { +public: + /* virtual */ bool AddFile(const char *filename, size_t basepath_length); + + /** Do the scan for Tars. */ + static uint DoScan(); +}; /* Implementation of opendir/readdir/closedir for Windows */ #if defined(WIN32) diff --git a/src/landscape.cpp b/src/landscape.cpp index e85c22d824..d013f7dd96 100644 --- a/src/landscape.cpp +++ b/src/landscape.cpp @@ -827,6 +827,8 @@ static void CreateDesertOrRainForest() for (TileIndex tile = 0; tile != MapSize(); ++tile) { if ((tile % update_freq) == 0) IncreaseGeneratingWorldProgress(GWP_LANDSCAPE); + if (!IsValidTile(tile)) continue; + for (data = _make_desert_or_rainforest_data; data != endof(_make_desert_or_rainforest_data); ++data) { TileIndex t = AddTileIndexDiffCWrap(tile, *data); @@ -845,6 +847,8 @@ static void CreateDesertOrRainForest() for (TileIndex tile = 0; tile != MapSize(); ++tile) { if ((tile % update_freq) == 0) IncreaseGeneratingWorldProgress(GWP_LANDSCAPE); + if (!IsValidTile(tile)) continue; + for (data = _make_desert_or_rainforest_data; data != endof(_make_desert_or_rainforest_data); ++data) { TileIndex t = AddTileIndexDiffCWrap(tile, *data); diff --git a/src/network/network_content.cpp b/src/network/network_content.cpp index 06e30f736b..6360597de9 100644 --- a/src/network/network_content.cpp +++ b/src/network/network_content.cpp @@ -27,7 +27,6 @@ #include #endif -extern bool TarListAddFile(const char *filename); extern bool HasScenario(const ContentInfo *ci, bool md5sum); ClientNetworkContentSocketHandler _network_content_client; @@ -498,7 +497,8 @@ void ClientNetworkContentSocketHandler::AfterDownload() if (GunzipFile(this->curInfo)) { unlink(GetFullFilename(this->curInfo, true)); - TarListAddFile(GetFullFilename(this->curInfo, false)); + TarScanner ts; + ts.AddFile(GetFullFilename(this->curInfo, false), 0); if (this->curInfo->type == CONTENT_TYPE_BASE_MUSIC) { /* Music can't be in a tar. So extract the tar! */ diff --git a/src/newgrf_engine.cpp b/src/newgrf_engine.cpp index 515e7f60e3..266cfbc292 100644 --- a/src/newgrf_engine.cpp +++ b/src/newgrf_engine.cpp @@ -383,6 +383,7 @@ static inline const Vehicle *GRV(const ResolverObject *object) case VSG_SCOPE_SELF: return object->u.vehicle.self; case VSG_SCOPE_PARENT: return object->u.vehicle.parent; case VSG_SCOPE_RELATIVE: { + if (object->u.vehicle.self == NULL) return NULL; const Vehicle *v = NULL; switch (GB(object->count, 6, 2)) { default: NOT_REACHED(); diff --git a/src/os/unix/unix.cpp b/src/os/unix/unix.cpp index a9b81e62cd..44b27bbad7 100644 --- a/src/os/unix/unix.cpp +++ b/src/os/unix/unix.cpp @@ -92,17 +92,20 @@ bool FiosGetDiskFreeSpace(const char *path, uint64 *tot) bool FiosIsValidFile(const char *path, const struct dirent *ent, struct stat *sb) { char filename[MAX_PATH]; - + int res; #if defined(__MORPHOS__) || defined(__AMIGAOS__) /* On MorphOS or AmigaOS paths look like: "Volume:directory/subdirectory" */ if (FiosIsRoot(path)) { - snprintf(filename, lengthof(filename), "%s:%s", path, ent->d_name); + res = snprintf(filename, lengthof(filename), "%s:%s", path, ent->d_name); } else // XXX - only next line! #else assert(path[strlen(path) - 1] == PATHSEPCHAR); if (strlen(path) > 2) assert(path[strlen(path) - 2] != PATHSEPCHAR); #endif - snprintf(filename, lengthof(filename), "%s%s", path, ent->d_name); + res = snprintf(filename, lengthof(filename), "%s%s", path, ent->d_name); + + /* Could we fully concatenate the path and filename? */ + if (res >= (int)lengthof(filename) || res < 0) return false; return stat(filename, sb) == 0; } diff --git a/src/saveload/afterload.cpp b/src/saveload/afterload.cpp index d85b5d2328..84746dd953 100644 --- a/src/saveload/afterload.cpp +++ b/src/saveload/afterload.cpp @@ -2065,6 +2065,13 @@ bool AfterLoadGame() } } + if (CheckSavegameVersion(141)) { + for (TileIndex t = 0; t < map_size; t++) { + /* Reset tropic zone for VOID tiles, they shall not have any. */ + if (IsTileType(t, MP_VOID)) SetTropicZone(t, TROPICZONE_NORMAL); + } + } + /* Road stops is 'only' updating some caches */ AfterLoadRoadStops(); AfterLoadLabelMaps(); diff --git a/src/script/script_scanner.cpp b/src/script/script_scanner.cpp index 308aea8fe9..5c6a738013 100644 --- a/src/script/script_scanner.cpp +++ b/src/script/script_scanner.cpp @@ -87,9 +87,6 @@ void ScriptScanner::ScanScriptDir(const char *info_file_name, Subdirectory searc char buf[MAX_PATH]; Searchpath sp; - extern void ScanForTarFiles(); - ScanForTarFiles(); - FOR_ALL_SEARCHPATHS(sp) { FioAppendDirectory(buf, MAX_PATH, sp, search_dir); if (FileExists(buf)) this->ScanDir(buf, info_file_name); diff --git a/src/stdafx.h b/src/stdafx.h index 35ec1f1367..b008d0e670 100644 --- a/src/stdafx.h +++ b/src/stdafx.h @@ -395,7 +395,13 @@ void NORETURN CDECL error(const char *str, ...) WARN_FORMAT(1, 2); #define _stricmp strcasecmp #endif -#if !defined(MAX_PATH) +#if defined(MAX_PATH) + /* It's already defined, no need to override */ +#elif defined(PATH_MAX) && PATH_MAX > 0 + /* Use the value from PATH_MAX, if it exists */ + #define MAX_PATH PATH_MAX +#else + /* If all else fails, hardcode something :( */ #define MAX_PATH 260 #endif diff --git a/src/tile_map.h b/src/tile_map.h index fcbe2199c0..393b89e017 100644 --- a/src/tile_map.h +++ b/src/tile_map.h @@ -186,6 +186,7 @@ static inline bool IsTileOwner(TileIndex tile, Owner owner) static inline void SetTropicZone(TileIndex tile, TropicZone type) { assert(tile < MapSize()); + assert(!IsTileType(tile, MP_VOID) || type == TROPICZONE_NORMAL); SB(_m[tile].m6, 0, 2, type); } diff --git a/src/train_cmd.cpp b/src/train_cmd.cpp index b1e6578beb..0c26204978 100644 --- a/src/train_cmd.cpp +++ b/src/train_cmd.cpp @@ -2230,6 +2230,8 @@ static void CheckNextTrainTile(Train *v) if ((v->tile == v->dest_tile && v->current_order.IsType(OT_GOTO_DEPOT)) || v->track == TRACK_BIT_DEPOT) return; /* Exit if we are on a station tile and are going to stop. */ if (IsRailStationTile(v->tile) && v->current_order.ShouldStopAtStation(v, GetStationIndex(v->tile))) return; + /* If we reached our waypoint, make sure we see that. */ + if (v->current_order.IsType(OT_GOTO_WAYPOINT) && IsRailWaypointTile(v->tile) && GetStationIndex(v->tile) == v->current_order.GetDestination()) ProcessOrders(v); /* Exit if the current order doesn't have a destination, but the train has orders. */ if ((v->current_order.IsType(OT_NOTHING) || v->current_order.IsType(OT_LEAVESTATION) || v->current_order.IsType(OT_LOADING)) && v->GetNumOrders() > 0) return;