From: DeaDDooMER Date: Sun, 20 Oct 2019 20:01:40 +0000 (+0300) Subject: allow resources in non current directory (warning: res downloader are broken) X-Git-Url: http://deadsoftware.ru/gitweb?p=d2df-sdl.git;a=commitdiff_plain;h=414f2873efa0cce84499f64774db7000e6268971 allow resources in non current directory (warning: res downloader are broken) --- diff --git a/src/engine/e_res.pas b/src/engine/e_res.pas new file mode 100644 index 0000000..db32879 --- /dev/null +++ b/src/engine/e_res.pas @@ -0,0 +1,259 @@ +(* Copyright (C) Doom 2D: Forever Developers + * + * 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, version 3 of the License ONLY. + * + * 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 . + *) +{$I ../shared/a_modes.inc} +unit e_res; + +interface + + uses SysUtils, Utils, Classes; + + var + debug_e_res: Boolean; + + {-------------------------------------------} + {--- insert separator beetwin a and b ---} + {--- result are correct if (a or b) = '' ---} + {--- - - - - - - - - - - - - - - - - - - ---} + function e_CatPath (a, b: AnsiString): AnsiString; + + {--- remove last entry from path ---} + function e_UpperDir (path: AnsiString): AnsiString; + + {--- not absolute and have no relative dirs ---} + function e_IsValidResourceName (name: AnsiString): Boolean; + + {-----------------------------------------------------------------------} + {--- try to open/create file in one dir from `dirs` in reverse order ---} + {--- e_OpenResourceRW tries to create if not exists ---} + {--- create dirs if not exists ---} + {--- result <> nil, throws exceptions on errors ---} + {--- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ---} + function e_CreateResource (dirs: SSArray; name: AnsiString): TStream; + function e_OpenResourceRO (dirs: SSArray; name: AnsiString): TStream; + function e_OpenResourceRW (dirs: SSArray; name: AnsiString): TStream; + + {--- same as shared/utils ---} + function e_FindResource (dirs: SSArray; var name: AnsiString; nameIsDir: Boolean = false): Boolean; + function e_FindWad (dirs: SSArray; name: AnsiString): AnsiString; + + {--- append dirs to 'path.wad:\file'. if disk is void, append defWad ---} + function e_GetResourcePath (dirs: SSArray; path: AnsiString; defWad: AnsiString): AnsiString; + + {--- same as SysUtils.FinFirst ---} + function e_FindFirst (dirs: SSArray; name: AnsiString; attr: LongInt; out Rslt: TRawbyteSearchRec): LongInt; + + {--- try to create directory from list, throws if no one directory created ---} + function e_GetDir (dirs: SSArray): AnsiString; + +implementation + + uses WadReader, e_log; + + type + SpawnProc = function (pathname: AnsiString): Tstream; + + function e_UpperDir (path: AnsiString): AnsiString; + var i: Integer; + begin + i := High(path); + while (i >= 1) and (path[i] <> '/') and (path[i] <> '\') do Dec(i); + result := Copy(path, 1, i) + end; + + function HasRelativeDirs (name: AnsiString): Boolean; + var i: Integer; ch: Char; + begin + i := 1; + result := false; + while (result = false) and (name[i] <> #0) do + begin + ch := name[i]; + if (ch = '/') or (ch = '\') then + begin + Inc(i); + if name[i] = '.' then + begin + Inc(i); + if name[i] = '.' then + begin + Inc(i); + ch := name[i]; + result := (ch = #0) or (ch = '/') or (ch = '\') + end + end + end + else + begin + Inc(i) + end + end + end; + + function HasAbsoluteDirs (name: AnsiString): Boolean; + begin + result := (name = '') or (name[1] = '/') or (name[1] = '\') + end; + + function e_IsValidResourceName (name: AnsiString): Boolean; + begin + result := (HasAbsoluteDirs(name) = false) and (HasRelativeDirs(name) = false) + end; + + function SpawnStream (dirs: SSArray; name: AnsiString; p: SpawnProc; createNewDir: Boolean): TStream; + var i: Integer; + begin + result := nil; + assert(dirs <> nil); + assert(e_IsValidResourceName(name)); + i := High(dirs); + while (i >= 0) and (result = nil) do + begin + try + if debug_e_res then + e_LogWritefln(' %s', [dirs[i]]); + if (createNewDir = false) or (ForceDirectories(dirs[i]) = true) then + result := p(e_CatPath(dirs[i], name)) + finally + Dec(i) + end + end + end; + + function e_CreateResource (dirs: SSArray; name: AnsiString): TStream; + begin + if debug_e_res then + e_LogWritefln('e_CreateResource %s', [name]); + result := SpawnStream(dirs, name, @createDiskFile, true); + if result = nil then + raise Exception.Create('can''t create resource "' + name + '"'); + end; + + function e_OpenResourceRO (dirs: SSArray; name: AnsiString): TStream; + begin + if debug_e_res then + e_LogWritefln('e_OpenResourceRO %s', [name]); + result := SpawnStream(dirs, name, @openDiskFileRO, false); + if result = nil then + raise EFileNotFoundException.Create('can''t open resource "' + name + '"') + end; + + function e_OpenResourceRW (dirs: SSArray; name: AnsiString): TStream; + begin + if debug_e_res then + e_LogWritefln('e_OpenResourceRW %s', [name]); + result := SpawnStream(dirs, name, @openDiskFileRW, true); + if result = nil then + raise Exception.Create('can''t create resource "' + name + '"') + end; + + function e_CatPath (a, b: AnsiString): AnsiString; + begin + if a = '' then + result := b + else if b = '' then + result := a + else + result := a + '/' + b + end; + + function e_FindResource (dirs: SSArray; var name: AnsiString; nameIsDir: Boolean = false): Boolean; + var i: Integer; dir: AnsiString; + begin + if debug_e_res then + e_LogWritefln('e_FindResource %s (%s)', [name, nameIsDir]); + result := false; + assert(dirs <> nil); + assert(e_IsValidResourceName(name)); + i := High(dirs); dir := name; + while (i >= 0) and (result = false) do + begin + dir := e_CatPath(dirs[i], name); + result := findFileCI(dir, nameIsDir); + if debug_e_res then + e_LogWritefln(' %s -> %s', [dir, result]); + Dec(i) + end; + if result = true then + name := dir; + if debug_e_res then + e_LogWritefln(' result = %s (%s)', [name, result]); + end; + + function e_FindWad (dirs: SSArray; name: AnsiString): AnsiString; + var i: Integer; + begin + if debug_e_res then + e_LogWritefln('e_FindWad "%s"', [name]); + result := ''; + assert(dirs <> nil); + assert(e_IsValidResourceName(name)); + i := High(dirs); + while (i >= 0) and (result = '') do + begin + result := findDiskWad(dirs[i] + DirectorySeparator + name); + if debug_e_res then + e_LogWritefln(' %s -> %s', [dirs[i] + DirectorySeparator + name, result]); + Dec(i) + end + end; + + function e_GetResourcePath (dirs: SSArray; path: AnsiString; defWad: AnsiString): AnsiString; + var diskName, fileName: AnsiString; + begin + if debug_e_res then + e_LogWritefln('e_GetResourcePath0 %s (%s)', [path, defWad]); + assert(dirs <> nil); + assert(path <> ''); + assert(defWad <> ''); + diskName := g_ExtractWadName(path); + fileName := g_ExtractFilePathName(path); + if diskName = '' then diskName := defWad else diskName := e_FindWad(dirs, diskName); + assert(diskName <> '', 'oh fuck, wad "' + diskName + '" not founded'); + result := diskName + ':\' + fileName; + if debug_e_res then + e_LogWritefln(' this>>> %s', [result]); + end; + + function e_FindFirst (dirs: SSArray; name: AnsiString; attr: LongInt; out Rslt: TRawbyteSearchRec): LongInt; + var i: Integer; dir: AnsiString; + begin + if debug_e_res then + e_LogWritefln('e_FindFirst %s', [name]); + assert(dirs <> nil); + assert(e_IsValidResourceName(name)); + i := High(dirs); result := -1; + while (i >= 0) and (result <> 0) do + begin + dir := dirs[i] + DirectorySeparator + name; + result := FindFirst(dir, attr, Rslt); + if debug_e_res then + e_LogWritefln(' %s: %s -- %s', [i, dir, result]); + Dec(i); + end + end; + + function e_GetDir (dirs: SSArray): AnsiString; + var i: Integer; + begin + result := ''; + i := High(dirs); + while (i >= 0) and (ForceDirectories(dirs[i]) = false) do Dec(i); + if i >= 0 then + result := dirs[i] + else + raise Exception.Create('unable to create directory') + end; + +end. diff --git a/src/game/Doom2DF.lpr b/src/game/Doom2DF.lpr index 69cf034..561dc36 100644 --- a/src/game/Doom2DF.lpr +++ b/src/game/Doom2DF.lpr @@ -101,6 +101,7 @@ uses e_sound in '../engine/e_sound.pas', e_texture in '../engine/e_texture.pas', e_msg in '../engine/e_msg.pas', + e_res in '../engine/e_res.pas', utils in '../shared/utils.pas', xstreams in '../shared/xstreams.pas', sfs in '../sfs/sfs.pas', @@ -242,15 +243,6 @@ begin Inc(f) end; - if LogFileName = '' then - begin -{$IFDEF HEADLESS} - LogFileName := 'Doom2DF_H.log'; -{$ELSE} - LogFileName := 'Doom2DF.log'; -{$ENDIF} - end; - if noct then begin Main() diff --git a/src/game/g_console.pas b/src/game/g_console.pas index 4141f27..6b8ddc8 100644 --- a/src/game/g_console.pas +++ b/src/game/g_console.pas @@ -86,9 +86,13 @@ implementation uses g_textures, g_main, e_graphics, e_input, g_game, - SysUtils, g_basic, g_options, Math, g_touch, + SysUtils, g_basic, g_options, Math, g_touch, e_res, g_menu, g_gui, g_language, g_net, g_netmsg, e_log, conbuf; +const + configScript = 'dfconfig.cfg'; + autoexecScript = 'autoexec.cfg'; + configComment = 'generated by doom2d, do not modify'; type PCommand = ^TCommand; @@ -580,7 +584,7 @@ begin begin // exec if Length(p) = 2 then - g_Console_ReadConfig(GameDir + '/' + p[1]) + g_Console_ReadConfig(p[1]) else g_Console_Add('exec