changeset 18764:bd2a1a20a792 draft

(svn r23612) -Add: allow importing libraries in the same way as AI does, only with GS prefix (and in game/library)
author truebrain <truebrain@openttd.org>
date Mon, 19 Dec 2011 20:56:59 +0000
parents 10757b027360
children 5fbaf80f0375
files src/console_cmds.cpp src/fileio.cpp src/fileio_type.h src/game/game.hpp src/game/game_core.cpp src/game/game_info.cpp src/game/game_info.hpp src/game/game_instance.cpp src/game/game_scanner.cpp src/game/game_scanner.hpp src/network/core/tcp_content.h src/network/network_content.cpp src/script/api/game/game_controller.hpp.sq src/script/squirrel.cpp
diffstat 14 files changed, 214 insertions(+), 27 deletions(-) [+]
line wrap: on
line diff
--- a/src/console_cmds.cpp
+++ b/src/console_cmds.cpp
@@ -1106,6 +1106,16 @@
 	return true;
 }
 
+DEF_CONSOLE_CMD(ConListGameLibs)
+{
+	char buf[4096];
+	Game::GetConsoleLibraryList(buf, lastof(buf));
+
+	PrintLineByLine(buf);
+
+	return true;
+}
+
 DEF_CONSOLE_CMD(ConListGame)
 {
 	char buf[4096];
@@ -1743,7 +1753,7 @@
 	if (strcasecmp(argv[1], "state") == 0) {
 		IConsolePrintF(CC_WHITE, "id, type, state, name");
 		for (ConstContentIterator iter = _network_content_client.Begin(); iter != _network_content_client.End(); iter++) {
-			static const char * const types[] = { "Base graphics", "NewGRF", "AI", "AI library", "Scenario", "Heightmap", "Base sound", "Base music", "Game script" };
+			static const char * const types[] = { "Base graphics", "NewGRF", "AI", "AI library", "Scenario", "Heightmap", "Base sound", "Base music", "Game script", "GS library" };
 			assert_compile(lengthof(types) == CONTENT_TYPE_END - CONTENT_TYPE_BEGIN);
 			static const char * const states[] = { "Not selected", "Selected", "Dep Selected", "Installed", "Unknown" };
 			static const TextColour state_to_colour[] = { CC_COMMAND, CC_INFO, CC_INFO, CC_WHITE, CC_ERROR };
@@ -1907,6 +1917,7 @@
 	IConsoleCmdRegister("stop_ai",      ConStopAI);
 
 	IConsoleCmdRegister("list_game",    ConListGame);
+	IConsoleCmdRegister("list_game_libs", ConListGameLibs);
 
 	/* networking functions */
 #ifdef ENABLE_NETWORK
--- a/src/fileio.cpp
+++ b/src/fileio.cpp
@@ -282,6 +282,7 @@
 	"ai" PATHSEP,
 	"ai" PATHSEP "library" PATHSEP,
 	"game" PATHSEP,
+	"game" PATHSEP "library" PATHSEP,
 };
 assert_compile(lengthof(_subdirs) == NUM_SUBDIRS);
 
@@ -678,6 +679,7 @@
 	}
 	if (mode & TarScanner::GAME) {
 		num += fs.DoScan(GAME_DIR);
+		num += fs.DoScan(GAME_LIBRARY_DIR);
 	}
 	if (mode & TarScanner::SCENARIO) {
 		num += fs.DoScan(SCENARIO_DIR);
@@ -1199,7 +1201,7 @@
 #endif
 
 	static const Subdirectory default_subdirs[] = {
-		SAVE_DIR, AUTOSAVE_DIR, SCENARIO_DIR, HEIGHTMAP_DIR, BASESET_DIR, NEWGRF_DIR, AI_DIR, AI_LIBRARY_DIR, GAME_DIR
+		SAVE_DIR, AUTOSAVE_DIR, SCENARIO_DIR, HEIGHTMAP_DIR, BASESET_DIR, NEWGRF_DIR, AI_DIR, AI_LIBRARY_DIR, GAME_DIR, GAME_LIBRARY_DIR
 	};
 
 	for (uint i = 0; i < lengthof(default_subdirs); i++) {
@@ -1214,7 +1216,7 @@
 	FioCreateDirectory(_searchpaths[SP_AUTODOWNLOAD_DIR]);
 
 	/* Create the directory for each of the types of content */
-	const Subdirectory dirs[] = { SCENARIO_DIR, HEIGHTMAP_DIR, BASESET_DIR, NEWGRF_DIR, AI_DIR, AI_LIBRARY_DIR, GAME_DIR };
+	const Subdirectory dirs[] = { SCENARIO_DIR, HEIGHTMAP_DIR, BASESET_DIR, NEWGRF_DIR, AI_DIR, AI_LIBRARY_DIR, GAME_DIR, GAME_LIBRARY_DIR };
 	for (uint i = 0; i < lengthof(dirs); i++) {
 		char *tmp = str_fmt("%s%s", _searchpaths[SP_AUTODOWNLOAD_DIR], _subdirs[dirs[i]]);
 		FioCreateDirectory(tmp);
--- a/src/fileio_type.h
+++ b/src/fileio_type.h
@@ -31,6 +31,7 @@
 	AI_DIR,        ///< Subdirectory for all AI files
 	AI_LIBRARY_DIR,///< Subdirectory for all AI libraries
 	GAME_DIR,      ///< Subdirectory for all game scripts
+	GAME_LIBRARY_DIR, ///< Subdirectory for all GS libraries
 	NUM_SUBDIRS,   ///< Number of subdirectories
 	NO_DIRECTORY,  ///< A path without any base directory
 };
--- a/src/game/game.hpp
+++ b/src/game/game.hpp
@@ -68,23 +68,34 @@
 
 	/** Wrapper function for GameScanner::GetConsoleList */
 	static char *GetConsoleList(char *p, const char *last, bool newest_only = false);
+	/** Wrapper function for GameScanner::GetConsoleLibraryList */
+	static char *GetConsoleLibraryList(char *p, const char *last);
 	/** Wrapper function for GameScanner::GetInfoList */
 	static const ScriptInfoList *GetInfoList();
 	/** Wrapper function for GameScanner::GetUniqueInfoList */
 	static const ScriptInfoList *GetUniqueInfoList();
 	/** Wrapper function for GameScannerInfo::FindInfo */
 	static class GameInfo *FindInfo(const char *name, int version, bool force_exact_match);
+	/** Wrapper function for GameScanner::FindLibrary */
+	static class GameLibrary *FindLibrary(const char *library, int version);
 
 	/**
 	 * Get the current active instance.
 	 */
 	static class GameInstance *GetInstance() { return Game::instance; }
 
+#if defined(ENABLE_NETWORK)
+	/** Wrapper function for GameScanner::HasGame */
+	static bool HasGame(const struct ContentInfo *ci, bool md5sum);
+	static bool HasGameLibrary(const ContentInfo *ci, bool md5sum);
+#endif
+
 private:
-	static uint frame_counter;             ///< Tick counter for the Game code.
-	static class GameInstance *instance;   ///< Instance to the current active Game.
-	static class GameScannerInfo *scanner; ///< Scanner for Game scripts.
-	static class GameInfo *info;           ///< Current selected GameInfo.
+	static uint frame_counter;                        ///< Tick counter for the Game code.
+	static class GameInstance *instance;              ///< Instance to the current active Game.
+	static class GameScannerInfo *scanner_info;       ///< Scanner for Game scripts.
+	static class GameScannerLibrary *scanner_library; ///< Scanner for GS Libraries.
+	static class GameInfo *info;                      ///< Current selected GameInfo.
 };
 
 #endif /* GAME_HPP */
--- a/src/game/game_core.cpp
+++ b/src/game/game_core.cpp
@@ -26,7 +26,8 @@
 /* static */ uint Game::frame_counter = 0;
 /* static */ GameInfo *Game::info = NULL;
 /* static */ GameInstance *Game::instance = NULL;
-/* static */ GameScannerInfo *Game::scanner = NULL;
+/* static */ GameScannerInfo *Game::scanner_info = NULL;
+/* static */ GameScannerLibrary *Game::scanner_library = NULL;
 
 /* static */ void Game::GameLoop()
 {
@@ -52,10 +53,12 @@
 
 	Game::frame_counter = 0;
 
-	if (Game::scanner == NULL) {
+	if (Game::scanner_info == NULL) {
 		TarScanner::DoScan(TarScanner::GAME);
-		Game::scanner = new GameScannerInfo();
-		Game::scanner->Initialize();
+		Game::scanner_info = new GameScannerInfo();
+		Game::scanner_info->Initialize();
+		Game::scanner_library = new GameScannerLibrary();
+		Game::scanner_library->Initialize();
 	}
 }
 
@@ -90,8 +93,10 @@
 	if (keepConfig) {
 		Rescan();
 	} else {
-		delete Game::scanner;
-		Game::scanner = NULL;
+		delete Game::scanner_info;
+		delete Game::scanner_library;
+		Game::scanner_info = NULL;
+		Game::scanner_library = NULL;
 
 		if (_settings_game.game_config != NULL) {
 			delete _settings_game.game_config;
@@ -132,7 +137,8 @@
 {
 	TarScanner::DoScan(TarScanner::GAME);
 
-	Game::scanner->RescanDir();
+	Game::scanner_info->RescanDir();
+	Game::scanner_library->RescanDir();
 	ResetConfig();
 
 	InvalidateWindowData(WC_AI_LIST, 0, 1);
@@ -166,20 +172,50 @@
 
 /* static */ char *Game::GetConsoleList(char *p, const char *last, bool newest_only)
 {
-	return Game::scanner->GetConsoleList(p, last, newest_only);
+	return Game::scanner_info->GetConsoleList(p, last, newest_only);
+}
+
+/* static */ char *Game::GetConsoleLibraryList(char *p, const char *last)
+{
+	 return Game::scanner_library->GetConsoleList(p, last, true);
 }
 
 /* static */ const ScriptInfoList *Game::GetInfoList()
 {
-	return Game::scanner->GetInfoList();
+	return Game::scanner_info->GetInfoList();
 }
 
 /* static */ const ScriptInfoList *Game::GetUniqueInfoList()
 {
-	return Game::scanner->GetUniqueInfoList();
+	return Game::scanner_info->GetUniqueInfoList();
 }
 
 /* static */ GameInfo *Game::FindInfo(const char *name, int version, bool force_exact_match)
 {
-	return Game::scanner->FindInfo(name, version, force_exact_match);
+	return Game::scanner_info->FindInfo(name, version, force_exact_match);
+}
+
+/* static */ GameLibrary *Game::FindLibrary(const char *library, int version)
+{
+	return Game::scanner_library->FindLibrary(library, version);
 }
+
+#if defined(ENABLE_NETWORK)
+
+/**
+ * Check whether we have an Game (library) with the exact characteristics as ci.
+ * @param ci the characteristics to search on (shortname and md5sum)
+ * @param md5sum whether to check the MD5 checksum
+ * @return true iff we have an Game (library) matching.
+ */
+/* static */ bool Game::HasGame(const ContentInfo *ci, bool md5sum)
+{
+	return Game::scanner_info->HasScript(ci, md5sum);
+}
+
+/* static */ bool Game::HasGameLibrary(const ContentInfo *ci, bool md5sum)
+{
+	return Game::scanner_library->HasScript(ci, md5sum);
+}
+
+#endif /* defined(ENABLE_NETWORK) */
--- a/src/game/game_info.cpp
+++ b/src/game/game_info.cpp
@@ -99,3 +99,40 @@
 	if (version == -1) return true;
 	return version >= this->min_loadable_version && version <= this->GetVersion();
 }
+
+
+GameLibrary::~GameLibrary()
+{
+	free(this->category);
+}
+
+/* static */ void GameLibrary::RegisterAPI(Squirrel *engine)
+{
+	/* Create the GameLibrary class, and add the RegisterLibrary function */
+	engine->AddClassBegin("GSLibrary");
+	engine->AddClassEnd();
+	engine->AddMethod("RegisterLibrary", &GameLibrary::Constructor, 2, "tx");
+}
+
+/* static */ SQInteger GameLibrary::Constructor(HSQUIRRELVM vm)
+{
+	/* Create a new library */
+	GameLibrary *library = new GameLibrary();
+
+	SQInteger res = ScriptInfo::Constructor(vm, library);
+	if (res != 0) {
+		delete library;
+		return res;
+	}
+
+	/* Cache the category */
+	if (!library->CheckMethod("GetCategory") || !library->engine->CallStringMethodStrdup(*library->SQ_instance, "GetCategory", &library->category, MAX_GET_OPS)) {
+		delete library;
+		return SQ_ERROR;
+	}
+
+	/* Register the Library to the base system */
+	library->GetScanner()->RegisterScript(library);
+
+	return 0;
+}
--- a/src/game/game_info.hpp
+++ b/src/game/game_info.hpp
@@ -46,4 +46,29 @@
 	const char *api_version;  ///< API version used by this Game.
 };
 
+/** All static information from an Game library like name, version, etc. */
+class GameLibrary : public ScriptInfo {
+public:
+	GameLibrary() : ScriptInfo(), category(NULL) {};
+	~GameLibrary();
+
+	/**
+	 * Register the functions of this class.
+	 */
+	static void RegisterAPI(Squirrel *engine);
+
+	/**
+	 * Create an GSLibrary, using this GSInfo as start-template.
+	 */
+	static SQInteger Constructor(HSQUIRRELVM vm);
+
+	/**
+	 * Get the category this library is in.
+	 */
+	const char *GetCategory() const { return this->category; }
+
+private:
+	const char *category; ///< The category this library is in.
+};
+
 #endif /* GAME_INFO_HPP */
--- a/src/game/game_instance.cpp
+++ b/src/game/game_instance.cpp
@@ -68,8 +68,7 @@
 
 ScriptInfo *GameInstance::FindLibrary(const char *library, int version)
 {
-	/* 'import' is not supported with GameScripts */
-	return NULL;
+	return (ScriptInfo *)Game::FindLibrary(library, version);
 }
 
 /**
--- a/src/game/game_scanner.cpp
+++ b/src/game/game_scanner.cpp
@@ -21,11 +21,6 @@
 #include "../script/api/script_controller.hpp"
 
 
-GameScannerInfo::GameScannerInfo() :
-	ScriptScanner()
-{
-}
-
 void GameScannerInfo::Initialize()
 {
 	ScriptScanner::Initialize("GSScanner");
@@ -87,3 +82,34 @@
 
 	return info;
 }
+
+
+void GameScannerLibrary::Initialize()
+{
+	ScriptScanner::Initialize("GSScanner");
+}
+
+void GameScannerLibrary::GetScriptName(ScriptInfo *info, char *name, int len)
+{
+	GameLibrary *library = static_cast<GameLibrary *>(info);
+	snprintf(name, len, "%s.%s", library->GetCategory(), library->GetInstanceName());
+}
+
+void GameScannerLibrary::RegisterAPI(class Squirrel *engine)
+{
+	GameLibrary::RegisterAPI(engine);
+}
+
+GameLibrary *GameScannerLibrary::FindLibrary(const char *library, int version)
+{
+	/* Internally we store libraries as 'library.version' */
+	char library_name[1024];
+	snprintf(library_name, sizeof(library_name), "%s.%d", library, version);
+	strtolower(library_name);
+
+	/* Check if the library + version exists */
+	ScriptInfoList::iterator iter = this->info_list.find(library_name);
+	if (iter == this->info_list.end()) return NULL;
+
+	return static_cast<GameLibrary *>((*iter).second);
+}
--- a/src/game/game_scanner.hpp
+++ b/src/game/game_scanner.hpp
@@ -16,8 +16,6 @@
 
 class GameScannerInfo : public ScriptScanner {
 public:
-	GameScannerInfo();
-
 	/* virtual */ void Initialize();
 
 	/**
@@ -37,4 +35,25 @@
 	/* virtual */ void RegisterAPI(class Squirrel *engine);
 };
 
+
+class GameScannerLibrary : public ScriptScanner {
+public:
+	/* virtual */ void Initialize();
+
+	/**
+	 * Find a library in the pool.
+	 * @param library The library name to find.
+	 * @param version The version the library should have.
+	 * @return The library if found, NULL otherwise.
+	 */
+	class GameLibrary *FindLibrary(const char *library, int version);
+
+protected:
+	/* virtual */ void GetScriptName(ScriptInfo *info, char *name, int len);
+	/* virtual */ const char *GetFileName() const { return PATHSEP "library.nut"; }
+	/* virtual */ Subdirectory GetDirectory() const { return GAME_LIBRARY_DIR; }
+	/* virtual */ const char *GetScannerName() const { return "GS Libraries"; }
+	/* virtual */ void RegisterAPI(class Squirrel *engine);
+};
+
 #endif /* GAME_SCANNER_HPP */
--- a/src/network/core/tcp_content.h
+++ b/src/network/core/tcp_content.h
@@ -33,6 +33,7 @@
 	CONTENT_TYPE_BASE_SOUNDS   = 7, ///< The content consists of base sounds
 	CONTENT_TYPE_BASE_MUSIC    = 8, ///< The content consists of base music
 	CONTENT_TYPE_GAME          = 9, ///< The content consists of a game script
+	CONTENT_TYPE_GAME_LIBRARY  = 10, ///< The content consists of a GS library
 	CONTENT_TYPE_END,               ///< Helper to mark the end of the types
 };
 
--- a/src/network/network_content.cpp
+++ b/src/network/network_content.cpp
@@ -14,6 +14,7 @@
 #include "../stdafx.h"
 #include "../rev.h"
 #include "../ai/ai.hpp"
+#include "../game/game.hpp"
 #include "../window_func.h"
 #include "../error.h"
 #include "../base_media_base.h"
@@ -104,6 +105,14 @@
 			proc = AI::HasAILibrary; break;
 			break;
 
+		case CONTENT_TYPE_GAME:
+			proc = Game::HasGame; break;
+			break;
+
+		case CONTENT_TYPE_GAME_LIBRARY:
+			proc = Game::HasGameLibrary; break;
+			break;
+
 		case CONTENT_TYPE_SCENARIO:
 		case CONTENT_TYPE_HEIGHTMAP:
 			proc = HasScenario;
@@ -183,6 +192,7 @@
 		this->RequestContentList(CONTENT_TYPE_AI);
 		this->RequestContentList(CONTENT_TYPE_AI_LIBRARY);
 		this->RequestContentList(CONTENT_TYPE_GAME);
+		this->RequestContentList(CONTENT_TYPE_GAME_LIBRARY);
 		this->RequestContentList(CONTENT_TYPE_NEWGRF);
 		return;
 	}
@@ -386,6 +396,7 @@
 		case CONTENT_TYPE_SCENARIO:      dir = SCENARIO_DIR;   break;
 		case CONTENT_TYPE_HEIGHTMAP:     dir = HEIGHTMAP_DIR;  break;
 		case CONTENT_TYPE_GAME:          dir = GAME_DIR;       break;
+		case CONTENT_TYPE_GAME_LIBRARY:  dir = GAME_LIBRARY_DIR; break;
 	}
 
 	static char buf[MAX_PATH];
