X-Git-Url: http://deadsoftware.ru/gitweb?a=blobdiff_plain;f=src%2Fgame%2Fg_res_downloader.pas;h=0b8d352eaab736e29962ea5e09d368ca8f913484;hb=cc289b13a569e26fa6fb389f215719af031c35a2;hp=ed1ea3bdf3feb7c77de12529d99b0b146c67d94b;hpb=b171ccb122f9084809e739b19baf68bba80a9dab;p=d2df-sdl.git diff --git a/src/game/g_res_downloader.pas b/src/game/g_res_downloader.pas index ed1ea3b..0b8d352 100644 --- a/src/game/g_res_downloader.pas +++ b/src/game/g_res_downloader.pas @@ -20,7 +20,6 @@ interface uses sysutils, Classes, md5, g_net, g_netmsg, g_console, g_main, e_log; function g_Res_SearchSameWAD(const path, filename: AnsiString; const resMd5: TMD5Digest): AnsiString; -function g_Res_SearchResWad (asMap: Boolean; const resMd5: TMD5Digest): AnsiString; // download map wad from server (if necessary) // download all required map resource wads too @@ -38,120 +37,12 @@ implementation uses g_language, sfs, utils, wadreader, g_game, hashtable; -const DOWNLOAD_DIR = 'downloads'; - -type - TFileInfo = record - diskName: AnsiString; // lowercased - baseName: AnsiString; // lowercased - md5: TMD5Digest; - md5valid: Boolean; - nextBaseNameIndex: Integer; - end; +//const DOWNLOAD_DIR = 'downloads'; var - knownFiles: array of TFileInfo; - knownHash: THashStrInt = nil; // key: base name; value: index - scannedDirs: THashStrInt = nil; // key: lowercased dir name replacements: THashStrStr = nil; -function findKnownFile (diskName: AnsiString): Integer; -var - idx: Integer; - baseName: AnsiString; -begin - result := -1; - if not assigned(knownHash) then exit; - if (length(diskName) = 0) then exit; - baseName := toLowerCase1251(ExtractFileName(diskName)); - if (not knownHash.get(baseName, idx)) then exit; - if (idx < 0) or (idx >= length(knownFiles)) then raise Exception.Create('wutafuck?'); - while (idx >= 0) do - begin - if (strEquCI1251(knownFiles[idx].diskName, diskName)) then begin result := idx; exit; end; // i found her! - idx := knownFiles[idx].nextBaseNameIndex; - end; -end; - - -function addKnownFile (diskName: AnsiString): Integer; -var - idx: Integer; - lastIdx: Integer = -1; - baseName: AnsiString; - fi: ^TFileInfo; -begin - result := -1; - if not assigned(knownHash) then knownHash := THashStrInt.Create(); - if (length(diskName) = 0) then exit; - baseName := toLowerCase1251(ExtractFileName(diskName)); - if (length(baseName) = 0) then exit; - // check if we already have this file - if (knownHash.get(baseName, idx)) then - begin - if (idx < 0) or (idx >= length(knownFiles)) then raise Exception.Create('wutafuck?'); - while (idx >= 0) do - begin - if (strEquCI1251(knownFiles[idx].diskName, diskName)) then - begin - // already here - result := idx; - exit; - end; - lastIdx := idx; - idx := knownFiles[idx].nextBaseNameIndex; - end; - end; - // this file is not there, append it - idx := length(knownFiles); - result := idx; - SetLength(knownFiles, idx+1); // sorry - fi := @knownFiles[idx]; - fi.diskName := diskName; - fi.baseName := baseName; - fi.md5valid := false; - fi.nextBaseNameIndex := -1; - if (lastIdx < 0) then - begin - // totally new one - knownHash.put(baseName, idx); - end - else - begin - knownFiles[lastIdx].nextBaseNameIndex := idx; - end; -end; - - -function getKnownFileWithMD5 (diskDir: AnsiString; baseName: AnsiString; const md5: TMD5Digest): AnsiString; -var - idx: Integer; -begin - result := ''; - if not assigned(knownHash) then exit; - if (not knownHash.get(toLowerCase1251(baseName), idx)) then exit; - if (idx < 0) or (idx >= length(knownFiles)) then raise Exception.Create('wutafuck?'); - while (idx >= 0) do - begin - if (strEquCI1251(knownFiles[idx].diskName, IncludeTrailingPathDelimiter(diskDir)+baseName)) then - begin - if (not knownFiles[idx].md5valid) then - begin - knownFiles[idx].md5 := MD5File(knownFiles[idx].diskName); - knownFiles[idx].md5valid := true; - end; - if (MD5Match(knownFiles[idx].md5, md5)) then - begin - result := knownFiles[idx].diskName; - exit; - end; - end; - idx := knownFiles[idx].nextBaseNameIndex; - end; -end; - - // call this before downloading a new map from a server procedure g_Res_ClearReplacementWads (); begin @@ -174,100 +65,91 @@ end; procedure g_Res_PutReplacementWad (oldname: AnsiString; newDiskName: AnsiString); begin e_LogWritefln('adding replacement wad: oldname=%s; newname=%s', [oldname, newDiskName]); + if not assigned(replacements) then replacements := THashStrStr.Create(); replacements.put(toLowerCase1251(oldname), newDiskName); end; -procedure scanDir (const dirName: AnsiString; calcMD5: Boolean); +function scanDir (dirName: AnsiString; baseName: AnsiString; const resMd5: TMD5Digest): AnsiString; var searchResult: TSearchRec; dfn: AnsiString; - idx: Integer; + md5: TMD5Digest; + dirs: array of AnsiString; + f: Integer; begin - if not assigned(scannedDirs) then scannedDirs := THashStrInt.Create(); - dfn := toLowerCase1251(IncludeTrailingPathDelimiter(dirName)); - if scannedDirs.has(dfn) then exit; - scannedDirs.put(dfn, 42); + result := ''; + SetLength(dirs, 0); + if (length(baseName) = 0) then exit; + dirName := IncludeTrailingPathDelimiter(dirName); + e_LogWritefln('scanning dir `%s` for file `%s`...', [dirName, baseName]); - if (FindFirst(dirName+'/*', faAnyFile, searchResult) <> 0) then exit; + // scan files + if (FindFirst(dirName+'*', faAnyFile, searchResult) <> 0) then exit; try repeat - if (searchResult.Attr and faDirectory) = 0 then + if ((searchResult.Attr and faDirectory) = 0) then begin - dfn := dirName+'/'+searchResult.Name; - idx := addKnownFile(dfn); - if (calcMD5) and (idx >= 0) then + if (isWadNamesEqu(searchResult.Name, baseName)) then begin - if (not knownFiles[idx].md5valid) then + dfn := dirName+searchResult.Name; + if FileExists(dfn) then begin - knownFiles[idx].md5 := MD5File(knownFiles[idx].diskName); - knownFiles[idx].md5valid := true; + 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 if (searchResult.Name <> '.') and (searchResult.Name <> '..') then + else begin - scanDir(IncludeTrailingPathDelimiter(dirName)+searchResult.Name, calcMD5); + 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; -end; - - -function CompareFileHash(const filename: AnsiString; const resMd5: TMD5Digest): Boolean; -var - gResHash: TMD5Digest; - fname: AnsiString; -begin - fname := findDiskWad(filename); - if length(fname) = 0 then begin result := false; exit; end; - gResHash := MD5File(fname); - Result := MD5Match(gResHash, resMd5); -end; -function CheckFileHash(const path, filename: AnsiString; const resMd5: TMD5Digest): Boolean; -var - fname: AnsiString; -begin - fname := findDiskWad(path+filename); - if length(fname) = 0 then begin result := false; exit; end; - Result := FileExists(fname) and CompareFileHash(fname, resMd5); + // 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; -function g_Res_SearchResWad (asMap: Boolean; const resMd5: TMD5Digest): AnsiString; -var - f: Integer; +function g_Res_SearchResWad (asMap: Boolean; fname: AnsiString; const resMd5: TMD5Digest): AnsiString; begin result := ''; //if not assigned(scannedDirs) then scannedDirs := THashStrInt.Create(); if (asMap) then begin - scanDir(GameDir+'/maps/downloads', true); + result := scanDir(GameDir+'/maps', ExtractFileName(fname), resMd5); end else begin - scanDir(GameDir+'/wads/downloads', true); - end; - for f := Low(knownFiles) to High(knownFiles) do - begin - if (not knownFiles[f].md5valid) then continue; - if (MD5Match(knownFiles[f].md5, resMd5)) then - begin - result := knownFiles[f].diskName; - exit; - end; + result := scanDir(GameDir+'/wads', ExtractFileName(fname), resMd5); end; - //resStream := createDiskFile(GameDir+'/wads/'+mapData.ExternalResources[i].Name); end; function g_Res_SearchSameWAD (const path, filename: AnsiString; const resMd5: TMD5Digest): AnsiString; begin - scanDir(path, false); - result := getKnownFileWithMD5(path, filename, resMd5); + result := scanDir(path, filename, resMd5); end; @@ -277,30 +159,18 @@ var resList: TStringList; f, res: Integer; strm: TStream; - mmd5: TMD5Digest; fname: AnsiString; - idx: Integer; wadname: AnsiString; + md5: TMD5Digest; begin //SetLength(mapData.ExternalResources, 0); - //result := g_Res_SearchResWad(true{asMap}, mapHash); result := ''; g_Res_ClearReplacementWads(); - g_Res_received_map_start := false; - - try - CreateDir(GameDir+'/maps/downloads'); - except - end; - - try - CreateDir(GameDir+'/wads/downloads'); - except - end; resList := TStringList.Create(); 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); g_Game_SetLoadingText(FileName + '...', 0, False); @@ -313,7 +183,7 @@ begin if (res <> 0) then exit; // find or download a map - result := g_Res_SearchResWad(true{asMap}, mapHash); + result := g_Res_SearchResWad(true{asMap}, tf.diskName, mapHash); if (length(result) = 0) then begin // download map @@ -324,14 +194,19 @@ begin result := ''; exit; end; + try + CreateDir(GameDir+'/maps/downloads'); + except + end; fname := GameDir+'/maps/downloads/'+FileName; try - strm := createDiskFile(fname); + strm := openDiskFileRW(fname); except e_WriteLog('cannot create map file `'+FileName+'`', TMsgType.Fatal); result := ''; exit; end; + tf.diskName := fname; try res := g_Net_ReceiveResourceFile(-1{map}, tf, strm); except @@ -347,22 +222,39 @@ begin result := ''; exit; end; - mmd5 := MD5File(fname); - if (not MD5Match(mmd5, mapHash)) then - begin - e_WriteLog('error downloading map file `'+FileName+'` (bad hash)', TMsgType.Fatal); - result := ''; - exit; - end; - idx := addKnownFile(fname); - if (idx < 0) then + // if it was resumed, check md5 and initiate full download if necessary + if tf.resumed then begin - e_WriteLog('error downloading map file `'+FileName+'`', TMsgType.Fatal); - result := ''; - exit; + md5 := MD5File(fname); + // sorry for pasta, i am asshole + if not MD5Match(md5, tf.hash) then + begin + e_LogWritefln('resuming failed; downloading map `%s` from scratch...', [fname]); + try + DeleteFile(fname); + strm := createDiskFile(fname); + except + 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); + strm.Free; + result := ''; + exit; + end; + strm.Free; + if (res <> 0) then + begin + e_WriteLog('error downloading map file `'+FileName+'`', TMsgType.Fatal); + result := ''; + exit; + end; + end; end; - knownFiles[idx].md5 := mmd5; - knownFiles[idx].md5valid := true; result := fname; end; @@ -371,7 +263,7 @@ begin begin res := g_Net_RequestResFileInfo(f, tf); if (res <> 0) then begin result := ''; exit; end; - wadname := g_Res_SearchResWad(false{asMap}, tf.hash); + wadname := g_Res_SearchResWad(false{asMap}, tf.diskName, tf.hash); if (length(wadname) <> 0) then begin // already here @@ -380,9 +272,14 @@ begin end else begin + try + CreateDir(GameDir+'/wads/downloads'); + except + end; fname := GameDir+'/wads/downloads/'+tf.diskName; + e_LogWritefln('downloading resource `%s` to `%s`...', [tf.diskName, fname]); try - strm := createDiskFile(fname); + strm := openDiskFileRW(fname); except e_WriteLog('cannot create resource file `'+fname+'`', TMsgType.Fatal); result := ''; @@ -403,20 +300,45 @@ begin result := ''; exit; end; - idx := addKnownFile(fname); - if (idx < 0) then + // if it was resumed, check md5 and initiate full download if necessary + if tf.resumed then begin - e_WriteLog('error downloading map file `'+FileName+'`', TMsgType.Fatal); - result := ''; - exit; + md5 := MD5File(fname); + // sorry for pasta, i am asshole + if not MD5Match(md5, tf.hash) then + begin + e_LogWritefln('resuming failed; downloading resource `%s` to `%s` from scratch...', [tf.diskName, fname]); + try + DeleteFile(fname); + strm := createDiskFile(fname); + except + e_WriteLog('cannot create resource file `'+fname+'`', TMsgType.Fatal); + result := ''; + exit; + end; + try + res := g_Net_ReceiveResourceFile(f, tf, strm); + except + e_WriteLog('error downloading map file `'+FileName+'`', TMsgType.Fatal); + strm.Free; + result := ''; + exit; + end; + strm.Free; + if (res <> 0) then + begin + e_WriteLog('error downloading map file `'+FileName+'`', TMsgType.Fatal); + result := ''; + exit; + end; + end; end; - knownFiles[idx].md5 := tf.hash; - knownFiles[idx].md5valid := true; g_Res_PutReplacementWad(tf.diskName, fname); end; end; finally resList.Free; + g_Res_received_map_start := 0; end; end;