From 202540722251d33ef467e03d3df6e6680c9de3fa Mon Sep 17 00:00:00 2001 From: Guangcong Luo Date: Sun, 17 Jan 2010 20:12:03 +0000 Subject: [PATCH] Commit mod list patch #1415: 1. Adds a specific autoload folder, `mods/autoload/`. This is essential for a good mod community. 2. Searches the `mods/` folder for global mods, as well as `mods/global/`. This is the first step in merging the three mod folders together, but I'm not planning on merging them completely in 2.3. 3. Constructs a list of loaded mods, and displays the list in the VersionString (including the list of games in the lobby). 4. Grays out games with incompatible mods in the NetPlay game list, and gives a warning in the tooltip: "Your loaded mods are incompatible with this game. (Check mods/autoload/?)" 5. Gives a warning when a game with an incompatible mod is clicked: "You have an incompatible mod." 6. Displays a list of mods above the Warzone logo. 7. Lists mods in hosting screen, and warns hosts that all players need the same mods loaded. Closes ticket:1415. git-svn-id: https://warzone2100.svn.sourceforge.net/svnroot/warzone2100/trunk@9291 4a71c877-e1ca-e34f-864e-861f7616d084 --- lib/netplay/netplay.c | 19 ++++++--- src/frontend.c | 19 ++++++++- src/init.c | 23 +++++++---- src/main.c | 96 ++++++++++++++++++++++++++++++++++++++++++- src/modding.h | 6 ++- src/multiint.c | 26 +++++++++++- 6 files changed, 171 insertions(+), 18 deletions(-) diff --git a/lib/netplay/netplay.c b/lib/netplay/netplay.c index 62f5e4eae..e1eebdb96 100644 --- a/lib/netplay/netplay.c +++ b/lib/netplay/netplay.c @@ -27,6 +27,7 @@ #include "lib/framework/string_ext.h" #include "lib/gamelib/gtime.h" #include "src/component.h" // FIXME: we need to handle this better +#include "src/modding.h" // FIXME: we need to handle this better #include // for stats #include #include @@ -267,8 +268,8 @@ static bool playerPasswordFlag[MAX_PLAYERS] = {false}; // we kick on false ************************************************************************************ **/ char VersionString[VersionStringSize] = "trunk, netcode 3.32"; -static int NETCODE_VERSION_MAJOR = 3; -static int NETCODE_VERSION_MINOR = 32; +static int NETCODE_VERSION_MAJOR = 2; +static int NETCODE_VERSION_MINOR = 33; static int NUMBER_OF_MODS = 0; // unused for now static int NETCODE_HASH = 0; // unused for now @@ -3438,8 +3439,13 @@ BOOL NEThostGame(const char* SessionName, const char* PlayerName, gamestruct.desc.dwUserFlags[3] = four; memset(gamestruct.secondaryHosts, 0, sizeof(gamestruct.secondaryHosts)); sstrcpy(gamestruct.extra, "Extra"); // extra string (future use) - sstrcpy(gamestruct.versionstring, VersionString); // version (string) - sstrcpy(gamestruct.modlist, "Mod list"); // List of mods + sstrcpy(gamestruct.versionstring, VersionString); // version (string) + if (*getModList()) + { + sstrcat(gamestruct.versionstring, _(", mods: ")); // version (string) + sstrcat(gamestruct.versionstring, getModList()); // version (string) + } + sstrcpy(gamestruct.modlist, getModList()); // List of mods gamestruct.GAMESTRUCT_VERSION = 3; // version of this structure gamestruct.game_version_major = NETCODE_VERSION_MAJOR; // Netcode Major version gamestruct.game_version_minor = NETCODE_VERSION_MINOR; // NetCode Minor version @@ -3719,9 +3725,10 @@ connect_succesfull: addressToText(cur->ai_addr, NetPlay.games[gameNumber].desc.host, sizeof(NetPlay.games[gameNumber].desc.host)); } freeaddrinfo(hosts); - if (NetPlay.games[gameNumber].desc.dwCurrentPlayers >= NetPlay.games[gameNumber].desc.dwMaxPlayers) + if (NetPlay.games[gameNumber].desc.dwCurrentPlayers >= NetPlay.games[gameNumber].desc.dwMaxPlayers || + strcmp(NetPlay.games[gameNumber].modlist, getModList()) != 0) { - // Shouldn't join; game is full + // Shouldn't join; game is full or we have an incompatible mod delSocket(socket_set, tcp_socket); socketClose(tcp_socket); free(socket_set); diff --git a/src/frontend.c b/src/frontend.c index ce0ee92eb..311f18fef 100644 --- a/src/frontend.c +++ b/src/frontend.c @@ -68,6 +68,7 @@ #include "wrappers.h" #include "version.h" #include "configuration.h" +#include "modding.h" // //////////////////////////////////////////////////////////////////////////// // Global variables @@ -535,6 +536,8 @@ BOOL runMultiPlayerMenu(void) switch(id) { case FRONTEND_HOST: + // don't pretend we are running a network game. Really do it! + NetPlay.bComms = true; // use network = true NETdiscoverUPnPDevices(); ingame.bHostSetup = true; bMultiPlayer = true; @@ -1675,8 +1678,9 @@ void addSideText(UDWORD id, UDWORD PosX, UDWORD PosY, const char *txt) static void displayTitleBitmap(WZ_DECL_UNUSED WIDGET *psWidget, WZ_DECL_UNUSED UDWORD xOffset, WZ_DECL_UNUSED UDWORD yOffset, WZ_DECL_UNUSED PIELIGHT *pColours) { iV_SetFont(font_regular); + iV_SetTextColour(WZCOL_GREY); + iV_DrawTextRotated(version_getFormattedVersionString(), pie_GetVideoBufferWidth() - 9, pie_GetVideoBufferHeight() - 14, 270.f); iV_SetTextColour(WZCOL_TEXT_BRIGHT); - iV_DrawTextRotated(version_getFormattedVersionString(), pie_GetVideoBufferWidth() - 10, pie_GetVideoBufferHeight() - 15, 270.f); } @@ -1685,6 +1689,19 @@ static void displayTitleBitmap(WZ_DECL_UNUSED WIDGET *psWidget, WZ_DECL_UNUSED U void displayLogo(WIDGET *psWidget, UDWORD xOffset, UDWORD yOffset, WZ_DECL_UNUSED PIELIGHT *pColours) { iV_DrawImage(FrontImages,IMAGE_FE_LOGO,xOffset+psWidget->x,yOffset+psWidget->y); + + if (*getModList()) + { + // show the mod list + char modListText[WIDG_MAXSTR] = ""; + sstrcat(modListText, _("Active mods: ")); + sstrcat(modListText, getModList()); + iV_SetFont(font_regular); + iV_SetTextColour(WZCOL_GREY); + iV_DrawText(modListText, xOffset+psWidget->x-9, yOffset+psWidget->y-19); + iV_SetTextColour(WZCOL_TEXT_BRIGHT); + iV_DrawText(modListText, xOffset+psWidget->x-10, yOffset+psWidget->y-20); + } } diff --git a/src/init.c b/src/init.c index 659827ce8..73e8d4a34 100644 --- a/src/init.c +++ b/src/init.c @@ -250,6 +250,7 @@ BOOL rebuildSearchPath( searchPathMode mode, BOOL force ) { case mod_clean: debug(LOG_WZ, "Cleaning up"); + clearLoadedMods(); while( curSearchPath ) { @@ -291,6 +292,7 @@ BOOL rebuildSearchPath( searchPathMode mode, BOOL force ) break; case mod_campaign: debug(LOG_WZ, "*** Switching to campaign mods ***"); + clearLoadedMods(); while( curSearchPath ) { @@ -300,9 +302,11 @@ BOOL rebuildSearchPath( searchPathMode mode, BOOL force ) // Add global and campaign mods PHYSFS_addToSearchPath( curSearchPath->path, PHYSFS_APPEND ); - addSubdirs( curSearchPath->path, "mods/music", PHYSFS_APPEND, NULL ); - addSubdirs( curSearchPath->path, "mods/global", PHYSFS_APPEND, global_mods ); - addSubdirs( curSearchPath->path, "mods/campaign", PHYSFS_APPEND, campaign_mods ); + addSubdirs( curSearchPath->path, "mods/music", PHYSFS_APPEND, NULL, false ); + addSubdirs( curSearchPath->path, "mods/global", PHYSFS_APPEND, global_mods, true ); + addSubdirs( curSearchPath->path, "mods", PHYSFS_APPEND, global_mods, true ); + addSubdirs( curSearchPath->path, "mods/autoload", PHYSFS_APPEND, NULL, true ); + addSubdirs( curSearchPath->path, "mods/campaign", PHYSFS_APPEND, campaign_mods, true ); if (!PHYSFS_removeFromSearchPath( curSearchPath->path )) { info("* Failed to remove path %s again", curSearchPath->path); @@ -323,12 +327,13 @@ BOOL rebuildSearchPath( searchPathMode mode, BOOL force ) sstrcpy(tmpstr, curSearchPath->path); sstrcat(tmpstr, "sequences.wz"); PHYSFS_addToSearchPath( tmpstr, PHYSFS_APPEND ); - + curSearchPath = curSearchPath->higherPriority; } break; case mod_multiplay: debug(LOG_WZ, "*** Switching to multiplay mods ***"); + clearLoadedMods(); while( curSearchPath ) { @@ -337,10 +342,12 @@ BOOL rebuildSearchPath( searchPathMode mode, BOOL force ) #endif // DEBUG // Add maps and global and multiplay mods PHYSFS_addToSearchPath( curSearchPath->path, PHYSFS_APPEND ); - addSubdirs( curSearchPath->path, "maps", PHYSFS_APPEND, NULL ); - addSubdirs( curSearchPath->path, "mods/music", PHYSFS_APPEND, NULL ); - addSubdirs( curSearchPath->path, "mods/global", PHYSFS_APPEND, global_mods ); - addSubdirs( curSearchPath->path, "mods/multiplay", PHYSFS_APPEND, multiplay_mods ); + addSubdirs( curSearchPath->path, "maps", PHYSFS_APPEND, NULL, false ); + addSubdirs( curSearchPath->path, "mods/music", PHYSFS_APPEND, NULL, false ); + addSubdirs( curSearchPath->path, "mods/global", PHYSFS_APPEND, global_mods, true ); + addSubdirs( curSearchPath->path, "mods", PHYSFS_APPEND, global_mods, true ); + addSubdirs( curSearchPath->path, "mods/autoload", PHYSFS_APPEND, NULL, true ); + addSubdirs( curSearchPath->path, "mods/multiplay", PHYSFS_APPEND, multiplay_mods, true ); PHYSFS_removeFromSearchPath( curSearchPath->path ); // Add multiplay patches diff --git a/src/main.c b/src/main.c index f91465a45..b3572c7ce 100644 --- a/src/main.c +++ b/src/main.c @@ -108,6 +108,10 @@ char * global_mods[MAX_MODS] = { NULL }; char * campaign_mods[MAX_MODS] = { NULL }; char * multiplay_mods[MAX_MODS] = { NULL }; +char * loaded_mods[MAX_MODS] = { NULL }; +char * mod_list = NULL; +int num_loaded_mods = 0; + // Warzone 2100 . Pumpkin Studios @@ -155,7 +159,7 @@ static BOOL inList( char * list[], const char * item ) * \param appendToPath Whether to append or prepend * \param checkList List of directories to check. NULL means any. */ -void addSubdirs( const char * basedir, const char * subdir, const BOOL appendToPath, char * checkList[] ) +void addSubdirs( const char * basedir, const char * subdir, const bool appendToPath, char * checkList[], bool addToModList ) { char tmpstr[PATH_MAX]; char ** subdirlist = PHYSFS_enumerateFiles( subdir ); @@ -171,6 +175,10 @@ void addSubdirs( const char * basedir, const char * subdir, const BOOL appendToP #ifdef DEBUG debug( LOG_NEVER, "addSubdirs: Adding [%s] to search path", tmpstr ); #endif // DEBUG + if (addToModList) + { + addLoadedMod(*i); + } PHYSFS_addToSearchPath( tmpstr, appendToPath ); } i++; @@ -213,6 +221,92 @@ void printSearchPath( void ) PHYSFS_freeList( searchPath ); } +void addLoadedMod(const char * modname) +{ + char * mod = strdup(modname); + int i, modlen; + if (num_loaded_mods >= MAX_MODS) + { + // mod list full + return; + } + modlen = strlen(mod); + if (modlen >= 3 && strcmp(&mod[modlen-3], ".wz")==0) + { + // remove ".wz" from end + mod[modlen-3] = 0; + modlen -= 3; + } + if (modlen >= 4 && strcmp(&mod[modlen-4], ".cam")==0) + { + // remove ".cam.wz" from end + mod[modlen-4] = 0; + modlen -= 4; + } + else if (modlen >= 4 && strcmp(&mod[modlen-4], ".mod")==0) + { + // remove ".mod.wz" from end + mod[modlen-4] = 0; + modlen -= 4; + } + else if (modlen >= 5 && strcmp(&mod[modlen-5], ".gmod")==0) + { + // remove ".gmod.wz" from end + mod[modlen-5] = 0; + modlen -= 5; + } + // Yes, this is an online insertion sort. + // I swear, for the numbers of mods this is going to be dealing with + // (i.e. 0 to 2), it really is faster than, say, Quicksort. + for (i=0; i0; i++); + if (i < num_loaded_mods) + { + if (strcmp(loaded_mods[i], mod) == 0) + { + // mod already in list + free(mod); + return; + } + memmove(&loaded_mods[i+1], &loaded_mods[i], (num_loaded_mods-i)*sizeof(char*)); + } + loaded_mods[i] = mod; + num_loaded_mods++; +} +void clearLoadedMods(void) +{ + int i; + for (i=0; i