@@ -552,6 +563,10 @@
 					sd = GAME_DIR;
 					break;
 
+				case CONTENT_TYPE_GAME_LIBRARY:
+					sd = GAME_LIBRARY_DIR;
+					break;
+
 				case CONTENT_TYPE_BASE_GRAPHICS:
 				case CONTENT_TYPE_BASE_SOUNDS:
 				case CONTENT_TYPE_BASE_MUSIC:
--- a/src/script/api/game/game_controller.hpp.sq
+++ b/src/script/api/game/game_controller.hpp.sq
@@ -25,4 +25,7 @@
 	SQGSController.DefSQStaticMethod(engine, &ScriptController::Print,             "Print",             3, ".bs");
 
 	SQGSController.PostRegister(engine);
+
+	/* Register the import statement to the global scope */
+	SQGSController.DefSQStaticMethod(engine, &ScriptController::Import,            "import",            4, ".ssi");
 }
--- a/src/script/squirrel.cpp
+++ b/src/script/squirrel.cpp
@@ -451,6 +451,7 @@
 		if (file == NULL) file = FioFOpenFile(filename, "rb", AI_LIBRARY_DIR, &size);
 	} else if (strncmp(this->GetAPIName(), "GS", 2) == 0) {
 		file = FioFOpenFile(filename, "rb", GAME_DIR, &size);
+		if (file == NULL) file = FioFOpenFile(filename, "rb", GAME_LIBRARY_DIR, &size);
 	} else {
 		NOT_REACHED();
 	}