# HG changeset patch # User truebrain # Date 2011-12-19 20:56:59 # Node ID 42d72cb83fe704b6c2e0ab5fa71106c4c6397638 # Parent 19e74c935c2d6477a0075aa4794e3a4008d315bf (svn r23612) -Add: allow importing libraries in the same way as AI does, only with GS prefix (and in game/library) diff --git a/src/console_cmds.cpp b/src/console_cmds.cpp --- a/src/console_cmds.cpp +++ b/src/console_cmds.cpp @@ -1106,6 +1106,16 @@ DEF_CONSOLE_CMD(ConListAI) 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 @@ DEF_CONSOLE_CMD(ConContent) 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 @@ void IConsoleStdLibRegister() IConsoleCmdRegister("stop_ai", ConStopAI); IConsoleCmdRegister("list_game", ConListGame); + IConsoleCmdRegister("list_game_libs", ConListGameLibs); /* networking functions */ #ifdef ENABLE_NETWORK diff --git a/src/fileio.cpp b/src/fileio.cpp --- a/src/fileio.cpp +++ b/src/fileio.cpp @@ -282,6 +282,7 @@ static const char * const _subdirs[] = { "ai" PATHSEP, "ai" PATHSEP "library" PATHSEP, "game" PATHSEP, + "game" PATHSEP "library" PATHSEP, }; assert_compile(lengthof(_subdirs) == NUM_SUBDIRS); @@ -678,6 +679,7 @@ uint TarScanner::DoScan(Subdirectory sd) } 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 @@ void DeterminePaths(const char *exe) #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 @@ void DeterminePaths(const char *exe) 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); diff --git a/src/fileio_type.h b/src/fileio_type.h --- a/src/fileio_type.h +++ b/src/fileio_type.h @@ -31,6 +31,7 @@ enum Subdirectory { 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 }; diff --git a/src/game/game.hpp b/src/game/game.hpp --- a/src/game/game.hpp +++ b/src/game/game.hpp @@ -68,23 +68,34 @@ public: /** 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 */ diff --git a/src/game/game_core.cpp b/src/game/game_core.cpp --- 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) */ diff --git a/src/game/game_info.cpp b/src/game/game_info.cpp --- a/src/game/game_info.cpp +++ b/src/game/game_info.cpp @@ -99,3 +99,40 @@ bool GameInfo::CanLoadFromVersion(int ve 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; +} diff --git a/src/game/game_info.hpp b/src/game/game_info.hpp --- a/src/game/game_info.hpp +++ b/src/game/game_info.hpp @@ -46,4 +46,29 @@ private: 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 */ diff --git a/src/game/game_instance.cpp b/src/game/game_instance.cpp --- a/src/game/game_instance.cpp +++ b/src/game/game_instance.cpp @@ -68,8 +68,7 @@ int GameInstance::GetSetting(const char ScriptInfo *GameInstance::FindLibrary(const char *library, int version) { - /* 'import' is not supported with GameScripts */ - return NULL; + return (ScriptInfo *)Game::FindLibrary(library, version); } /** diff --git a/src/game/game_scanner.cpp b/src/game/game_scanner.cpp --- 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 @@ GameInfo *GameScannerInfo::FindInfo(cons return info; } + + +void GameScannerLibrary::Initialize() +{ + ScriptScanner::Initialize("GSScanner"); +} + +void GameScannerLibrary::GetScriptName(ScriptInfo *info, char *name, int len) +{ + GameLibrary *library = static_cast(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((*iter).second); +} diff --git a/src/game/game_scanner.hpp b/src/game/game_scanner.hpp --- 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 @@ protected: /* 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 */ diff --git a/src/network/core/tcp_content.h b/src/network/core/tcp_content.h --- a/src/network/core/tcp_content.h +++ b/src/network/core/tcp_content.h @@ -33,6 +33,7 @@ enum ContentType { 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 }; diff --git a/src/network/network_content.cpp b/src/network/network_content.cpp --- 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 @@ bool ClientNetworkContentSocketHandler:: 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 @@ void ClientNetworkContentSocketHandler:: 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 @@ static char *GetFullFilename(const Conte 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 @@ void ClientNetworkContentSocketHandler:: 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: diff --git a/src/script/api/game/game_controller.hpp.sq b/src/script/api/game/game_controller.hpp.sq --- a/src/script/api/game/game_controller.hpp.sq +++ b/src/script/api/game/game_controller.hpp.sq @@ -25,4 +25,7 @@ void SQGSController_Register(Squirrel *e 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"); } diff --git a/src/script/squirrel.cpp b/src/script/squirrel.cpp --- a/src/script/squirrel.cpp +++ b/src/script/squirrel.cpp @@ -451,6 +451,7 @@ SQRESULT Squirrel::LoadFile(HSQUIRRELVM 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(); }