Skip to content

Commit

Permalink
Refactor: Relocated game resource location into the Games collection
Browse files Browse the repository at this point in the history
Plus various minor refactorings to the libdeng1 file system.
  • Loading branch information
danij-deng committed Oct 6, 2012
1 parent c14ae8e commit 965d0c9
Show file tree
Hide file tree
Showing 5 changed files with 297 additions and 219 deletions.
5 changes: 5 additions & 0 deletions doomsday/engine/portable/include/dd_games.h
Expand Up @@ -79,6 +79,11 @@ boolean Games_IsNullObject(Game const* game);
/// @return The first playable game in the collection according to registration order.
Game* Games_FirstPlayable(void);

/**
* Try to locate all startup resources for all registered games.
*/
void Games_LocateAllResources(void);

/**
* Print a game mode banner with rulers.
*/
Expand Down
51 changes: 23 additions & 28 deletions doomsday/engine/portable/include/fs_main.h
Expand Up @@ -86,14 +86,6 @@ int F_Reset(void);
*/
void F_ResetFileIds(void);

/**
* Calculate an identifier for the file based on its full path name.
* The identifier is the MD5 hash of the path.
*/
void F_GenerateFileId(char const* str, byte identifier[16]);

void F_PrintFileId(byte identifier[16]);

/**
* Maintains a list of identifiers already seen.
*
Expand Down Expand Up @@ -147,26 +139,6 @@ boolean F_RemoveFiles(char const* const* paths, int num, boolean permitRequired)
*/
int F_Access(char const* path);

/**
* Opens the given file (will be translated) for reading.
*
* @post If @a allowDuplicate = @c false a new file ID for this will have been
* added to the list of known file identifiers if this file hasn't yet been
* opened. It is the responsibility of the caller to release this identifier when done.
*
* @param path Possibly relative or mapped path to the resource being opened.
* @param mode 't' = text mode (with real files, lumps are always binary)
* 'b' = binary
* 'f' = must be a real file in the local file system
* @param baseOffset Offset from the start of the file in bytes to begin.
* @param allowDuplicate @c false = open only if not already opened.
*
* @return Opened file reference/handle else @c NULL.
*/
DFile* F_Open3(char const* path, char const* mode, size_t baseOffset, boolean allowDuplicate);
DFile* F_Open2(char const* path, char const* mode, size_t baseOffset/*, allowDuplicate = true */);
DFile* F_Open(char const* path, char const* mode/*, baseOffset = 0 */);

/**
* Try to locate the specified lump for reading.
*
Expand Down Expand Up @@ -253,6 +225,25 @@ namespace de {
class FS
{
public:
/**
* Opens the given file (will be translated) for reading.
*
* @post If @a allowDuplicate = @c false a new file ID for this will have been
* added to the list of known file identifiers if this file hasn't yet been
* opened. It is the responsibility of the caller to release this identifier when done.
*
* @param path Possibly relative or mapped path to the resource being opened.
* @param mode 't' = text mode (with real files, lumps are always binary)
* 'b' = binary
* 'f' = must be a real file in the local file system
* @param baseOffset Offset from the start of the file in bytes to begin.
* @param allowDuplicate @c false = open only if not already opened.
*
* @return Opened file reference/handle else @c NULL.
*/
static DFile* openFile(char const* path, char const* mode, size_t baseOffset = 0,
bool allowDuplicate = true);

/**
* Find a lump in the Zip LumpDirectory.
*
Expand Down Expand Up @@ -294,6 +285,10 @@ extern "C" {
* C wrapper API:
*/

DFile* F_Open3(char const* path, char const* mode, size_t baseOffset, boolean allowDuplicate);
DFile* F_Open2(char const* path, char const* mode, size_t baseOffset/*, allowDuplicate = true */);
DFile* F_Open(char const* path, char const* mode/*, baseOffset = 0 */);

boolean F_IsValidLumpNum(lumpnum_t absoluteLumpNum);

boolean F_LumpIsCustom(lumpnum_t absoluteLumpNum);
Expand Down
155 changes: 154 additions & 1 deletion doomsday/engine/portable/src/dd_games.cpp
Expand Up @@ -22,10 +22,14 @@

#include "de_base.h"
#include "de_console.h"
#include "de_filesys.h"
#include "dd_games.h"

#include "abstractresource.h"
#include "fs_util.h"

using de::FS;
using de::DFile;
using de::ZipFile;

