Skip to content

Commit

Permalink
Provide access to engine filesystem
Browse files Browse the repository at this point in the history
Resolves #86
  • Loading branch information
SamVanheer committed Nov 28, 2021
1 parent 0e54a05 commit 3f76ed3
Show file tree
Hide file tree
Showing 16 changed files with 417 additions and 1 deletion.
6 changes: 6 additions & 0 deletions cl_dll/cdll_int.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@

#include "tri.h"
#include "vgui_TeamFortressViewport.h"
#include "filesystem_utils.h"

cl_enginefunc_t gEngfuncs;
CHud gHUD;
Expand Down Expand Up @@ -145,6 +146,11 @@ int DLLEXPORT Initialize(cl_enginefunc_t* pEnginefuncs, int iVersion)
EV_HookEvents();
CL_LoadParticleMan();

if (!FileSystem_LoadFileSystem())
{
return 0;
}

// get tracker interface, if any
return 1;
}
Expand Down
2 changes: 2 additions & 0 deletions cl_dll/input.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include "Exports.h"

#include "vgui_TeamFortressViewport.h"
#include "filesystem_utils.h"


extern bool g_iAlive;
Expand Down Expand Up @@ -1029,5 +1030,6 @@ void DLLEXPORT HUD_Shutdown()
ClearEventList();
#endif

FileSystem_FreeFileSystem();
CL_UnloadParticleMan();
}
1 change: 1 addition & 0 deletions dlls/cbase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ static DLL_FUNCTIONS gFunctionTable =
NEW_DLL_FUNCTIONS gNewDLLFunctions =
{
OnFreeEntPrivateData, //pfnOnFreeEntPrivateData
GameDLLShutdown,
};

static void SetObjectCollisionBox(entvars_t* pev);
Expand Down
13 changes: 13 additions & 0 deletions dlls/game.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include "eiface.h"
#include "util.h"
#include "game.h"
#include "filesystem_utils.h"

cvar_t displaysoundlist = {"displaysoundlist", "0"};

Expand Down Expand Up @@ -467,6 +468,13 @@ void GameDLLInit()
g_footsteps = CVAR_GET_POINTER("mp_footsteps");
g_psv_cheats = CVAR_GET_POINTER("sv_cheats");

if (!FileSystem_LoadFileSystem())
{
//Shut the game down as soon as possible.
SERVER_COMMAND("quit\n");
return;
}

CVAR_REGISTER(&displaysoundlist);
CVAR_REGISTER(&allow_spectators);

Expand Down Expand Up @@ -899,3 +907,8 @@ void GameDLLInit()

SERVER_COMMAND("exec skill.cfg\n");
}

void GameDLLShutdown()
{
FileSystem_FreeFileSystem();
}
1 change: 1 addition & 0 deletions dlls/game.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#pragma once

extern void GameDLLInit( void );
void GameDLLShutdown();


extern cvar_t displaysoundlist;
Expand Down
149 changes: 149 additions & 0 deletions game_shared/filesystem_utils.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
/***
*
* Copyright (c) 1996-2002, Valve LLC. All rights reserved.
*
* This product contains software technology licensed from Id
* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc.
* All Rights Reserved.
*
* Use, distribution, and modification of this source code and/or resulting
* object code is restricted to non-commercial enhancements to products from
* Valve LLC. All other use, distribution, or modification is prohibited
* without written permission from Valve LLC.
*
****/

#include <cassert>
#include <limits>

#include "Platform.h"

#include "extdll.h"
#include "util.h"

#include "interface.h"

#include "filesystem_utils.h"

static CSysModule* g_pFileSystemModule = nullptr;

bool FileSystem_LoadFileSystem()
{
if (nullptr != g_pFileSystem)
{
//Already loaded.
return true;
}

// Determine which filesystem to use.
#if defined ( _WIN32 )
const char* szFsModule = "filesystem_stdio.dll";
#elif defined(OSX)
const char* szFsModule = "filesystem_stdio.dylib";
#elif defined(LINUX)
const char* szFsModule = "filesystem_stdio.so";
#else
#error
#endif

// Get filesystem interface.
// The library is located next to the game exe, so there is no need to resolve the path first.
g_pFileSystemModule = Sys_LoadModule(szFsModule);

assert(nullptr != g_pFileSystemModule);

if (nullptr == g_pFileSystemModule)
{
return false;
}

CreateInterfaceFn fileSystemFactory = Sys_GetFactory(g_pFileSystemModule);

if (nullptr == fileSystemFactory)
{
return false;
}

g_pFileSystem = reinterpret_cast<IFileSystem*>(fileSystemFactory(FILESYSTEM_INTERFACE_VERSION, nullptr));

assert(nullptr != g_pFileSystem);

if (nullptr == g_pFileSystem)
{
return false;
}

return true;
}

void FileSystem_FreeFileSystem()
{
if (nullptr != g_pFileSystem)
{
g_pFileSystem = nullptr;
}

if (nullptr != g_pFileSystemModule)
{
Sys_UnloadModule(g_pFileSystemModule);
g_pFileSystemModule = nullptr;
}
}

std::vector<std::byte> FileSystem_LoadFileIntoBuffer(const char* fileName, const char* pathID)
{
assert(nullptr != g_pFileSystem);

if (nullptr == fileName)
{
return {};
}

if (FSFile file{fileName, "rb", pathID}; file)
{
const auto size = file.Size();

//Null terminate it in case it's actually text.
std::vector<std::byte> buffer;

buffer.resize(size + 1);

file.Read(buffer.data(), size);

buffer[size] = std::byte{'\0'};

return buffer;
}

ALERT(at_console, "FileSystem_LoadFileIntoBuffer: couldn't open file \"%s\" for reading\n", fileName);
return {};
}

