bool stageOneShutDown(void) { debug(LOG_WZ, "== stageOneShutDown =="); if ( audio_Disabled() == false ) { sound_CheckAllUnloaded(); } proj_Shutdown(); releaseMission(); if (!aiShutdown()) { return false; } if (!objShutdown()) { return false; } grpShutDown(); ResearchRelease(); //free up the gateway stuff? gwShutDown(); shutdownTerrain(); if (!mapShutdown()) { return false; } scrShutDown(); gridShutDown(); if ( !anim_Shutdown() ) { return false; } if ( !animObj_Shutdown() ) { return false; } debug(LOG_TEXTURE, "=== stageOneShutDown ==="); pie_TexShutDown(); // Use mod_multiplay as the default (campaign might have set it to mod_singleplayer) rebuildSearchPath( mod_multiplay, true ); pie_TexInit(); // restart it initMiscVars(); return true; }
bool stageOneShutDown() { debug(LOG_WZ, "== stageOneShutDown =="); atmosSetWeatherType(WT_NONE); // reset weather and free its data wzPerfShutdown(); pie_FreeShaders(); if (audio_Disabled() == false) { sound_CheckAllUnloaded(); } proj_Shutdown(); releaseMission(); if (!aiShutdown()) { return false; } if (!objShutdown()) { return false; } grpShutDown(); ResearchRelease(); //free up the gateway stuff? gwShutDown(); shutdownTerrain(); if (!mapShutdown()) { return false; } scrShutDown(); gridShutDown(); debug(LOG_TEXTURE, "== stageOneShutDown =="); modelShutdown(); pie_TexShutDown(); // Use mod_multiplay as the default (campaign might have set it to mod_singleplayer) rebuildSearchPath(mod_multiplay, true); pie_TexInit(); // restart it initMiscVars(); wzSceneEnd("Main game loop"); wzSceneBegin("Main menu loop"); return true; }
// Another player is broadcasting a map, recv a chunk. Returns false if not yet done. bool recvMapFileData(NETQUEUE queue) { mapDownloadProgress = NETrecvFile(queue); if (mapDownloadProgress == 100) { addConsoleMessage("MAP DOWNLOADED!",DEFAULT_JUSTIFY, SYSTEM_MESSAGE); sendTextMessage("MAP DOWNLOADED",true); //send debug(LOG_NET, "=== File has been received. ==="); // clear out the old level list. levShutDown(); levInitialise(); rebuildSearchPath(mod_multiplay, true); // MUST rebuild search path for the new maps we just got! if (!buildMapList()) { return false; } return true; } return false; }
/*! * \brief Rebuilds the PHYSFS searchPath with mode specific subdirs * * Priority: * maps > mods > base > base.wz */ bool rebuildSearchPath( searchPathMode mode, bool force ) { static searchPathMode current_mode = mod_clean; static std::string current_current_map; wzSearchPath * curSearchPath = searchPathRegistry; char tmpstr[PATH_MAX] = "\0"; if (mode != current_mode || (current_map != NULL? current_map : "") != current_current_map || force || (use_override_mods && strcmp(override_mod_list, getModList()))) { if (mode != mod_clean) { rebuildSearchPath( mod_clean, false ); } current_mode = mode; current_current_map = current_map != NULL? current_map : ""; // Start at the lowest priority while( curSearchPath->lowerPriority ) curSearchPath = curSearchPath->lowerPriority; switch ( mode ) { case mod_clean: debug(LOG_WZ, "Cleaning up"); clearLoadedMods(); while( curSearchPath ) { #ifdef DEBUG debug(LOG_WZ, "Removing [%s] from search path", curSearchPath->path); #endif // DEBUG // Remove maps and mods removeSubdirs( curSearchPath->path, "maps", NULL ); removeSubdirs( curSearchPath->path, "mods/music", NULL ); removeSubdirs( curSearchPath->path, "mods/global", NULL ); removeSubdirs( curSearchPath->path, "mods/campaign", NULL ); removeSubdirs( curSearchPath->path, "mods/multiplay", NULL ); removeSubdirs( curSearchPath->path, "mods/autoload", NULL ); // Remove multiplay patches sstrcpy(tmpstr, curSearchPath->path); sstrcat(tmpstr, "mp"); PHYSFS_removeFromSearchPath( tmpstr ); sstrcpy(tmpstr, curSearchPath->path); sstrcat(tmpstr, "mp.wz"); PHYSFS_removeFromSearchPath( tmpstr ); // Remove plain dir PHYSFS_removeFromSearchPath( curSearchPath->path ); // Remove base files sstrcpy(tmpstr, curSearchPath->path); sstrcat(tmpstr, "base"); PHYSFS_removeFromSearchPath( tmpstr ); sstrcpy(tmpstr, curSearchPath->path); sstrcat(tmpstr, "base.wz"); PHYSFS_removeFromSearchPath( tmpstr ); // remove video search path as well sstrcpy(tmpstr, curSearchPath->path); sstrcat(tmpstr, "sequences.wz"); PHYSFS_removeFromSearchPath( tmpstr ); curSearchPath = curSearchPath->higherPriority; } break; case mod_campaign: debug(LOG_WZ, "*** Switching to campaign mods ***"); clearLoadedMods(); while (curSearchPath) { // make sure videos override included files sstrcpy(tmpstr, curSearchPath->path); sstrcat(tmpstr, "sequences.wz"); PHYSFS_addToSearchPath(tmpstr, PHYSFS_APPEND); curSearchPath = curSearchPath->higherPriority; } curSearchPath = searchPathRegistry; while (curSearchPath->lowerPriority) curSearchPath = curSearchPath->lowerPriority; while( curSearchPath ) { #ifdef DEBUG debug(LOG_WZ, "Adding [%s] to search path", curSearchPath->path); #endif // DEBUG // Add global and campaign mods PHYSFS_addToSearchPath( curSearchPath->path, PHYSFS_APPEND ); addSubdirs( curSearchPath->path, "mods/music", PHYSFS_APPEND, NULL, false ); addSubdirs( curSearchPath->path, "mods/global", PHYSFS_APPEND, use_override_mods?override_mods:global_mods, true ); addSubdirs( curSearchPath->path, "mods", PHYSFS_APPEND, use_override_mods?override_mods:global_mods, true ); addSubdirs( curSearchPath->path, "mods/autoload", PHYSFS_APPEND, use_override_mods?override_mods:NULL, true ); addSubdirs( curSearchPath->path, "mods/campaign", PHYSFS_APPEND, use_override_mods?override_mods:campaign_mods, true ); if (!PHYSFS_removeFromSearchPath( curSearchPath->path )) { debug(LOG_WZ, "* Failed to remove path %s again", curSearchPath->path); } // Add plain dir PHYSFS_addToSearchPath( curSearchPath->path, PHYSFS_APPEND ); // Add base files sstrcpy(tmpstr, curSearchPath->path); sstrcat(tmpstr, "base"); PHYSFS_addToSearchPath( tmpstr, PHYSFS_APPEND ); sstrcpy(tmpstr, curSearchPath->path); sstrcat(tmpstr, "base.wz"); PHYSFS_addToSearchPath( tmpstr, PHYSFS_APPEND ); curSearchPath = curSearchPath->higherPriority; } break; case mod_multiplay: debug(LOG_WZ, "*** Switching to multiplay mods ***"); clearLoadedMods(); while (curSearchPath) { // make sure videos override included files sstrcpy(tmpstr, curSearchPath->path); sstrcat(tmpstr, "sequences.wz"); PHYSFS_addToSearchPath(tmpstr, PHYSFS_APPEND); curSearchPath = curSearchPath->higherPriority; } // Add the selected map first, for mapmod support if (current_map != NULL) { std::string realPathAndDir = std::string(PHYSFS_getRealDir(current_map)) + current_map; PHYSFS_addToSearchPath(realPathAndDir.c_str(), PHYSFS_APPEND); } curSearchPath = searchPathRegistry; while (curSearchPath->lowerPriority) curSearchPath = curSearchPath->lowerPriority; while( curSearchPath ) { #ifdef DEBUG debug(LOG_WZ, "Adding [%s] to search path", curSearchPath->path); #endif // DEBUG // Add global and multiplay mods PHYSFS_addToSearchPath( curSearchPath->path, PHYSFS_APPEND ); addSubdirs( curSearchPath->path, "mods/music", PHYSFS_APPEND, NULL, false ); addSubdirs( curSearchPath->path, "mods/global", PHYSFS_APPEND, use_override_mods?override_mods:global_mods, true ); addSubdirs( curSearchPath->path, "mods", PHYSFS_APPEND, use_override_mods?override_mods:global_mods, true ); addSubdirs( curSearchPath->path, "mods/autoload", PHYSFS_APPEND, use_override_mods?override_mods:NULL, true ); addSubdirs( curSearchPath->path, "mods/multiplay", PHYSFS_APPEND, use_override_mods?override_mods:multiplay_mods, true ); PHYSFS_removeFromSearchPath( curSearchPath->path ); // Add multiplay patches sstrcpy(tmpstr, curSearchPath->path); sstrcat(tmpstr, "mp"); PHYSFS_addToSearchPath( tmpstr, PHYSFS_APPEND ); sstrcpy(tmpstr, curSearchPath->path); sstrcat(tmpstr, "mp.wz"); PHYSFS_addToSearchPath( tmpstr, PHYSFS_APPEND ); // Add plain dir PHYSFS_addToSearchPath( curSearchPath->path, PHYSFS_APPEND ); // Add base files sstrcpy(tmpstr, curSearchPath->path); sstrcat(tmpstr, "base"); PHYSFS_addToSearchPath( tmpstr, PHYSFS_APPEND ); sstrcpy(tmpstr, curSearchPath->path); sstrcat(tmpstr, "base.wz"); PHYSFS_addToSearchPath( tmpstr, PHYSFS_APPEND ); curSearchPath = curSearchPath->higherPriority; } break; default: debug(LOG_ERROR, "Can't switch to unknown mods %i", mode); return false; } if (use_override_mods && mode != mod_clean) { if (strcmp(getModList(),override_mod_list)) { debug(LOG_POPUP, _("The required mod could not be loaded: %s\n\nWarzone will try to load the game without it."), override_mod_list); } clearOverrideMods(); current_mode = mod_override; } // User's home dir must be first so we allways see what we write PHYSFS_removeFromSearchPath(PHYSFS_getWriteDir()); PHYSFS_addToSearchPath( PHYSFS_getWriteDir(), PHYSFS_PREPEND ); #ifdef DEBUG printSearchPath(); #endif // DEBUG } else if (use_override_mods) { // override mods are already the same as current mods, so no need to do anything clearOverrideMods(); } return true; }
// load up the data for a level bool levLoadData(const char* name, char *pSaveName, GAME_TYPE saveType) { LEVEL_DATASET *psNewLevel, *psBaseData, *psChangeLevel; SDWORD i; bool bCamChangeSaveGame; debug(LOG_WZ, "Loading level %s (%s, type %d)", name, pSaveName, (int)saveType); if (saveType == GTYPE_SAVE_START || saveType == GTYPE_SAVE_MIDMISSION) { if (!levReleaseAll()) { debug(LOG_ERROR, "Failed to unload old data"); return false; } } levelLoadType = saveType; // find the level dataset psNewLevel = levFindDataSet(name); if (psNewLevel == NULL) { debug(LOG_WZ, "Dataset %s not found - trying to load as WRF", name); return levLoadSingleWRF(name); } debug(LOG_WZ, "** Data set found is %s type %d", psNewLevel->pName, (int)psNewLevel->type); /* Keep a copy of the present level name */ sstrcpy(currentLevelName, name); bCamChangeSaveGame = false; if (pSaveName && saveType == GTYPE_SAVE_START) { if (psNewLevel->psChange != NULL) { bCamChangeSaveGame = true; debug(LOG_WZ, "** CAMCHANGE FOUND"); } } // select the change dataset if there is one psChangeLevel = NULL; if (((psNewLevel->psChange != NULL) && (psCurrLevel != NULL)) || bCamChangeSaveGame) { //store the level name debug(LOG_WZ, "Found CAMCHANGE dataset"); psChangeLevel = psNewLevel; psNewLevel = psNewLevel->psChange; } // ensure the correct dataset is loaded if (psNewLevel->type == LDS_CAMPAIGN) { debug(LOG_ERROR, "Cannot load a campaign dataset (%s)", psNewLevel->pName); return false; } else { if (psCurrLevel != NULL) { if ((psCurrLevel->psBaseData != psNewLevel->psBaseData) || (psCurrLevel->type < LDS_NONE && psNewLevel->type >= LDS_NONE) || (psCurrLevel->type >= LDS_NONE && psNewLevel->type < LDS_NONE)) { // there is a dataset loaded but it isn't the correct one debug(LOG_WZ, "Incorrect base dataset loaded (%p != %p, %d - %d)", psCurrLevel->psBaseData, psNewLevel->psBaseData, (int)psCurrLevel->type, (int)psNewLevel->type); if (!levReleaseAll()) // this sets psCurrLevel to NULL { return false; } } else { debug(LOG_WZ, "Correct base dataset already loaded."); } } // setup the correct dataset to load if necessary if (psCurrLevel == NULL) { if (psNewLevel->psBaseData != NULL) { debug(LOG_WZ, "Setting base dataset to load: %s", psNewLevel->psBaseData->pName); } psBaseData = psNewLevel->psBaseData; } else { debug(LOG_WZ, "No base dataset to load"); psBaseData = NULL; } } setCurrentMap(psNewLevel->pName, psNewLevel->players); if (!rebuildSearchPath(psNewLevel->dataDir, true)) { return false; } // reset the old mission data if necessary if (psCurrLevel != NULL) { debug(LOG_WZ, "Reseting old mission data"); if (!levReleaseMissionData()) { return false; } } // need to free the current map and droids etc for a save game if ((psBaseData == NULL) && (pSaveName != NULL)) { if (!saveGameReset()) { return false; } } // initialise if necessary if (psNewLevel->type == LDS_COMPLETE || //psNewLevel->type >= LDS_MULTI_TYPE_START || psBaseData != NULL) { debug(LOG_WZ, "Calling stageOneInitialise!"); if (!stageOneInitialise()) { return false; } } // load up a base dataset if necessary if (psBaseData != NULL) { debug(LOG_WZ, "Loading base dataset %s", psBaseData->pName); for(i=0; i<LEVEL_MAXFILES; i++) { if (psBaseData->apDataFiles[i]) { // load the data debug(LOG_WZ, "Loading [directory: %s] %s ...", PHYSFS_getRealDir(psBaseData->apDataFiles[i]), psBaseData->apDataFiles[i]); if (!resLoad(psBaseData->apDataFiles[i], i)) { return false; } } } } if (psNewLevel->type == LDS_CAMCHANGE) { if (!campaignReset()) { return false; } } if (psNewLevel->game == -1) //no .gam file to load - BETWEEN missions (for Editor games only) { ASSERT( psNewLevel->type == LDS_BETWEEN, "levLoadData: only BETWEEN missions do not need a .gam file" ); debug(LOG_WZ, "No .gam file for level: BETWEEN mission"); if (pSaveName != NULL) { if (psBaseData != NULL) { if (!stageTwoInitialise()) { return false; } } //set the mission type before the saveGame data is loaded if (saveType == GTYPE_SAVE_MIDMISSION) { debug(LOG_WZ, "Init mission stuff"); if (!startMissionSave(psNewLevel->type)) { return false; } debug(LOG_NEVER, "dataSetSaveFlag"); dataSetSaveFlag(); } debug(LOG_NEVER, "Loading savegame: %s", pSaveName); if (!loadGame(pSaveName, false, true,true)) { return false; } } if ((pSaveName == NULL) || (saveType == GTYPE_SAVE_START)) { debug(LOG_NEVER, "Start mission - no .gam"); if (!startMission((LEVEL_TYPE)psNewLevel->type, NULL)) { return false; } } } //we need to load up the save game data here for a camchange if (bCamChangeSaveGame) { if (pSaveName != NULL) { if (psBaseData != NULL) { if (!stageTwoInitialise()) { return false; } } debug(LOG_NEVER, "loading savegame: %s", pSaveName); if (!loadGame(pSaveName, false, true,true)) { return false; } if (!campaignReset()) { return false; } } } // load the new data debug(LOG_NEVER, "Loading mission dataset: %s", psNewLevel->pName); for(i=0; i < LEVEL_MAXFILES; i++) { if (psNewLevel->game == i) { // do some more initialising if necessary if (psNewLevel->type == LDS_COMPLETE || psNewLevel->type >= LDS_MULTI_TYPE_START || (psBaseData != NULL && !bCamChangeSaveGame)) { if (!stageTwoInitialise()) { return false; } } // load a savegame if there is one - but not if already done so if (pSaveName != NULL && !bCamChangeSaveGame) { //set the mission type before the saveGame data is loaded if (saveType == GTYPE_SAVE_MIDMISSION) { debug(LOG_WZ, "Init mission stuff"); if (!startMissionSave(psNewLevel->type)) { return false; } debug(LOG_NEVER, "dataSetSaveFlag"); dataSetSaveFlag(); } debug(LOG_NEVER, "Loading save game %s", pSaveName); if (!loadGame(pSaveName, false, true,true)) { return false; } } if ((pSaveName == NULL) || (saveType == GTYPE_SAVE_START)) { // load the game debug(LOG_WZ, "Loading scenario file %s", psNewLevel->apDataFiles[i]); switch (psNewLevel->type) { case LDS_COMPLETE: case LDS_CAMSTART: debug(LOG_WZ, "LDS_COMPLETE / LDS_CAMSTART"); if (!startMission(LDS_CAMSTART, psNewLevel->apDataFiles[i])) { return false; } break; case LDS_BETWEEN: debug(LOG_WZ, "LDS_BETWEEN"); if (!startMission(LDS_BETWEEN, psNewLevel->apDataFiles[i])) { return false; } break; case LDS_MKEEP: debug(LOG_WZ, "LDS_MKEEP"); if (!startMission(LDS_MKEEP, psNewLevel->apDataFiles[i])) { return false; } break; case LDS_CAMCHANGE: debug(LOG_WZ, "LDS_CAMCHANGE"); if (!startMission(LDS_CAMCHANGE, psNewLevel->apDataFiles[i])) { return false; } break; case LDS_EXPAND: debug(LOG_WZ, "LDS_EXPAND"); if (!startMission(LDS_EXPAND, psNewLevel->apDataFiles[i])) { return false; } break; case LDS_EXPAND_LIMBO: debug(LOG_WZ, "LDS_LIMBO"); if (!startMission(LDS_EXPAND_LIMBO, psNewLevel->apDataFiles[i])) { return false; } break; case LDS_MCLEAR: debug(LOG_WZ, "LDS_MCLEAR"); if (!startMission(LDS_MCLEAR, psNewLevel->apDataFiles[i])) { return false; } break; case LDS_MKEEP_LIMBO: debug(LOG_WZ, "LDS_MKEEP_LIMBO"); if (!startMission(LDS_MKEEP_LIMBO, psNewLevel->apDataFiles[i])) { return false; } break; default: ASSERT( psNewLevel->type >= LDS_MULTI_TYPE_START, "levLoadData: Unexpected mission type" ); debug(LOG_WZ, "default (MULTIPLAYER)"); if (!startMission(LDS_CAMSTART, psNewLevel->apDataFiles[i])) { return false; } break; } } } else if (psNewLevel->apDataFiles[i]) { // load the data debug(LOG_WZ, "Loading %s", psNewLevel->apDataFiles[i]); if (!resLoad(psNewLevel->apDataFiles[i], i + CURRENT_DATAID)) { return false; } } } if (pSaveName != NULL) { //load MidMission Extras if (!loadMissionExtras(pSaveName, psNewLevel->type)) { return false; } } if (bMultiPlayer) { loadMultiScripts(); } if (pSaveName != NULL && saveType == GTYPE_SAVE_MIDMISSION) { //load script stuff // load the event system state here for a save game debug(LOG_SAVE, "Loading script system state"); if (!loadScriptState(pSaveName)) { return false; } } if (!stageThreeInitialise()) { return false; } dataClearSaveFlag(); //this enables us to to start cam2/cam3 without going via a save game and get the extra droids //in from the script-controlled Transporters if (!pSaveName && psNewLevel->type == LDS_CAMSTART) { eventFireCallbackTrigger((TRIGGER_TYPE)CALL_NO_REINFORCEMENTS_LEFT); } //restore the level name for comparisons on next mission load up if (psChangeLevel == NULL) { psCurrLevel = psNewLevel; } else { psCurrLevel = psChangeLevel; } { // Copy this info to be used by the crash handler for the dump file char buf[256]; ssprintf(buf, "Current Level/map is %s", psCurrLevel->pName); addDumpInfo(buf); } return true; }
/*! * \brief Adds default data dirs * * Priority: * Lower loads first. Current: * -datadir > User's home dir > source tree data > AutoPackage > BaseDir > DEFAULT_DATADIR * * Only -datadir and home dir are allways examined. Others only if data still not found. * * We need ParseCommandLine, before we can add any mods... * * \sa rebuildSearchPath */ static void scanDataDirs( void ) { char tmpstr[PATH_MAX], prefix[PATH_MAX]; char* separator; #if defined(WZ_OS_MAC) // version-independent location for video files registerSearchPath("/Library/Application Support/Warzone 2100/", 1); #endif // Find out which PREFIX we are in... sstrcpy(prefix, PHYSFS_getBaseDir()); separator = strrchr(prefix, *PHYSFS_getDirSeparator()); if (separator) { *separator = '\0'; // Trim ending '/', which getBaseDir always provides separator = strrchr(prefix, *PHYSFS_getDirSeparator()); if (separator) { *separator = '\0'; // Skip the last dir from base dir } } // Commandline supplied datadir if( strlen( datadir ) != 0 ) registerSearchPath( datadir, 1 ); // User's home dir registerSearchPath( PHYSFS_getWriteDir(), 2 ); rebuildSearchPath( mod_multiplay, true ); if( !PHYSFS_exists("gamedesc.lev") ) { // Data in source tree sstrcpy(tmpstr, prefix); sstrcat(tmpstr, "/data/"); registerSearchPath( tmpstr, 3 ); rebuildSearchPath( mod_multiplay, true ); if( !PHYSFS_exists("gamedesc.lev") ) { // Relocation for AutoPackage sstrcpy(tmpstr, prefix); sstrcat(tmpstr, "/share/warzone2100/"); registerSearchPath( tmpstr, 4 ); rebuildSearchPath( mod_multiplay, true ); if( !PHYSFS_exists("gamedesc.lev") ) { // Program dir registerSearchPath( PHYSFS_getBaseDir(), 5 ); rebuildSearchPath( mod_multiplay, true ); if( !PHYSFS_exists("gamedesc.lev") ) { // Guessed fallback default datadir on Unix registerSearchPath( WZ_DATADIR, 6 ); rebuildSearchPath( mod_multiplay, true ); } } } } #ifdef WZ_OS_MAC if( !PHYSFS_exists("gamedesc.lev") ) { CFURLRef resourceURL = CFBundleCopyResourcesDirectoryURL(CFBundleGetMainBundle()); char resourcePath[PATH_MAX]; if( CFURLGetFileSystemRepresentation( resourceURL, true, (UInt8 *) resourcePath, PATH_MAX) ) { chdir( resourcePath ); registerSearchPath( "data", 7 ); rebuildSearchPath( mod_multiplay, true ); } else { debug( LOG_ERROR, "Could not change to resources directory." ); } if( resourceURL != NULL ) { CFRelease( resourceURL ); } } #endif /** Debugging and sanity checks **/ printSearchPath(); if( PHYSFS_exists("gamedesc.lev") ) { debug( LOG_WZ, "gamedesc.lev found at %s", PHYSFS_getRealDir( "gamedesc.lev" ) ); } else { debug( LOG_FATAL, "Could not find game data. Aborting." ); exit(1); } }
// //////////////////////////////////////////////////////////////////////////// // options for a game. (usually recvd in frontend) void recvOptions(NETQUEUE queue) { unsigned int i; debug(LOG_NET, "Receiving options from host"); NETbeginDecode(queue, NET_OPTIONS); // Get general information about the game NETuint8_t(&game.type); NETstring(game.map, 128); NETbin(game.hash.bytes, game.hash.Bytes); uint32_t modHashesSize; NETuint32_t(&modHashesSize); ASSERT_OR_RETURN(, modHashesSize < 1000000, "Way too many mods %u", modHashesSize); game.modHashes.resize(modHashesSize); for (auto &hash : game.modHashes) { NETbin(hash.bytes, hash.Bytes); } NETuint8_t(&game.maxPlayers); NETstring(game.name, 128); NETuint32_t(&game.power); NETuint8_t(&game.base); NETuint8_t(&game.alliance); NETbool(&game.scavengers); NETbool(&game.isMapMod); for (i = 0; i < MAX_PLAYERS; i++) { NETuint8_t(&game.skDiff[i]); } // Send the list of who is still joining for (i = 0; i < MAX_PLAYERS; i++) { NETbool(&ingame.JoiningInProgress[i]); } // Alliances for (i = 0; i < MAX_PLAYERS; i++) { unsigned int j; for (j = 0; j < MAX_PLAYERS; j++) { NETuint8_t(&alliances[i][j]); } } netPlayersUpdated = true; // Free any structure limits we may have in-place if (ingame.numStructureLimits) { ingame.numStructureLimits = 0; free(ingame.pStructureLimits); ingame.pStructureLimits = NULL; } // Get the number of structure limits to expect NETuint32_t(&ingame.numStructureLimits); debug(LOG_NET, "Host is sending us %u structure limits", ingame.numStructureLimits); // If there were any changes allocate memory for them if (ingame.numStructureLimits) { ingame.pStructureLimits = (MULTISTRUCTLIMITS *)malloc(ingame.numStructureLimits * sizeof(MULTISTRUCTLIMITS)); } for (i = 0; i < ingame.numStructureLimits; i++) { NETuint32_t(&ingame.pStructureLimits[i].id); NETuint32_t(&ingame.pStructureLimits[i].limit); } NETuint8_t(&ingame.flags); NETend(); // Do the skirmish slider settings if they are up for (i = 0; i < MAX_PLAYERS; i++) { if (widgGetFromID(psWScreen, MULTIOP_SKSLIDE + i)) { widgSetSliderPos(psWScreen, MULTIOP_SKSLIDE + i, game.skDiff[i]); } } debug(LOG_INFO, "Rebuilding map list"); // clear out the old level list. levShutDown(); levInitialise(); rebuildSearchPath(mod_multiplay, true); // MUST rebuild search path for the new maps we just got! buildMapList(); bool haveData = true; auto requestFile = [&haveData](Sha256 &hash, char const *filename) { if (std::any_of(NetPlay.wzFiles.begin(), NetPlay.wzFiles.end(), [&hash](WZFile const &file) { return file.hash == hash; })) { debug(LOG_INFO, "Already requested file, continue waiting."); haveData = false; return false; // Downloading the file already } if (!PHYSFS_exists(filename)) { debug(LOG_INFO, "Creating new file %s", filename); } else if (findHashOfFile(filename) != hash) { debug(LOG_INFO, "Overwriting old incomplete or corrupt file %s", filename); } else { return false; // Have the file already. } NetPlay.wzFiles.emplace_back(PHYSFS_openWrite(filename), hash); // Request the map/mod from the host NETbeginEncode(NETnetQueue(NET_HOST_ONLY), NET_FILE_REQUESTED); NETbin(hash.bytes, hash.Bytes); NETend(); haveData = false; return true; // Starting download now. }; LEVEL_DATASET *mapData = levFindDataSet(game.map, &game.hash); // See if we have the map or not if (mapData == nullptr) { char mapName[256]; sstrcpy(mapName, game.map); removeWildcards(mapName); if (strlen(mapName) >= 3 && mapName[strlen(mapName) - 3] == '-' && mapName[strlen(mapName) - 2] == 'T' && unsigned(mapName[strlen(mapName) - 1] - '1') < 3) { mapName[strlen(mapName) - 3] = '\0'; // Cut off "-T1", "-T2" or "-T3". } char filename[256]; ssprintf(filename, "maps/%dc-%s-%s.wz", game.maxPlayers, mapName, game.hash.toString().c_str()); // Wonder whether game.maxPlayers is initialised already? if (requestFile(game.hash, filename)) { debug(LOG_INFO, "Map was not found, requesting map %s from host, type %d", game.map, game.isMapMod); addConsoleMessage("MAP REQUESTED!", DEFAULT_JUSTIFY, SYSTEM_MESSAGE); } else { debug(LOG_FATAL, "Can't load map %s, even though we downloaded %s", game.map, filename); abort(); } } for (Sha256 &hash : game.modHashes) { char filename[256]; ssprintf(filename, "mods/downloads/%s", hash.toString().c_str()); if (requestFile(hash, filename)) { debug(LOG_INFO, "Mod was not found, requesting mod %s from host", hash.toString().c_str()); addConsoleMessage("MOD REQUESTED!", DEFAULT_JUSTIFY, SYSTEM_MESSAGE); } } if (mapData && CheckForMod(mapData->realFileName)) { char const *str = game.isMapMod ? _("Warning, this is a map-mod, it could alter normal gameplay.") : _("Warning, HOST has altered the game code, and can't be trusted!"); addConsoleMessage(str, DEFAULT_JUSTIFY, NOTIFY_MESSAGE); game.isMapMod = true; } if (mapData) { loadMapPreview(false); } }
// //////////////////////////////////////////////////////////////////////////// // options for a game. (usually recvd in frontend) void recvOptions(NETQUEUE queue) { unsigned int i; debug(LOG_NET, "Receiving options from host"); NETbeginDecode(queue, NET_OPTIONS); // Get general information about the game NETuint8_t(&game.type); NETstring(game.map, 128); NETbin(game.hash.bytes, game.hash.Bytes); NETuint8_t(&game.maxPlayers); NETstring(game.name, 128); NETuint32_t(&game.power); NETuint8_t(&game.base); NETuint8_t(&game.alliance); NETbool(&game.scavengers); for (i = 0; i < MAX_PLAYERS; i++) { NETuint8_t(&game.skDiff[i]); } // Send the list of who is still joining for (i = 0; i < MAX_PLAYERS; i++) { NETbool(&ingame.JoiningInProgress[i]); } // Alliances for (i = 0; i < MAX_PLAYERS; i++) { unsigned int j; for (j = 0; j < MAX_PLAYERS; j++) { NETuint8_t(&alliances[i][j]); } } netPlayersUpdated = true; // Free any structure limits we may have in-place if (ingame.numStructureLimits) { ingame.numStructureLimits = 0; free(ingame.pStructureLimits); ingame.pStructureLimits = NULL; } // Get the number of structure limits to expect NETuint32_t(&ingame.numStructureLimits); debug(LOG_NET, "Host is sending us %u structure limits", ingame.numStructureLimits); // If there were any changes allocate memory for them if (ingame.numStructureLimits) { ingame.pStructureLimits = (MULTISTRUCTLIMITS *)malloc(ingame.numStructureLimits * sizeof(MULTISTRUCTLIMITS)); } for (i = 0; i < ingame.numStructureLimits; i++) { NETuint32_t(&ingame.pStructureLimits[i].id); NETuint32_t(&ingame.pStructureLimits[i].limit); } NETuint8_t(&ingame.flags); NETend(); // Do the skirmish slider settings if they are up for (i = 0; i < MAX_PLAYERS; i++) { if (widgGetFromID(psWScreen, MULTIOP_SKSLIDE + i)) { widgSetSliderPos(psWScreen, MULTIOP_SKSLIDE + i, game.skDiff[i]); } } debug(LOG_INFO, "Rebuilding map list"); // clear out the old level list. levShutDown(); levInitialise(); setCurrentMap(NULL, 42); rebuildSearchPath(mod_multiplay, true); // MUST rebuild search path for the new maps we just got! buildMapList(); // See if we have the map or not if (levFindDataSet(game.map, &game.hash) == NULL) { uint32_t player = selectedPlayer; debug(LOG_INFO, "Map was not found, requesting map %s from host.", game.map); // Request the map from the host NETbeginEncode(NETnetQueue(NET_HOST_ONLY), NET_FILE_REQUESTED); NETuint32_t(&player); NETend(); addConsoleMessage("MAP REQUESTED!", DEFAULT_JUSTIFY, SYSTEM_MESSAGE); } else { loadMapPreview(false); } }
/*! * \brief Rebuilds the PHYSFS searchPath with mode specific subdirs * * Priority: * maps > mods > base > base.wz */ bool rebuildSearchPath(searchPathMode mode, bool force, const char *current_map) { static searchPathMode current_mode = mod_clean; static std::string current_current_map; wzSearchPath *curSearchPath = searchPathRegistry; char tmpstr[PATH_MAX] = "\0"; if (mode != current_mode || (current_map != nullptr ? current_map : "") != current_current_map || force || (use_override_mods && override_mod_list != getModList())) { if (mode != mod_clean) { rebuildSearchPath(mod_clean, false); } current_mode = mode; current_current_map = current_map != nullptr ? current_map : ""; // Start at the lowest priority while (curSearchPath->lowerPriority) { curSearchPath = curSearchPath->lowerPriority; } switch (mode) { case mod_clean: debug(LOG_WZ, "Cleaning up"); clearLoadedMods(); while (curSearchPath) { #ifdef DEBUG debug(LOG_WZ, "Removing [%s] from search path", curSearchPath->path); #endif // DEBUG // Remove maps and mods removeSubdirs(curSearchPath->path, "maps"); removeSubdirs(curSearchPath->path, "mods/music"); removeSubdirs(curSearchPath->path, "mods/global"); removeSubdirs(curSearchPath->path, "mods"); removeSubdirs(curSearchPath->path, "mods/autoload"); removeSubdirs(curSearchPath->path, "mods/campaign"); removeSubdirs(curSearchPath->path, "mods/multiplay"); removeSubdirs(curSearchPath->path, "mods/downloads"); // Remove multiplay patches sstrcpy(tmpstr, curSearchPath->path); sstrcat(tmpstr, "mp"); WZ_PHYSFS_unmount(tmpstr); sstrcpy(tmpstr, curSearchPath->path); sstrcat(tmpstr, "mp.wz"); WZ_PHYSFS_unmount(tmpstr); // Remove plain dir WZ_PHYSFS_unmount(curSearchPath->path); // Remove base files sstrcpy(tmpstr, curSearchPath->path); sstrcat(tmpstr, "base"); WZ_PHYSFS_unmount(tmpstr); sstrcpy(tmpstr, curSearchPath->path); sstrcat(tmpstr, "base.wz"); WZ_PHYSFS_unmount(tmpstr); // remove video search path as well sstrcpy(tmpstr, curSearchPath->path); sstrcat(tmpstr, "sequences.wz"); WZ_PHYSFS_unmount(tmpstr); curSearchPath = curSearchPath->higherPriority; } break; case mod_campaign: debug(LOG_WZ, "*** Switching to campaign mods ***"); clearLoadedMods(); while (curSearchPath) { // make sure videos override included files sstrcpy(tmpstr, curSearchPath->path); sstrcat(tmpstr, "sequences.wz"); PHYSFS_mount(tmpstr, NULL, PHYSFS_APPEND); curSearchPath = curSearchPath->higherPriority; } curSearchPath = searchPathRegistry; while (curSearchPath->lowerPriority) { curSearchPath = curSearchPath->lowerPriority; } while (curSearchPath) { #ifdef DEBUG debug(LOG_WZ, "Adding [%s] to search path", curSearchPath->path); #endif // DEBUG // Add global and campaign mods PHYSFS_mount(curSearchPath->path, NULL, PHYSFS_APPEND); addSubdirs(curSearchPath->path, "mods/music", PHYSFS_APPEND, nullptr, false); addSubdirs(curSearchPath->path, "mods/global", PHYSFS_APPEND, use_override_mods ? &override_mods : &global_mods, true); addSubdirs(curSearchPath->path, "mods", PHYSFS_APPEND, use_override_mods ? &override_mods : &global_mods, true); addSubdirs(curSearchPath->path, "mods/autoload", PHYSFS_APPEND, use_override_mods ? &override_mods : nullptr, true); addSubdirs(curSearchPath->path, "mods/campaign", PHYSFS_APPEND, use_override_mods ? &override_mods : &campaign_mods, true); if (!WZ_PHYSFS_unmount(curSearchPath->path)) { debug(LOG_WZ, "* Failed to remove path %s again", curSearchPath->path); } // Add plain dir PHYSFS_mount(curSearchPath->path, NULL, PHYSFS_APPEND); // Add base files sstrcpy(tmpstr, curSearchPath->path); sstrcat(tmpstr, "base"); PHYSFS_mount(tmpstr, NULL, PHYSFS_APPEND); sstrcpy(tmpstr, curSearchPath->path); sstrcat(tmpstr, "base.wz"); PHYSFS_mount(tmpstr, NULL, PHYSFS_APPEND); curSearchPath = curSearchPath->higherPriority; } break; case mod_multiplay: debug(LOG_WZ, "*** Switching to multiplay mods ***"); clearLoadedMods(); while (curSearchPath) { // make sure videos override included files sstrcpy(tmpstr, curSearchPath->path); sstrcat(tmpstr, "sequences.wz"); PHYSFS_mount(tmpstr, NULL, PHYSFS_APPEND); curSearchPath = curSearchPath->higherPriority; } // Add the selected map first, for mapmod support if (current_map != nullptr) { WzString realPathAndDir = WzString::fromUtf8(PHYSFS_getRealDir(current_map)) + current_map; realPathAndDir.replace("/", PHYSFS_getDirSeparator()); // Windows fix PHYSFS_mount(realPathAndDir.toUtf8().c_str(), NULL, PHYSFS_APPEND); } curSearchPath = searchPathRegistry; while (curSearchPath->lowerPriority) { curSearchPath = curSearchPath->lowerPriority; } while (curSearchPath) { #ifdef DEBUG debug(LOG_WZ, "Adding [%s] to search path", curSearchPath->path); #endif // DEBUG // Add global and multiplay mods PHYSFS_mount(curSearchPath->path, NULL, PHYSFS_APPEND); addSubdirs(curSearchPath->path, "mods/music", PHYSFS_APPEND, nullptr, false); if (NetPlay.isHost || !NetPlay.bComms) { addSubdirs(curSearchPath->path, "mods/global", PHYSFS_APPEND, use_override_mods ? &override_mods : &global_mods, true); addSubdirs(curSearchPath->path, "mods", PHYSFS_APPEND, use_override_mods ? &override_mods : &global_mods, true); addSubdirs(curSearchPath->path, "mods/autoload", PHYSFS_APPEND, use_override_mods ? &override_mods : nullptr, true); addSubdirs(curSearchPath->path, "mods/multiplay", PHYSFS_APPEND, use_override_mods ? &override_mods : &multiplay_mods, true); } else { std::vector<std::string> hashList; for (Sha256 &hash : game.modHashes) { hashList = {hash.toString()}; addSubdirs(curSearchPath->path, "mods/downloads", PHYSFS_APPEND, &hashList, true); } } WZ_PHYSFS_unmount(curSearchPath->path); // Add multiplay patches sstrcpy(tmpstr, curSearchPath->path); sstrcat(tmpstr, "mp"); PHYSFS_mount(tmpstr, NULL, PHYSFS_APPEND); sstrcpy(tmpstr, curSearchPath->path); sstrcat(tmpstr, "mp.wz"); PHYSFS_mount(tmpstr, NULL, PHYSFS_APPEND); // Add plain dir PHYSFS_mount(curSearchPath->path, NULL, PHYSFS_APPEND); // Add base files sstrcpy(tmpstr, curSearchPath->path); sstrcat(tmpstr, "base"); PHYSFS_mount(tmpstr, NULL, PHYSFS_APPEND); sstrcpy(tmpstr, curSearchPath->path); sstrcat(tmpstr, "base.wz"); PHYSFS_mount(tmpstr, NULL, PHYSFS_APPEND); curSearchPath = curSearchPath->higherPriority; } break; default: debug(LOG_ERROR, "Can't switch to unknown mods %i", mode); return false; } if (use_override_mods && mode != mod_clean) { if (getModList() != override_mod_list) { debug(LOG_POPUP, _("The required mod could not be loaded: %s\n\nWarzone will try to load the game without it."), override_mod_list.c_str()); } clearOverrideMods(); current_mode = mod_override; } // User's home dir must be first so we always see what we write WZ_PHYSFS_unmount(PHYSFS_getWriteDir()); PHYSFS_mount(PHYSFS_getWriteDir(), NULL, PHYSFS_PREPEND); #ifdef DEBUG printSearchPath(); #endif // DEBUG } else if (use_override_mods) { // override mods are already the same as current mods, so no need to do anything clearOverrideMods(); } return true; }