extern "C" {

Expand Down Expand Up @@ -155,6 +159,155 @@ boolean Games_IsNullObject(Game const* game)
return game == nullGame;
}

/// @return @c true, iff the resource appears to be what we think it is.
static bool recognizeWAD(char const* filePath, void* parameters)
{
lumpnum_t auxLumpBase = F_OpenAuxiliary3(filePath, 0, true);
bool result = false;

if(auxLumpBase >= 0)
{
// Ensure all identity lumps are present.
if(parameters)
{
ddstring_t const* const* lumpNames = (ddstring_t const* const*) parameters;
result = true;
for(; result && *lumpNames; lumpNames++)
{
lumpnum_t lumpNum = F_CheckLumpNumForName2(Str_Text(*lumpNames), true);
if(lumpNum < 0)
{
result = false;
}
}
}
else
{
// Matched.
result = true;
}

F_CloseAuxiliary();
}
return result;
}

/// @return @c true, iff the resource appears to be what we think it is.
static bool recognizeZIP(char const* filePath, void* parameters)
{
DENG_UNUSED(parameters);

DFile* dfile = FS::openFile(filePath, "bf");
bool result = false;
if(dfile)
{
result = ZipFile::recognise(*dfile);
/// @todo Check files. We should implement an auxiliary zip lumpdirectory...
FS::closeFile(dfile);
}
return result;
}

/// @todo This logic should be encapsulated by AbstractResource.
static bool validateResource(AbstractResource* rec)
{
DENG_ASSERT(rec);
bool validated = false;

if(AbstractResource_ResourceClass(rec) == RC_PACKAGE)
{
Uri* const* uriList = AbstractResource_SearchPaths(rec);
Uri* const* ptr;
int idx = 0;
for(ptr = uriList; *ptr; ptr++, idx++)
{
Str const* path = AbstractResource_ResolvedPathWithIndex(rec, idx, true/*locate resources*/);
if(!path) continue;

if(recognizeWAD(Str_Text(path), (void*)AbstractResource_IdentityKeys(rec)))
{
validated = true;
break;
}
else if(recognizeZIP(Str_Text(path), (void*)AbstractResource_IdentityKeys(rec)))
{
validated = true;
break;
}
}
}
else
{
// Other resource types are not validated.
validated = true;
}

AbstractResource_MarkAsFound(rec, validated);
return validated;
}

static void locateGameStartupResources(Game* game)
{
if(!game) return;

Game* oldGame = theGame;
if(theGame != game)
{
/// @attention Kludge: Temporarily switch Game.
theGame = game;
// Re-init the resource locator using the search paths of this Game.
F_ResetAllResourceNamespaces();
}

for(uint rclass = RESOURCECLASS_FIRST; rclass < RESOURCECLASS_COUNT; ++rclass)
{
AbstractResource* const* records = Game_Resources(game, resourceclass_t(rclass), 0);
if(!records) continue;

for(AbstractResource* const* i = records; *i; i++)
{
AbstractResource* rec = *i;

// We are only interested in startup resources at this time.
if(!(AbstractResource_ResourceFlags(rec) & RF_STARTUP)) continue;

validateResource(rec);
}
}

if(theGame != oldGame)
{
// Kludge end - Restore the old Game.
theGame = oldGame;
// Re-init the resource locator using the search paths of this Game.
F_ResetAllResourceNamespaces();
}
}

static int locateAllResourcesWorker(void* parameters)
{
DENG_UNUSED(parameters);
for(int i = 0; i < gamesCount; ++i)
{
Game* game = games[i];

VERBOSE( Con_Printf("Locating resources for \"%s\"...\n", Str_Text(Game_Title(game))) )

locateGameStartupResources(game);
Con_SetProgress((i+1) * 200/Games_Count() -1);

VERBOSE( Games_Print(game, PGF_LIST_STARTUP_RESOURCES|PGF_STATUS) )
}
BusyMode_WorkerEnd();
return 0;
}

void Games_LocateAllResources(void)
{
BusyMode_RunNewTaskWithName(BUSYF_STARTUP | BUSYF_PROGRESS_BAR | (verbose? BUSYF_CONSOLE_OUTPUT : 0),
locateAllResourcesWorker, 0, "Locating game resources...");
}

/**
* @todo This has been moved here so that strings like the game title and author can
* be overridden (e.g., via DEHACKED). Make it so!
Expand Down

0 comments on commit 965d0c9

Please sign in to comment.