index 961a84c99260bfac880e028fde712135fc07435d..7fc295119c4cdada4b8e7b98f8db5fb2026f6f6e 100644 (file)
@@ -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;
var
// cvars
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
err := true;
st := nil;
try
- st := createDiskFile(GameDir+'/data/maphash.db');
+ st := createDiskFile(ccdir+'/maphash.db');
knownMaps.saveTo(st);
err := false;
except
err := true;
st := nil;
try
- st := createDiskFile(GameDir+'/data/reshash.db');
+ st := createDiskFile(ccdir+'/reshash.db');
knownRes.saveTo(st);
err := false;
except
// 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;
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
//==========================================================================
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);
//==========================================================================
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);
end;
+//==========================================================================
+//
+// generateFileName
+//
+// generate new file name based on the given one and the hash
+// you can pass files with pathes here too
+//
+//==========================================================================
+function generateFileName (fname: AnsiString; const hash: TMD5Digest): AnsiString;
+var
+ mds: AnsiString;
+ path: AnsiString;
+ base: AnsiString;
+ ext: AnsiString;
+begin
+ mds := MD5Print(hash);
+ if (length(mds) > 16) then mds := Copy(mds, 1, 16);
+ mds := '_'+mds;
+ if (length(fname) = 0) then begin result := mds; exit; end;
+ path := ExtractFilePath(fname);
+ base := ExtractFileName(fname);
+ ext := getFilenameExt(base);
+ base := forceFilenameExt(base, '');
+ if (length(path) > 0) then result := IncludeTrailingPathDelimiter(path) else result := '';
+ result := result+base+mds+ext;
+end;
+
+
//==========================================================================
//
// g_Res_DownloadMapWAD
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;
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;
exit;
end;
try
- CreateDir(GameDir+'/maps/downloads');
+ destMapDir := e_GetWriteableDir(MapDownloadDirs, false); // not required
except
end;
- fname := GameDir+'/maps/downloads/'+FileName;
+ 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;
- tf.diskName := fname;
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;
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;
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;
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;
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;
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/'+tf.diskName;
+ 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);
end;
end;
finally
- resList.Free;
+ SetLength(resList, 0);
g_Res_received_map_start := 0;
end;