diff options
Diffstat (limited to 'src/fios.cpp')
-rw-r--r-- | src/fios.cpp | 111 |
1 files changed, 111 insertions, 0 deletions
diff --git a/src/fios.cpp b/src/fios.cpp index 3fb5dabe4..3a365e62f 100644 --- a/src/fios.cpp +++ b/src/fios.cpp @@ -495,3 +495,114 @@ void FiosGetHeightmapList(SaveLoadDialogMode mode) FiosGetFileList(mode, &FiosGetHeightmapListCallback, strcmp(base_path, _fios_path) == 0 ? HEIGHTMAP_DIR : NO_DIRECTORY); } + +#if defined(ENABLE_NETWORK) +#include "core/smallvec_type.hpp" +#include "network/network_content.h" +#include "md5.h" + +/** Basic data to distinguish a scenario. Used in the server list window */ +struct ScenarioIdentifier { + uint32 scenid; ///< ID for the scenario (generated by content) + uint8 md5sum[16]; ///< MD5 checksum of file + + bool operator == (const ScenarioIdentifier &other) const + { + return this->scenid == other.scenid && + memcmp(this->md5sum, other.md5sum, sizeof(this->md5sum)) == 0; + } + + bool operator != (const ScenarioIdentifier &other) const + { + return !(*this == other); + } +}; + +/** + * Scanner to find the unique IDs of scenarios + */ +class ScenarioScanner : protected FileScanner, public SmallVector<ScenarioIdentifier, 8> { + bool scanned; ///< Whether we've already scanned +public: + /** Initialise */ + ScenarioScanner() : scanned(false) {} + + /** + * Scan, but only if it's needed. + * @param rescan whether to force scanning even when it's not necessary + */ + void Scan(bool rescan) + { + if (this->scanned && !rescan) return; + + this->FileScanner::Scan(".id", SCENARIO_DIR, true, true); + this->scanned = true; + } + + /* virtual */ bool AddFile(const char *filename, size_t basepath_length) + { + FILE *f = FioFOpenFile(filename, "r"); + if (f == NULL) return false; + + ScenarioIdentifier id; + fscanf(f, "%i", &id.scenid); + FioFCloseFile(f); + + Md5 checksum; + uint8 buffer[1024]; + size_t len, size; + + /* open the scenario file, but first get the name. + * This is safe as we check on extension which + * must always exist. */ + *strrchr(filename, '.') = '\0'; + f = FioFOpenFile(filename, "rb", SCENARIO_DIR, &size); + if (f == NULL) return false; + + /* calculate md5sum */ + while ((len = fread(buffer, 1, (size > sizeof(buffer)) ? sizeof(buffer) : size, f)) != 0 && size != 0) { + size -= len; + checksum.Append(buffer, len); + } + checksum.Finish(id.md5sum); + + FioFCloseFile(f); + + this->Include(id); + return true; + } +}; + +/** Scanner for scenarios */ +static ScenarioScanner _scanner; + +/** + * Check whether we've got a given scenario based on it's unique ID. + * @param ci the content info to compare it to + * @param md5sum whether to look at the md5sum or the id + * @return true if we've got the scenario + */ +bool HasScenario(const ContentInfo *ci, bool md5sum) +{ + _scanner.Scan(false); + + for (ScenarioIdentifier *id = _scanner.Begin(); id != _scanner.End(); id++) { + if (md5sum ? + (memcmp(id->md5sum, ci->md5sum, sizeof(id->md5sum)) == 0) : + (id->scenid == ci->unique_id)) { + return true; + } + } + + return false; +} + +/** + * Force a (re)scan of the scenarios. + */ +void ScanScenarios() +{ + _scanner.Scan(true); +} + +#endif /* ENABLE_NETWORK */ |