X-Git-Url: http://deadsoftware.ru/gitweb?a=blobdiff_plain;f=src%2Fgame%2Fg_res_downloader.pas;h=8bd5e04cd70ddd6dcd87e2be585261c3e067c480;hb=d0936017ccb8a078d1b03f55478af284bb015bbc;hp=098e0dd706313aa02bc4a6037541bd241f66f21b;hpb=782be84c041a01f0255ce718e2b5757d31e5c0d9;p=d2df-sdl.git diff --git a/src/game/g_res_downloader.pas b/src/game/g_res_downloader.pas index 098e0dd..8bd5e04 100644 --- a/src/game/g_res_downloader.pas +++ b/src/game/g_res_downloader.pas @@ -17,7 +17,7 @@ unit g_res_downloader; interface -uses sysutils, Classes, md5, g_net, g_netmsg, g_console, g_main, e_log; +uses sysutils, Classes, md5, g_net, g_netmsg, g_console, e_log; // download map wad from server (if necessary) @@ -30,12 +30,12 @@ function g_Res_DownloadMapWAD (FileName: AnsiString; const mapHash: TMD5Digest): function g_Res_FindReplacementWad (oldname: AnsiString): AnsiString; // call this somewhere in startup sequence -procedure g_Res_CreateDatabases (); +procedure g_Res_CreateDatabases (allowRescan: Boolean=false); implementation -uses g_language, sfs, utils, wadreader, g_game, hashtable, fhashdb; +uses g_language, sfs, utils, wadreader, g_game, hashtable, fhashdb, e_res, g_options; var // cvars @@ -58,8 +58,11 @@ procedure saveDatabases (saveMap, saveRes: Boolean); var err: Boolean; st: TStream; + ccdir: AnsiString = ''; begin if (not saveDBsToDiskEnabled) or (not g_res_save_databases) then exit; + ccdir := e_GetWriteableDir(CacheDirs, false); + if (length(ccdir) = 0) then exit; // rescan dirs // save map database if (saveMap) then @@ -67,7 +70,7 @@ begin err := true; st := nil; try - st := createDiskFile(GameDir+'/data/maphash.db'); + st := createDiskFile(ccdir+'/maphash.db'); knownMaps.saveTo(st); err := false; except @@ -81,7 +84,7 @@ begin err := true; st := nil; try - st := createDiskFile(GameDir+'/data/reshash.db'); + st := createDiskFile(ccdir+'/reshash.db'); knownRes.saveTo(st); err := false; except @@ -97,40 +100,62 @@ end; // g_Res_CreateDatabases // //========================================================================== -procedure g_Res_CreateDatabases (); +procedure g_Res_CreateDatabases (allowRescan: Boolean=false); var st: TStream; + upmap: Boolean; + upres: Boolean; + forcesave: Boolean; + ccdir: AnsiString = ''; begin - // create and load a know map database, if necessary - knownMaps.Free; - knownMaps := TFileHashDB.Create(GameDir+'/maps/'); - knownRes := TFileHashDB.Create(GameDir+'/wads/'); - saveDBsToDiskEnabled := true; - // load map database - st := nil; - try - st := openDiskFileRO(GameDir+'/data/maphash.db'); - knownMaps.loadFrom(st); - e_LogWriteln('loaded map database'); - except - end; - st.Free; - // load resource database - st := nil; - try - st := openDiskFileRO(GameDir+'/data/reshash.db'); - knownRes.loadFrom(st); - e_LogWriteln('loaded resource database'); - except + if not assigned(knownMaps) then + begin + // create and load a know map database, if necessary + knownMaps := TFileHashDB.Create({GameDir}'', MapDirs); + knownMaps.appendMoreDirs(MapDownloadDirs); + knownRes := TFileHashDB.Create({GameDir}'', WadDirs); + knownRes.appendMoreDirs(WadDownloadDirs); + saveDBsToDiskEnabled := true; + // load map database + st := nil; + try + ccdir := e_GetWriteableDir(CacheDirs, false); + if (length(ccdir) > 0) then + begin + st := openDiskFileRO(ccdir+'/maphash.db'); + knownMaps.loadFrom(st); + e_LogWriteln('loaded map database'); + end; + except + end; + st.Free; + // load resource database + st := nil; + try + if (length(ccdir) > 0) then + begin + st := openDiskFileRO(ccdir+'/reshash.db'); + knownRes.loadFrom(st); + e_LogWriteln('loaded resource database'); + end; + except + end; + st.Free; + forcesave := true; + end + else + begin + if (not allowRescan) then exit; + forcesave := false; end; - st.Free; // rescan dirs e_LogWriteln('refreshing map database'); - knownMaps.scanFiles(); + upmap := knownMaps.scanFiles(); e_LogWriteln('refreshing resource database'); - knownRes.scanFiles(); + upres := knownRes.scanFiles(); // save databases - saveDatabases(true, true); + if (forcesave) then begin upmap := true; upres := true; end; + if upmap or upres then saveDatabases(upmap, upres); end; @@ -242,80 +267,6 @@ begin end; -//========================================================================== -// -// scanDir -// -// look for a wad to match the hash -// scans subdirs, ignores known wad extensions -// -// returns found wad disk name, or empty string -// -//========================================================================== -(* -function scanDir (dirName: AnsiString; baseName: AnsiString; const resMd5: TMD5Digest): AnsiString; -var - searchResult: TSearchRec; - dfn: AnsiString; - md5: TMD5Digest; - dirs: array of AnsiString; - f: Integer; -begin - result := ''; - SetLength(dirs, 0); - if (length(baseName) = 0) then exit; - dirName := IncludeTrailingPathDelimiter(dirName); - e_LogWritefln('scanning dir `%s` for file `%s`...', [dirName, baseName]); - - // scan files - if (FindFirst(dirName+'*', faAnyFile, searchResult) <> 0) then exit; - try - repeat - if ((searchResult.Attr and faDirectory) = 0) then - begin - if (isWadNamesEqu(searchResult.Name, baseName)) then - begin - dfn := dirName+searchResult.Name; - if FileExists(dfn) then - begin - e_LogWritefln(' found `%s`...', [dfn]); - md5 := MD5File(dfn); - if MD5Match(md5, resMd5) then - begin - e_LogWritefln(' MATCH `%s`...', [dfn]); - SetLength(dirs, 0); - result := dfn; - exit; - end; - end; - end; - end - else - begin - if (searchResult.Name <> '.') and (searchResult.Name <> '..') then - begin - dfn := dirName+searchResult.Name; - SetLength(dirs, Length(dirs)+1); - dirs[length(dirs)-1] := dfn; - end; - end; - until (FindNext(searchResult) <> 0); - finally - FindClose(searchResult); - end; - - // scan subdirs - for f := 0 to High(dirs) do - begin - dfn := dirs[f]; - result := scanDir(dfn, baseName, resMd5); - if (length(result) <> 0) then begin SetLength(dirs, 0); exit; end; - end; - SetLength(dirs, 0); -end; -*) - - //========================================================================== // // findExistingMapWadWithHash @@ -327,11 +278,10 @@ end; //========================================================================== function findExistingMapWadWithHash (fname: AnsiString; const resMd5: TMD5Digest): AnsiString; begin - //result := scanDir(GameDir+'/maps', ExtractFileName(fname), resMd5); result := knownMaps.findByHash(resMd5); if (length(result) > 0) then begin - result := GameDir+'/maps/'+result; + //result := GameDir+'/maps/'+result; if not FileExists(result) then begin if (knownMaps.scanFiles()) then saveDatabases(true, false); @@ -352,11 +302,10 @@ end; //========================================================================== function findExistingResWadWithHash (fname: AnsiString; const resMd5: TMD5Digest): AnsiString; begin - //result := scanDir(GameDir+'/wads', ExtractFileName(fname), resMd5); result := knownRes.findByHash(resMd5); if (length(result) > 0) then begin - result := GameDir+'/wads/'+result; + //result := GameDir+'/wads/'+result; if not FileExists(result) then begin if (knownRes.scanFiles()) then saveDatabases(false, true); @@ -408,7 +357,7 @@ end; function g_Res_DownloadMapWAD (FileName: AnsiString; const mapHash: TMD5Digest): AnsiString; var tf: TNetFileTransfer; - resList: TStringList; + resList: array of TNetMapResourceInfo = nil; f, res: Integer; strm: TStream; fname: AnsiString; @@ -416,21 +365,24 @@ var md5: TMD5Digest; mapdbUpdated: Boolean = false; resdbUpdated: Boolean = false; + transStarted: Boolean; + destMapDir: AnsiString = ''; + destResDir: AnsiString = ''; begin result := ''; clearReplacementWads(); - - resList := TStringList.Create(); + sfsGCCollect(); // why not? + g_Res_CreateDatabases(); + FileName := ExtractFileName(FileName); + if (length(FileName) = 0) then FileName := '__unititled__.wad'; try g_Res_received_map_start := 1; g_Console_Add(Format(_lc[I_NET_MAP_DL], [FileName])); - e_WriteLog('Downloading map `' + FileName + '` from server', TMsgType.Notify); + e_LogWritefln('Downloading map [%s] from server...', [FileName], TMsgType.Notify); g_Game_SetLoadingText(FileName + '...', 0, False); - if (not g_Net_SendMapRequest()) then exit; - FileName := ExtractFileName(FileName); - if (length(FileName) = 0) then FileName := 'fucked_map_wad.wad'; + // this also sends map request res := g_Net_Wait_MapInfo(tf, resList); if (res <> 0) then exit; @@ -447,22 +399,29 @@ begin exit; end; try - CreateDir(GameDir+'/maps/downloads'); + destMapDir := e_GetWriteableDir(MapDownloadDirs, false); // not required except end; - fname := GameDir+'/maps/downloads/'+generateFileName(FileName, mapHash); + if (length(destMapDir) = 0) then + begin + e_LogWriteln('cannot create map download directory', TMsgType.Fatal); + result := ''; + exit; + end; + fname := destMapDir+'/'+generateFileName(FileName, mapHash); tf.diskName := fname; + e_LogWritefln('map disk file for `%s` is `%s`', [FileName, fname], TMsgType.Fatal); try strm := openDiskFileRW(fname); except - e_WriteLog('cannot create map file `'+FileName+'`', TMsgType.Fatal); + e_WriteLog('cannot create map file `'+fname+'`', TMsgType.Fatal); result := ''; exit; end; try res := g_Net_ReceiveResourceFile(-1{map}, tf, strm); except - e_WriteLog('error downloading map file `'+FileName+'`', TMsgType.Fatal); + e_WriteLog('error downloading map file (exception) `'+FileName+'`', TMsgType.Fatal); strm.Free; result := ''; exit; @@ -470,7 +429,7 @@ begin strm.Free; if (res <> 0) then begin - e_WriteLog('error downloading map file `'+FileName+'`', TMsgType.Fatal); + e_LogWritefln('error downloading map `%s` (res=%d)', [FileName, res], TMsgType.Fatal); result := ''; exit; end; @@ -486,7 +445,7 @@ begin DeleteFile(fname); strm := createDiskFile(fname); except - e_WriteLog('cannot create map file `'+fname+'`', TMsgType.Fatal); + e_WriteLog('cannot create map file `'+fname+'` (exception)', TMsgType.Fatal); result := ''; exit; end; @@ -501,7 +460,7 @@ begin strm.Free; if (res <> 0) then begin - e_WriteLog('error downloading map file `'+FileName+'`', TMsgType.Fatal); + e_LogWritefln('error downloading map `%s` (res=%d)', [FileName, res], TMsgType.Fatal); result := ''; exit; end; @@ -512,14 +471,28 @@ begin end; // download resources - for f := 0 to resList.Count-1 do + for f := 0 to High(resList) do begin - res := g_Net_RequestResFileInfo(f, tf); - if (res <> 0) then begin result := ''; exit; end; + // if we got a new-style reslist packet, use received data to check for resource files + if (resList[f].size < 0) then + begin + // old-style packet + transStarted := true; + res := g_Net_RequestResFileInfo(f, tf); + if (res <> 0) then begin result := ''; exit; end; + end + else + begin + // new-style packet + transStarted := false; + tf.diskName := resList[f].wadName; + tf.hash := resList[f].hash; + tf.size := resList[f].size; + end; if (isIgnoredResWad(tf.diskName)) then begin // ignored file, abort download - g_Net_AbortResTransfer(tf); + if (transStarted) then g_Net_AbortResTransfer(tf); e_LogWritefln('ignoring wad resource `%s` by user request', [tf.diskName]); continue; end; @@ -527,16 +500,27 @@ begin if (length(wadname) <> 0) then begin // already here - g_Net_AbortResTransfer(tf); + if (transStarted) then g_Net_AbortResTransfer(tf); addReplacementWad(tf.diskName, wadname); end else begin + if (not transStarted) then + begin + res := g_Net_RequestResFileInfo(f, tf); + if (res <> 0) then begin result := ''; exit; end; + end; try - CreateDir(GameDir+'/wads/downloads'); + destResDir := e_GetWriteableDir(WadDownloadDirs, false); // not required except end; - fname := GameDir+'/wads/downloads/'+generateFileName(tf.diskName, tf.hash); + if (length(destResDir) = 0) then + begin + e_LogWriteln('cannot create wad download directory', TMsgType.Fatal); + result := ''; + exit; + end; + fname := destResDir+'/'+generateFileName(tf.diskName, tf.hash); e_LogWritefln('downloading resource `%s` to `%s`...', [tf.diskName, fname]); try strm := openDiskFileRW(fname); @@ -598,7 +582,7 @@ begin end; end; finally - resList.Free; + SetLength(resList, 0); g_Res_received_map_start := 0; end;