|
|
|
@ -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 */
|
|
|
|
|