summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorrubidium <rubidium@openttd.org>2009-03-06 19:33:45 +0000
committerrubidium <rubidium@openttd.org>2009-03-06 19:33:45 +0000
commitd5762a506985abfe90d04150d4952f94c644f8a2 (patch)
tree785d2e3194f2744aa1c4620d6c6364ac056d5a8a
parent86229361c8d4fad06b3ae6e21950304104bcaeb4 (diff)
downloadopenttd-d5762a506985abfe90d04150d4952f94c644f8a2.tar.xz
(svn r15632) -Feature: allow downloading scenarios and heightmaps via bananas.
-rw-r--r--src/fios.cpp111
-rw-r--r--src/network/network_content.cpp8
-rw-r--r--src/network/network_content_gui.cpp7
3 files changed, 126 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 */
diff --git a/src/network/network_content.cpp b/src/network/network_content.cpp
index 83740c81c..3a558c7d5 100644
--- a/src/network/network_content.cpp
+++ b/src/network/network_content.cpp
@@ -22,6 +22,7 @@
extern bool TarListAddFile(const char *filename);
extern bool HasGraphicsSet(const ContentInfo *ci, bool md5sum);
+extern bool HasScenario(const ContentInfo *ci, bool md5sum);
ClientNetworkContentSocketHandler _network_content_client;
/** Wrapper function for the HasProc */
@@ -86,6 +87,11 @@ DEF_CONTENT_RECEIVE_COMMAND(Client, PACKET_CONTENT_SERVER_INFO)
proc = AI::HasAI; break;
break;
+ case CONTENT_TYPE_SCENARIO:
+ case CONTENT_TYPE_HEIGHTMAP:
+ proc = HasScenario;
+ break;
+
default:
break;
}
@@ -143,6 +149,8 @@ void ClientNetworkContentSocketHandler::RequestContentList(ContentType type)
{
if (type == CONTENT_TYPE_END) {
this->RequestContentList(CONTENT_TYPE_BASE_GRAPHICS);
+ this->RequestContentList(CONTENT_TYPE_SCENARIO);
+ this->RequestContentList(CONTENT_TYPE_HEIGHTMAP);
this->RequestContentList(CONTENT_TYPE_AI);
this->RequestContentList(CONTENT_TYPE_NEWGRF);
this->RequestContentList(CONTENT_TYPE_AI_LIBRARY);
diff --git a/src/network/network_content_gui.cpp b/src/network/network_content_gui.cpp
index a2be8557d..2c2f9eac6 100644
--- a/src/network/network_content_gui.cpp
+++ b/src/network/network_content_gui.cpp
@@ -98,6 +98,13 @@ public:
InvalidateWindowData(WC_NETWORK_WINDOW, 0, 2);
break;
+ case CONTENT_TYPE_SCENARIO:
+ case CONTENT_TYPE_HEIGHTMAP:
+ InvalidateWindowClasses(WC_SAVELOAD);
+ extern void ScanScenarios();
+ ScanScenarios();
+ break;
+
default:
break;
}