bool FileSystem_WriteTextToFile(const char* fileName, const char* text, const char* pathID)
{
assert(nullptr != g_pFileSystem);

if (nullptr == fileName || nullptr == text)
{
return false;
}

const std::size_t length = std::strlen(text);

if (length > static_cast<std::size_t>(std::numeric_limits<int>::max()))
{
ALERT(at_console, "FileSystem_WriteTextToFile: text too long\n");
return false;
}

if (FSFile file{fileName, "w", pathID}; file)
{
file.Write(text, length);

return true;
}

ALERT(at_console, "FileSystem_WriteTextToFile: couldn't open file \"%s\" for writing\n", fileName);

return false;
}
164 changes: 164 additions & 0 deletions game_shared/filesystem_utils.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
/***
*
* Copyright (c) 1996-2002, Valve LLC. All rights reserved.
*
* This product contains software technology licensed from Id
* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc.
* All Rights Reserved.
*
* Use, distribution, and modification of this source code and/or resulting
* object code is restricted to non-commercial enhancements to products from
* Valve LLC. All other use, distribution, or modification is prohibited
* without written permission from Valve LLC.
*
****/

#pragma once

/**
* @file
*
* Functions, types and globals to load and use the GoldSource engine filesystem interface to read and write files.
* See the VDC for information on which search paths exist to be used as path IDs:
* https://developer.valvesoftware.com/wiki/GoldSource_SteamPipe_Directories
*/

#include <cstddef>
#include <vector>

#include "Platform.h"
#include "FileSystem.h"

inline IFileSystem* g_pFileSystem = nullptr;

bool FileSystem_LoadFileSystem();
void FileSystem_FreeFileSystem();

/**
* @brief Loads a file from disk into a buffer.
*
* @details If the returned buffer contains text data it is safe to cast the data pointer to char*:
* @code{.cpp}
* auto text = reinterpret_cast<char*>(buffer.data());
* @endcode
*
* @param fileName Name of the file to load.
* @param pathID If not null, only looks for the file in this search path.
* @return If the file was successfully loaded, the contents of the buffer, with a zero byte (null terminator) appended to it in case it's a text file.
* If the file could not be loaded an empty buffer is returned.
*/
std::vector<std::byte> FileSystem_LoadFileIntoBuffer(const char* fileName, const char* pathID = nullptr);

/**
* @brief Writes a text file to disk.
* @param fileName Name of the file to write to.
* @param text Null-terminated text to write. The null terminator is not written to disk.
* @param pathID If not null, writes to a writable location assigned to the given search path.
* Otherwise the first writable location will be used (in practice this will be the mod directory).
* If no writable location exists no file will be written to.
* @return True if the file was written, false if an error occurred.
*/
bool FileSystem_WriteTextToFile(const char* fileName, const char* text, const char* pathID = nullptr);

/**
* @brief Helper class to automatically close the file handle associated with a file.
*/
class FSFile
{
public:
FSFile() noexcept = default;
FSFile(const char* fileName, const char* options, const char* pathID = nullptr);

FSFile(FSFile&& other) noexcept
: _handle(other._handle)
{
other._handle = FILESYSTEM_INVALID_HANDLE;
}

FSFile& operator=(FSFile&& other) noexcept
{
if (this != &other)
{
Close();
_handle = other._handle;
other._handle = FILESYSTEM_INVALID_HANDLE;
}

return *this;
}

FSFile(const FSFile&) = delete;
FSFile& operator=(const FSFile&) = delete;

~FSFile();

constexpr bool IsOpen() const { return _handle != FILESYSTEM_INVALID_HANDLE; }

std::size_t Size() const { return static_cast<std::size_t>(g_pFileSystem->Size(_handle)); }

bool Open(const char* filename, const char* options, const char* pathID = nullptr);
void Close();

void Seek(int pos, FileSystemSeek_t seekType);

int Read(void* dest, int size);

int Write(const void* input, int size);

template<typename... Args>
int Printf(const char* format, Args&&... args)
{
return g_pFileSystem->FPrintf(_handle, format, std::forward<Args>(args)...);
}

constexpr operator bool() const { return IsOpen(); }

private:
FileHandle_t _handle = FILESYSTEM_INVALID_HANDLE;
};

inline FSFile::FSFile(const char* filename, const char* options, const char* pathID)
{
Open(filename, options, pathID);
}

inline FSFile::~FSFile()
{
Close();
}

inline bool FSFile::Open(const char* filename, const char* options, const char* pathID)
{
Close();

_handle = g_pFileSystem->Open(filename, options, pathID);

return IsOpen();
}

inline void FSFile::Close()
{
if (IsOpen())
{
g_pFileSystem->Close(_handle);
_handle = FILESYSTEM_INVALID_HANDLE;
}
}

inline void FSFile::Seek(int pos, FileSystemSeek_t seekType)
{
if (IsOpen())
{
g_pFileSystem->Seek(_handle, pos, seekType);
}
}

inline int FSFile::Read(void* dest, int size)
{
return g_pFileSystem->Read(dest, size, _handle);
}

inline int FSFile::Write(const void* input, int size)
{
return g_pFileSystem->Write(input, size, _handle);
}
Loading

0 comments on commit 3f76ed3

Please sign in to comment.