changeset 11283:65d6451a3be8 draft

(svn r15632) -Feature: allow downloading scenarios and heightmaps via bananas.
author rubidium <rubidium@openttd.org>
date Fri, 06 Mar 2009 19:33:45 +0000
parents 7f5ce1bf8883
children bace6a2ec632
files src/fios.cpp src/network/network_content.cpp src/network/network_content_gui.cpp
diffstat 3 files changed, 126 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/src/fios.cpp
+++ b/src/fios.cpp
@@ -495,3 +495,114 @@
 
 	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 */
--- 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 @@
 			proc = AI::HasAI; break;
 			break;
 
+		case CONTENT_TYPE_SCENARIO:
+		case CONTENT_TYPE_HEIGHTMAP:
+			proc = HasScenario;
+			break;
+
 		default:
 			break;
 	}
@@ -143,6 +149,8 @@
 {
 	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);
--- a/src/network/network_content_gui.cpp
+++ b/src/network/network_content_gui.cpp
@@ -98,6 +98,13 @@
 					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;
 			}