/* ** Command & Conquer Generals Zero Hour(tm) ** Copyright 2025 Electronic Arts Inc. ** ** This program is free software: you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation, either version 3 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program. If not, see . */ //////////////////////////////////////////////////////////////////////////////// // // // (c) 2001-2003 Electronic Arts Inc. // // // //////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////// // FILE: FileTransfer.cpp // Author: Matthew D. Campbell, December 2002 // Description: File Transfer wrapper using TheNetwork /////////////////////////////////////////////////////////////////////////////////////// #include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine #include "GameClient/LoadScreen.h" #include "GameClient/Shell.h" #include "GameNetwork/FileTransfer.h" #include "GameNetwork/NetworkUtil.h" //------------------------------------------------------------------------------------- //------------------------------------------------------------------------------------- static Bool doFileTransfer( AsciiString filename, MapTransferLoadScreen *ls, Int mask ) { Bool fileTransferDone = FALSE; Int fileTransferPercent = 0; Int i; if (mask) { ls->setCurrentFilename(filename); UnsignedInt startTime = timeGetTime(); const Int timeoutPeriod = 2*60*1000; ls->processTimeout(timeoutPeriod/1000); ls->update(0); fileTransferDone = FALSE; fileTransferPercent = 0; UnsignedShort fileCommandID = 0; Bool sentFile = FALSE; if (TheGameInfo->amIHost()) { Sleep(500); fileCommandID = TheNetwork->sendFileAnnounce(filename, mask); } else { sentFile = TRUE; } DEBUG_LOG(("Starting file transfer loop\n")); while (!fileTransferDone) { if (!sentFile && TheNetwork->areAllQueuesEmpty()) { TheNetwork->sendFile(filename, mask, fileCommandID); sentFile = TRUE; } // get the progress for each player, and take the min for our overall progress fileTransferDone = TRUE; fileTransferPercent = 100; for (i=1; igetConstSlot(i)->isHuman() && !TheGameInfo->getConstSlot(i)->hasMap()) { Int slotTransferPercent = TheNetwork->getFileTransferProgress(i, filename); fileTransferPercent = min(fileTransferPercent, slotTransferPercent); if (slotTransferPercent == 0) ls->processProgress(i, slotTransferPercent, "MapTransfer:Preparing"); else if (slotTransferPercent < 100) ls->processProgress(i, slotTransferPercent, "MapTransfer:Recieving"); else ls->processProgress(i, slotTransferPercent, "MapTransfer:Done"); } } if (fileTransferPercent < 100) { fileTransferDone = FALSE; if (fileTransferPercent == 0) ls->processProgress(0, fileTransferPercent, "MapTransfer:Preparing"); else ls->processProgress(0, fileTransferPercent, "MapTransfer:Sending"); } else { DEBUG_LOG(("File transfer is 100%%!\n")); ls->processProgress(0, fileTransferPercent, "MapTransfer:Done"); } Int now = timeGetTime(); if (now > startTime + timeoutPeriod) // bail if we don't finish in a reasonable amount of time { DEBUG_LOG(("Timing out file transfer\n")); break; } else { ls->processTimeout((startTime + timeoutPeriod - now)/1000); } ls->update(fileTransferPercent); } if (!fileTransferDone) { return FALSE; } } return TRUE; } //------------------------------------------------------------------------------------- //------------------------------------------------------------------------------------- AsciiString GetBasePathFromPath( AsciiString path ) { const char *s = path.reverseFind('\\'); if (s) { Int len = s - path.str(); AsciiString base; char *buf = base.getBufferForRead(len + 1); memcpy(buf, path.str(), len); buf[len] = 0; return buf; } return AsciiString::TheEmptyString; } AsciiString GetFileFromPath( AsciiString path ) { const char *s = path.reverseFind('\\'); if (s) return s+1; return path; } AsciiString GetExtensionFromFile( AsciiString fname ) { const char *s = fname.reverseFind('.'); if (s) return s+1; return fname; } AsciiString GetBaseFileFromFile( AsciiString fname ) { const char *s = fname.reverseFind('.'); if (s) { Int len = s - fname.str(); AsciiString base; char *buf = base.getBufferForRead(len + 1); memcpy(buf, fname.str(), len); buf[len] = 0; return buf; } return AsciiString::TheEmptyString; } AsciiString GetPreviewFromMap( AsciiString path ) { AsciiString fname = GetBaseFileFromFile(GetFileFromPath(path)); AsciiString base = GetBasePathFromPath(path); AsciiString out; out.format("%s\\%s.tga", base.str(), fname.str()); return out; } AsciiString GetINIFromMap( AsciiString path ) { AsciiString base = GetBasePathFromPath(path); AsciiString out; out.format("%s\\map.ini", base.str()); return out; } AsciiString GetStrFileFromMap( AsciiString path ) { AsciiString base = GetBasePathFromPath(path); AsciiString out; out.format("%s\\map.str", base.str()); return out; } AsciiString GetSoloINIFromMap( AsciiString path ) { AsciiString base = GetBasePathFromPath(path); AsciiString out; out.format("%s\\solo.ini", base.str()); return out; } AsciiString GetAssetUsageFromMap( AsciiString path ) { AsciiString base = GetBasePathFromPath(path); AsciiString out; out.format("%s\\assetusage.txt", base.str()); return out; } AsciiString GetReadmeFromMap( AsciiString path ) { AsciiString base = GetBasePathFromPath(path); AsciiString out; out.format("%s\\readme.txt", base.str()); return out; } //------------------------------------------------------------------------------------- //------------------------------------------------------------------------------------- Bool DoAnyMapTransfers(GameInfo *game) { TheGameInfo = game; Int mask = 0; Int i=0; for (i=1; igetConstSlot(i)->isHuman() && !TheGameInfo->getConstSlot(i)->hasMap()) { DEBUG_LOG(("Adding player %d to transfer mask\n", i)); mask |= (1<hideShell(); MapTransferLoadScreen *ls = NEW MapTransferLoadScreen; ls->init(TheGameInfo); Bool ok = TRUE; if (TheGameInfo->getMapContentsMask() & 2) ok = doFileTransfer(GetPreviewFromMap(game->getMap()), ls, mask); if (ok && TheGameInfo->getMapContentsMask() & 4) ok = doFileTransfer(GetINIFromMap(game->getMap()), ls, mask); if (ok && TheGameInfo->getMapContentsMask() & 8) ok = doFileTransfer(GetStrFileFromMap(game->getMap()), ls, mask); if (ok && TheGameInfo->getMapContentsMask() & 16) ok = doFileTransfer(GetSoloINIFromMap(game->getMap()), ls, mask); if (ok && TheGameInfo->getMapContentsMask() & 32) ok = doFileTransfer(GetAssetUsageFromMap(game->getMap()), ls, mask); if (ok && TheGameInfo->getMapContentsMask() & 64) ok = doFileTransfer(GetReadmeFromMap(game->getMap()), ls, mask); if (ok) ok = doFileTransfer(game->getMap(), ls, mask); delete ls; ls = NULL; if (!ok) TheShell->showShell(); return ok; }