mirror of
https://github.com/rwengine/openrw.git
synced 2024-11-22 02:12:45 +01:00
commit
83ee9ef568
@ -2,7 +2,7 @@
|
||||
|
||||
#include <cstring>
|
||||
#include <fstream>
|
||||
#include <rw/defines.hpp>
|
||||
#include <rw/debug.hpp>
|
||||
|
||||
namespace RW {
|
||||
|
||||
|
@ -4,7 +4,7 @@
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
|
||||
#include <rw/defines.hpp>
|
||||
#include <rw/debug.hpp>
|
||||
|
||||
#include "BinaryStream.hpp"
|
||||
|
||||
|
@ -7,7 +7,7 @@
|
||||
#include "ai/AIGraphNode.hpp"
|
||||
#include "data/PathData.hpp"
|
||||
|
||||
#include <rw/defines.hpp>
|
||||
#include <rw/debug.hpp>
|
||||
#include <rw/types.hpp>
|
||||
|
||||
AIGraph::~AIGraph() {
|
||||
|
@ -11,7 +11,7 @@
|
||||
|
||||
#include <LinearMath/btScalar.h>
|
||||
|
||||
#include <rw/defines.hpp>
|
||||
#include <rw/debug.hpp>
|
||||
|
||||
#include "data/WeaponData.hpp"
|
||||
#include "engine/Animator.hpp"
|
||||
|
@ -8,7 +8,7 @@ extern "C" {
|
||||
#include <libavutil/avutil.h>
|
||||
}
|
||||
//ab
|
||||
#include <rw/defines.hpp>
|
||||
#include <rw/debug.hpp>
|
||||
|
||||
// Rename some functions for older libavcodec/ffmpeg versions (e.g. Ubuntu Trusty)
|
||||
#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(55,28,1)
|
||||
@ -64,7 +64,7 @@ bool SoundManager::initializeAVCodec() {
|
||||
return true;
|
||||
}
|
||||
|
||||
void SoundManager::SoundSource::loadFromFile(const std::string& filename) {
|
||||
void SoundManager::SoundSource::loadFromFile(const rwfs::path& filePath) {
|
||||
// Allocate audio frame
|
||||
AVFrame* frame = av_frame_alloc();
|
||||
if (!frame) {
|
||||
@ -74,9 +74,9 @@ void SoundManager::SoundSource::loadFromFile(const std::string& filename) {
|
||||
|
||||
// Allocate formatting context
|
||||
AVFormatContext* formatContext = nullptr;
|
||||
if (avformat_open_input(&formatContext, filename.c_str(), nullptr, nullptr) != 0) {
|
||||
if (avformat_open_input(&formatContext, filePath.string().c_str(), nullptr, nullptr) != 0) {
|
||||
av_frame_free(&frame);
|
||||
RW_ERROR("Error opening audio file (" << filename << ")");
|
||||
RW_ERROR("Error opening audio file (" << filePath << ")");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -93,7 +93,7 @@ void SoundManager::SoundSource::loadFromFile(const std::string& filename) {
|
||||
if (streamIndex < 0) {
|
||||
av_frame_free(&frame);
|
||||
avformat_close_input(&formatContext);
|
||||
RW_ERROR("Could not find any audio stream in the file " << filename);
|
||||
RW_ERROR("Could not find any audio stream in the file " << filePath);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -196,7 +196,7 @@ bool SoundManager::SoundBuffer::bufferData(SoundSource& soundSource) {
|
||||
}
|
||||
|
||||
bool SoundManager::loadSound(const std::string& name,
|
||||
const std::string& fileName) {
|
||||
const rwfs::path& path) {
|
||||
Sound* sound = nullptr;
|
||||
auto sound_iter = sounds.find(name);
|
||||
|
||||
@ -208,7 +208,7 @@ bool SoundManager::loadSound(const std::string& name,
|
||||
std::forward_as_tuple());
|
||||
sound = &emplaced.first->second;
|
||||
|
||||
sound->source.loadFromFile(fileName);
|
||||
sound->source.loadFromFile(path);
|
||||
sound->isLoaded = sound->buffer.bufferData(sound->source);
|
||||
}
|
||||
|
||||
@ -280,8 +280,8 @@ bool SoundManager::playBackground(const std::string& fileName) {
|
||||
}
|
||||
|
||||
bool SoundManager::loadMusic(const std::string& name,
|
||||
const std::string& fileName) {
|
||||
return loadSound(name, fileName);
|
||||
const rwfs::path& path) {
|
||||
return loadSound(name, path);
|
||||
}
|
||||
|
||||
void SoundManager::playMusic(const std::string& name) {
|
||||
|
@ -7,6 +7,8 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <rw/filesystem.hpp>
|
||||
|
||||
#include <al.h>
|
||||
#include <alc.h>
|
||||
|
||||
@ -15,7 +17,7 @@ public:
|
||||
SoundManager();
|
||||
~SoundManager();
|
||||
|
||||
bool loadSound(const std::string& name, const std::string& fileName);
|
||||
bool loadSound(const std::string& name, const rwfs::path& path);
|
||||
bool isLoaded(const std::string& name);
|
||||
void playSound(const std::string& name);
|
||||
void pauseSound(const std::string& name);
|
||||
@ -26,9 +28,9 @@ public:
|
||||
void pauseAllSounds();
|
||||
void resumeAllSounds();
|
||||
|
||||
bool playBackground(const std::string& fileName);
|
||||
bool playBackground(const std::string& name);
|
||||
|
||||
bool loadMusic(const std::string& name, const std::string& fileName);
|
||||
bool loadMusic(const std::string& name, const rwfs::path& path);
|
||||
void playMusic(const std::string& name);
|
||||
void stopMusic(const std::string& name);
|
||||
|
||||
@ -40,7 +42,7 @@ private:
|
||||
friend class SoundBuffer;
|
||||
|
||||
public:
|
||||
void loadFromFile(const std::string& filename);
|
||||
void loadFromFile(const rwfs::path& filePath);
|
||||
|
||||
private:
|
||||
std::vector<int16_t> data;
|
||||
|
@ -9,7 +9,7 @@
|
||||
#include <vector>
|
||||
#define time_unit std::chrono::microseconds
|
||||
|
||||
#include <rw/defines.hpp>
|
||||
#include <rw/debug.hpp>
|
||||
|
||||
namespace perf {
|
||||
|
||||
|
@ -3,7 +3,7 @@
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
|
||||
#include <rw/defines.hpp>
|
||||
#include <rw/debug.hpp>
|
||||
#include <rw/forward.hpp>
|
||||
|
||||
// The default animations for every cycle
|
||||
|
@ -4,7 +4,7 @@
|
||||
#include <cstddef>
|
||||
#include <fstream>
|
||||
|
||||
#include <rw/defines.hpp>
|
||||
#include <rw/debug.hpp>
|
||||
|
||||
#include "engine/GameWorld.hpp"
|
||||
#include "objects/GameObject.hpp"
|
||||
|
@ -11,7 +11,7 @@
|
||||
#include <vector>
|
||||
|
||||
#include <data/Clump.hpp>
|
||||
#include <rw/defines.hpp>
|
||||
#include <rw/debug.hpp>
|
||||
#include <rw/forward.hpp>
|
||||
|
||||
#include <data/CollisionModel.hpp>
|
||||
|
@ -3,7 +3,7 @@
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
#include <rw/defines.hpp>
|
||||
#include <rw/debug.hpp>
|
||||
#include <rw/forward.hpp>
|
||||
|
||||
struct AnimationBone;
|
||||
|
@ -13,7 +13,7 @@
|
||||
#include <boost/algorithm/string/predicate.hpp>
|
||||
|
||||
#include <data/Clump.hpp>
|
||||
#include <rw/defines.hpp>
|
||||
#include <rw/debug.hpp>
|
||||
#include <rw/types.hpp>
|
||||
|
||||
#include "core/Logger.hpp"
|
||||
@ -39,7 +39,6 @@ GameData::GameData(Logger* log, const rwfs::path& path)
|
||||
}
|
||||
|
||||
void GameData::load() {
|
||||
index.indexGameDirectory(datpath);
|
||||
index.indexTree(datpath);
|
||||
|
||||
loadIMG("models/gta3.img");
|
||||
@ -189,8 +188,7 @@ void GameData::loadCOL(const size_t zone, const std::string& name) {
|
||||
}
|
||||
|
||||
void GameData::loadIMG(const std::string& name) {
|
||||
auto syspath = index.findFilePath(name).string();
|
||||
index.indexArchive(syspath);
|
||||
index.indexArchive(name);
|
||||
}
|
||||
|
||||
void GameData::loadIPL(const std::string& path) {
|
||||
@ -288,7 +286,7 @@ void GameData::loadHandling(const std::string& path) {
|
||||
}
|
||||
|
||||
SCMFile* GameData::loadSCM(const std::string& path) {
|
||||
auto scm_h = index.openFilePath(path);
|
||||
auto scm_h = index.openFileRaw(path);
|
||||
SCMFile* scm = new SCMFile;
|
||||
scm->loadFile(scm_h->data, scm_h->length);
|
||||
scm_h.reset();
|
||||
@ -296,7 +294,7 @@ SCMFile* GameData::loadSCM(const std::string& path) {
|
||||
}
|
||||
|
||||
void GameData::loadGXT(const std::string& name) {
|
||||
auto file = index.openFilePath(name);
|
||||
auto file = index.openFileRaw(name);
|
||||
|
||||
LoaderGXT loader;
|
||||
|
||||
@ -417,7 +415,7 @@ ClumpPtr GameData::loadClump(const std::string& name, const std::string& texture
|
||||
}
|
||||
|
||||
void GameData::loadModelFile(const std::string& name) {
|
||||
auto file = index.openFilePath(name);
|
||||
auto file = index.openFileRaw(name);
|
||||
if (!file) {
|
||||
logger->log("Data", Logger::Error, "Failed to load model file " + name);
|
||||
return;
|
||||
|
@ -14,7 +14,7 @@
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
#include <platform/FileIndex.hpp>
|
||||
#include <rw/defines.hpp>
|
||||
#include <rw/debug.hpp>
|
||||
#include <rw/forward.hpp>
|
||||
|
||||
#include <data/AnimGroup.hpp>
|
||||
|
@ -691,11 +691,7 @@ void GameWorld::PhysicsTickCallback(btDynamicsWorld* physWorld,
|
||||
}
|
||||
|
||||
void GameWorld::loadCutscene(const std::string& name) {
|
||||
std::string lowerName(name);
|
||||
std::transform(lowerName.begin(), lowerName.end(), lowerName.begin(),
|
||||
::tolower);
|
||||
|
||||
auto datfile = data->index.openFile(lowerName + ".dat");
|
||||
auto datfile = data->index.openFile(name + ".dat");
|
||||
|
||||
CutsceneData* cutscene = new CutsceneData;
|
||||
|
||||
@ -704,7 +700,7 @@ void GameWorld::loadCutscene(const std::string& name) {
|
||||
loaderdat.load(cutscene->tracks, datfile);
|
||||
}
|
||||
|
||||
data->loadIFP(lowerName + ".ifp");
|
||||
data->loadIFP(name + ".ifp");
|
||||
|
||||
cutsceneAudioLoaded = data->loadAudioStream(name + ".mp3");
|
||||
|
||||
|
@ -1,9 +1,9 @@
|
||||
#ifndef _RWENGINE_Garage_HPP_
|
||||
#define _RWENGINE_Garage_HPP_
|
||||
#ifndef _RWENGINE_GARAGE_HPP_
|
||||
#define _RWENGINE_GARAGE_HPP_
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
#include <glm/gtc/quaternion.hpp>
|
||||
#include <rw/defines.hpp>
|
||||
#include <rw/debug.hpp>
|
||||
|
||||
class PlayerController;
|
||||
|
||||
@ -109,4 +109,4 @@ public:
|
||||
void tick(float dt);
|
||||
};
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
@ -1,6 +1,6 @@
|
||||
#include "engine/Payphone.hpp"
|
||||
|
||||
#include <rw/defines.hpp>
|
||||
#include <rw/debug.hpp>
|
||||
|
||||
#include "ai/PlayerController.hpp"
|
||||
|
||||
|
@ -12,7 +12,7 @@
|
||||
#include <glm/glm.hpp>
|
||||
#include <glm/gtc/quaternion.hpp>
|
||||
|
||||
#include <rw/defines.hpp>
|
||||
#include <rw/debug.hpp>
|
||||
|
||||
#include "data/ZoneData.hpp"
|
||||
#include "engine/GameData.hpp"
|
||||
|
@ -1,6 +1,6 @@
|
||||
#include "engine/ScreenText.hpp"
|
||||
|
||||
#include <rw/defines.hpp>
|
||||
#include <rw/debug.hpp>
|
||||
|
||||
void ScreenText::tick(float dt) {
|
||||
int millis = dt * 1000;
|
||||
|
@ -6,7 +6,7 @@
|
||||
#include <iterator>
|
||||
#include <sstream>
|
||||
|
||||
#include <rw/defines.hpp>
|
||||
#include <rw/debug.hpp>
|
||||
|
||||
#include <data/ModelData.hpp>
|
||||
#include <data/WeaponData.hpp>
|
||||
|
@ -7,7 +7,7 @@
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
#include <rw/defines.hpp>
|
||||
#include <rw/debug.hpp>
|
||||
|
||||
#include "data/CutsceneData.hpp"
|
||||
#include "platform/FileHandle.hpp"
|
||||
|
@ -9,7 +9,7 @@
|
||||
#include <BulletDynamics/Character/btKinematicCharacterController.h>
|
||||
#include <btBulletDynamicsCommon.h>
|
||||
|
||||
#include <rw/defines.hpp>
|
||||
#include <rw/debug.hpp>
|
||||
|
||||
#include "ai/CharacterController.hpp"
|
||||
#include "ai/PlayerController.hpp"
|
||||
|
@ -7,7 +7,7 @@
|
||||
#include <glm/gtc/quaternion.hpp>
|
||||
#include <glm/gtc/matrix_transform.hpp>
|
||||
|
||||
#include <rw/defines.hpp>
|
||||
#include <rw/debug.hpp>
|
||||
#include <rw/forward.hpp>
|
||||
|
||||
#include <data/ModelData.hpp>
|
||||
|
@ -4,7 +4,7 @@
|
||||
#include <cstdint>
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
#include <rw/defines.hpp>
|
||||
#include <rw/debug.hpp>
|
||||
|
||||
#include <objects/GameObject.hpp>
|
||||
|
||||
|
@ -9,7 +9,7 @@
|
||||
#include <gl/DrawBuffer.hpp>
|
||||
#include <gl/GeometryBuffer.hpp>
|
||||
#include <gl/gl_core_3_3.h>
|
||||
#include <rw/defines.hpp>
|
||||
#include <rw/debug.hpp>
|
||||
|
||||
#include "render/GameRenderer.hpp"
|
||||
|
||||
|
@ -7,7 +7,7 @@
|
||||
#include <glm/gtc/type_ptr.hpp>
|
||||
|
||||
#include <gl/DrawBuffer.hpp>
|
||||
#include <rw/defines.hpp>
|
||||
#include <rw/debug.hpp>
|
||||
|
||||
namespace {
|
||||
constexpr GLuint kUBOIndexScene = 1;
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
#include <rw/defines.hpp>
|
||||
#include <rw/debug.hpp>
|
||||
#include <rw/types.hpp>
|
||||
|
||||
#include "engine/GameData.hpp"
|
||||
|
@ -1,13 +1,14 @@
|
||||
#ifndef _RWENGINE_SCMFILE_HPP_
|
||||
#define _RWENGINE_SCMFILE_HPP_
|
||||
|
||||
#include "script/ScriptTypes.hpp"
|
||||
|
||||
#include <rw/bit_cast.hpp>
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "script/ScriptTypes.hpp"
|
||||
#include "rw/bit_cast.cpp"
|
||||
|
||||
/**
|
||||
* @brief Handles in-memory SCM file data including section offsets.
|
||||
*/
|
||||
|
@ -1,7 +1,7 @@
|
||||
#ifndef _RWENGINE_SCRIPTFUNCTIONS_HPP_
|
||||
#define _RWENGINE_SCRIPTFUNCTIONS_HPP_
|
||||
|
||||
#include <rw/defines.hpp>
|
||||
#include <rw/debug.hpp>
|
||||
|
||||
#include <ai/AIGraphNode.hpp>
|
||||
#include <data/GameTexts.hpp>
|
||||
|
@ -9,7 +9,7 @@
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
#include <rw/defines.hpp>
|
||||
#include <rw/debug.hpp>
|
||||
|
||||
#include "engine/Garage.hpp"
|
||||
|
||||
|
@ -6,7 +6,7 @@
|
||||
|
||||
#include <SDL.h>
|
||||
|
||||
#include <rw/defines.hpp>
|
||||
#include <rw/debug.hpp>
|
||||
|
||||
#include "GitSHA1.h"
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
#include "GameConfig.hpp"
|
||||
#include <algorithm>
|
||||
|
||||
#include <rw/defines.hpp>
|
||||
#include <rw/debug.hpp>
|
||||
#include <rw/filesystem.hpp>
|
||||
|
||||
#include <boost/property_tree/ini_parser.hpp>
|
||||
|
@ -8,7 +8,7 @@
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
#include <render/GameRenderer.hpp>
|
||||
#include <rw/defines.hpp>
|
||||
#include <rw/debug.hpp>
|
||||
|
||||
/**
|
||||
* Default values for menus that should match the look and feel of the original
|
||||
|
@ -102,8 +102,8 @@ void IngameState::startTest() {
|
||||
void IngameState::startGame() {
|
||||
game->startScript("data/main.scm");
|
||||
game->getScriptVM()->startThread(0);
|
||||
getWorld()->sound.playBackground(getWorld()->data->getDataPath().string() +
|
||||
"/audio/City.wav"); // FIXME: use path
|
||||
auto audioCityPath = getWorld()->data->index.findFilePath("audio/City.wav");
|
||||
getWorld()->sound.playBackground(audioCityPath.string()); //FIXME: playBackground should just accept "audio/City.wav"
|
||||
}
|
||||
|
||||
void IngameState::enter() {
|
||||
|
@ -3,7 +3,7 @@
|
||||
#include "game.hpp"
|
||||
|
||||
#include <engine/SaveGame.hpp>
|
||||
#include <rw/defines.hpp>
|
||||
#include <rw/debug.hpp>
|
||||
#include "RWGame.hpp"
|
||||
|
||||
MenuState::MenuState(RWGame* game) : State(game) {
|
||||
|
@ -14,11 +14,11 @@ SET(RWLIB_SOURCES
|
||||
source/gl/TextureData.cpp
|
||||
|
||||
source/rw/abort.cpp
|
||||
source/rw/bit_cast.cpp
|
||||
source/rw/bit_cast.hpp
|
||||
source/rw/filesystem.hpp
|
||||
source/rw/forward.hpp
|
||||
source/rw/types.hpp
|
||||
source/rw/defines.hpp
|
||||
source/rw/debug.hpp
|
||||
|
||||
source/platform/FileHandle.hpp
|
||||
source/platform/FileIndex.hpp
|
||||
|
@ -14,7 +14,7 @@
|
||||
#include "gl/gl_core_3_3.h"
|
||||
#include "loaders/RWBinaryStream.hpp"
|
||||
#include "platform/FileHandle.hpp"
|
||||
#include "rw/defines.hpp"
|
||||
#include "rw/debug.hpp"
|
||||
|
||||
enum DFFChunks {
|
||||
CHUNK_STRUCT = 0x0001,
|
||||
|
@ -3,7 +3,7 @@
|
||||
#include <boost/algorithm/string/predicate.hpp>
|
||||
#include <cstdio>
|
||||
|
||||
#include "rw/defines.hpp"
|
||||
#include "rw/debug.hpp"
|
||||
|
||||
LoaderIMG::LoaderIMG() : m_version(GTAIIIVC), m_assetCount(0) {
|
||||
}
|
||||
|
@ -4,7 +4,7 @@
|
||||
#include <cstdio>
|
||||
#include <string>
|
||||
|
||||
#include "rw/defines.hpp"
|
||||
#include "rw/debug.hpp"
|
||||
|
||||
LoaderSDT::LoaderSDT() : m_version(GTAIIIVC), m_assetCount(0) {
|
||||
}
|
||||
|
@ -10,7 +10,7 @@
|
||||
#include "gl/gl_core_3_3.h"
|
||||
#include "loaders/RWBinaryStream.hpp"
|
||||
#include "platform/FileHandle.hpp"
|
||||
#include "rw/defines.hpp"
|
||||
#include "rw/debug.hpp"
|
||||
|
||||
GLuint gErrorTextureData[] = {0xFFFF00FF, 0xFF000000, 0xFF000000, 0xFFFF00FF};
|
||||
GLuint gDebugTextureData[] = {0xFF0000FF, 0xFF00FF00};
|
||||
|
@ -6,8 +6,8 @@
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
#include "rw/defines.hpp"
|
||||
#include "rw/bit_cast.cpp"
|
||||
#include "rw/debug.hpp"
|
||||
#include "rw/bit_cast.hpp"
|
||||
|
||||
/**
|
||||
* @brief Class for working with RenderWare binary streams.
|
||||
|
@ -1,13 +1,11 @@
|
||||
#ifndef _LIBRW_FILEHANDLE_HPP_
|
||||
#define _LIBRW_FILEHANDLE_HPP_
|
||||
|
||||
#include <memory>
|
||||
|
||||
/**
|
||||
* @brief Contains a pointer to a file's contents.
|
||||
*/
|
||||
struct FileContentsInfo {
|
||||
char* data;
|
||||
char *data;
|
||||
size_t length;
|
||||
|
||||
FileContentsInfo(char* mem, size_t len) : data(mem), length(len) {
|
||||
|
@ -1,38 +1,69 @@
|
||||
#include "platform/FileIndex.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
#include <fstream>
|
||||
#include <memory>
|
||||
#include <stdexcept>
|
||||
|
||||
#include <boost/range/iterator_range.hpp>
|
||||
#include <iterator>
|
||||
#include <sstream>
|
||||
|
||||
#include "FileHandle.hpp"
|
||||
#include "loaders/LoaderIMG.hpp"
|
||||
#include "platform/FileHandle.hpp"
|
||||
|
||||
void FileIndex::indexGameDirectory(const rwfs::path& base_path) {
|
||||
gamedatapath_ = base_path;
|
||||
#include "rw/debug.hpp"
|
||||
|
||||
for (const rwfs::path& path :
|
||||
rwfs::recursive_directory_iterator(base_path)) {
|
||||
std::string FileIndex::normalizeFilePath(const std::string &filePath) {
|
||||
std::ostringstream oss;
|
||||
std::transform(filePath.cbegin(), filePath.cend(), std::ostreambuf_iterator<char>(oss), [](char c) {
|
||||
if (c == '\\') {
|
||||
return '/';
|
||||
}
|
||||
return static_cast<char>(std::tolower(c));
|
||||
});
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
void FileIndex::indexTree(const rwfs::path &path) {
|
||||
// Remove the trailing "/" or "/." from base_path. Boost 1.66 and c++17 have different lexically_relative behavior.
|
||||
rwfs::path basePath = (path / ".").lexically_normal();
|
||||
basePath = basePath.parent_path();
|
||||
|
||||
for (const rwfs::path &path :
|
||||
rwfs::recursive_directory_iterator(basePath)) {
|
||||
if (!rwfs::is_regular_file(path)) {
|
||||
continue;
|
||||
}
|
||||
auto relPath = path.lexically_relative(basePath);
|
||||
std::string relPathName = normalizeFilePath(relPath.string());
|
||||
indexedData_[relPathName] = {IndexedDataType::FILE, path.string(), ""};
|
||||
|
||||
std::string name = path.string();
|
||||
std::transform(name.begin(), name.end(), name.begin(), ::tolower);
|
||||
filesystemfiles_[name] = path;
|
||||
auto filename = normalizeFilePath(path.filename().string());
|
||||
indexedData_[filename] = {IndexedDataType::FILE, path.string(), ""};
|
||||
}
|
||||
}
|
||||
|
||||
FileHandle FileIndex::openFilePath(const std::string& file_path) {
|
||||
auto datapath = findFilePath(file_path);
|
||||
std::ifstream dfile(datapath.string(),
|
||||
std::ios_base::binary | std::ios_base::ate);
|
||||
const FileIndex::IndexedData *FileIndex::getIndexedDataAt(const std::string &filePath) const {
|
||||
auto normPath = normalizeFilePath(filePath);
|
||||
return &indexedData_.at(normPath);
|
||||
}
|
||||
|
||||
rwfs::path FileIndex::findFilePath(const std::string &filePath) const {
|
||||
return getIndexedDataAt(filePath)->path;
|
||||
}
|
||||
|
||||
FileHandle FileIndex::openFileRaw(const std::string &filePath) const {
|
||||
const auto *indexData = getIndexedDataAt(filePath);
|
||||
std::ifstream dfile(indexData->path, std::ios::binary);
|
||||
if (!dfile.is_open()) {
|
||||
throw std::runtime_error("Unable to open file: " + file_path);
|
||||
throw std::runtime_error("Unable to open file: " + filePath);
|
||||
}
|
||||
|
||||
#if RW_DEBUG
|
||||
if (indexData->type != IndexedDataType::FILE) {
|
||||
RW_MESSAGE("Reading raw data from archive \"" << filePath << "\"");
|
||||
}
|
||||
#endif
|
||||
|
||||
dfile.seekg(0, std::ios::end);
|
||||
auto length = dfile.tellg();
|
||||
dfile.seekg(0);
|
||||
auto data = new char[length];
|
||||
@ -41,84 +72,57 @@ FileHandle FileIndex::openFilePath(const std::string& file_path) {
|
||||
return std::make_shared<FileContentsInfo>(data, length);
|
||||
}
|
||||
|
||||
void FileIndex::indexTree(const rwfs::path& root) {
|
||||
for (const rwfs::path& path : rwfs::recursive_directory_iterator(root)) {
|
||||
if (!rwfs::is_regular_file(path)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
std::string directory = path.parent_path().string();
|
||||
std::string realName = path.filename().string();
|
||||
std::string lowerName = realName;
|
||||
std::transform(lowerName.begin(), lowerName.end(), lowerName.begin(),
|
||||
::tolower);
|
||||
files[lowerName] = {lowerName, realName, directory, ""};
|
||||
}
|
||||
}
|
||||
|
||||
void FileIndex::indexArchive(const std::string& archive) {
|
||||
// Split directory from archive name
|
||||
auto archive_path = rwfs::path(archive);
|
||||
auto directory = archive_path.parent_path();
|
||||
auto archive_basename = archive_path.filename();
|
||||
auto archive_full_path = directory / archive_basename;
|
||||
void FileIndex::indexArchive(const std::string &archive) {
|
||||
rwfs::path path = findFilePath(archive);
|
||||
|
||||
LoaderIMG img;
|
||||
if (!img.load(archive_full_path.string())) {
|
||||
throw std::runtime_error("Failed to load IMG archive: " +
|
||||
archive_full_path.string());
|
||||
if (!img.load(path.string())) {
|
||||
throw std::runtime_error("Failed to load IMG archive: " + path.string());
|
||||
}
|
||||
|
||||
std::string lowerName;
|
||||
for (size_t i = 0; i < img.getAssetCount(); ++i) {
|
||||
auto& asset = img.getAssetInfoByIndex(i);
|
||||
auto &asset = img.getAssetInfoByIndex(i);
|
||||
|
||||
if (asset.size == 0) continue;
|
||||
|
||||
lowerName = asset.name;
|
||||
std::transform(lowerName.begin(), lowerName.end(), lowerName.begin(),
|
||||
::tolower);
|
||||
std::string assetName = normalizeFilePath(asset.name);
|
||||
|
||||
files[lowerName] = {lowerName, asset.name, directory.string(),
|
||||
archive_basename.string()};
|
||||
indexedData_[assetName] = {IndexedDataType::ARCHIVE, path.string(), asset.name};
|
||||
}
|
||||
}
|
||||
|
||||
FileHandle FileIndex::openFile(const std::string& filename) {
|
||||
auto iterator = files.find(filename);
|
||||
if (iterator == files.end()) {
|
||||
FileHandle FileIndex::openFile(const std::string &filePath) {
|
||||
auto cleanFilePath = normalizeFilePath(filePath);
|
||||
auto indexedDataPos = indexedData_.find(cleanFilePath);
|
||||
if (indexedDataPos == indexedData_.end()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
IndexData& f = iterator->second;
|
||||
bool isArchive = !f.archive.empty();
|
||||
const auto &indexedData = indexedDataPos->second;
|
||||
|
||||
auto fsName = f.directory + "/" + f.originalName;
|
||||
|
||||
char* data = nullptr;
|
||||
char *data = nullptr;
|
||||
size_t length = 0;
|
||||
|
||||
if (isArchive) {
|
||||
fsName = f.directory + "/" + f.archive;
|
||||
|
||||
if (indexedData.type == IndexedDataType::ARCHIVE) {
|
||||
LoaderIMG img;
|
||||
|
||||
if (!img.load(fsName)) {
|
||||
throw std::runtime_error("Failed to load IMG archive: " + fsName);
|
||||
if (!img.load(indexedData.path)) {
|
||||
throw std::runtime_error("Failed to load IMG archive: " + indexedData.path);
|
||||
}
|
||||
|
||||
LoaderIMGFile file;
|
||||
if (img.findAssetInfo(f.originalName, file)) {
|
||||
auto filename = rwfs::path(indexedData.assetData).filename().string();
|
||||
if (img.findAssetInfo(filename, file)) {
|
||||
length = file.size * 2048;
|
||||
data = img.loadToMemory(f.originalName);
|
||||
data = img.loadToMemory(filename);
|
||||
}
|
||||
} else {
|
||||
std::ifstream dfile(fsName.c_str(), std::ios_base::binary);
|
||||
std::ifstream dfile(indexedData.path, std::ios::binary);
|
||||
if (!dfile.is_open()) {
|
||||
throw std::runtime_error("Unable to open file: " + fsName);
|
||||
throw std::runtime_error("Unable to open file: " + indexedData.path);
|
||||
}
|
||||
|
||||
dfile.seekg(0, std::ios_base::end);
|
||||
dfile.seekg(0, std::ios::end);
|
||||
length = dfile.tellg();
|
||||
dfile.seekg(0);
|
||||
data = new char[length];
|
||||
|
@ -1,91 +1,96 @@
|
||||
#ifndef _LIBRW_FILEINDEX_HPP_
|
||||
#define _LIBRW_FILEINDEX_HPP_
|
||||
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include "rw/filesystem.hpp"
|
||||
#include "rw/forward.hpp"
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
#include <rw/filesystem.hpp>
|
||||
#include <rw/forward.hpp>
|
||||
|
||||
class FileIndex {
|
||||
private:
|
||||
/**
|
||||
* Mapping type (lower case name) => (on disk name)
|
||||
*/
|
||||
using FileSystemMap = std::unordered_map<rwfs::path, rwfs::path>;
|
||||
|
||||
rwfs::path gamedatapath_;
|
||||
FileSystemMap filesystemfiles_;
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief indexDirectory finds the true case for each file in the tree
|
||||
* @param base_path
|
||||
* @brief normalizeString Normalize a file path
|
||||
* @param filePath the path to normalize
|
||||
* @return normalized file path
|
||||
*/
|
||||
static std::string normalizeFilePath(const std::string &filePath);
|
||||
|
||||
/**
|
||||
* @brief indexDirectory index all files at path
|
||||
* @param path the path to index
|
||||
*
|
||||
* This is used to build the mapping of lower-case file paths to the
|
||||
* true case on the file system for platforms where this is an issue.
|
||||
*
|
||||
*/
|
||||
void indexGameDirectory(const rwfs::path& base_path);
|
||||
void indexTree(const rwfs::path &path);
|
||||
|
||||
/**
|
||||
* @brief findFilePath finds disk path for a game data file
|
||||
* @param path
|
||||
* @param filePath the path to find
|
||||
* @return The file path as it exists on disk
|
||||
* @throws if this FileIndex has not indexed the path
|
||||
*/
|
||||
rwfs::path findFilePath(std::string path) {
|
||||
auto backslash = std::string::npos;
|
||||
while ((backslash = path.find("\\")) != std::string::npos) {
|
||||
path.replace(backslash, 1, "/");
|
||||
}
|
||||
auto realpath = gamedatapath_ / path;
|
||||
std::string name = realpath.string();
|
||||
std::transform(name.begin(), name.end(), name.begin(), ::tolower);
|
||||
|
||||
return filesystemfiles_[name];
|
||||
}
|
||||
rwfs::path findFilePath(const std::string &filePath) const;
|
||||
|
||||
/**
|
||||
* @brief openFilePath opens a file on the disk
|
||||
* @param file_path
|
||||
* @return A handle for the file on the disk
|
||||
* @brief openFileRaw Opens a raw file on the disk
|
||||
* @param filePath the path to open
|
||||
* @return FileHandle to the file
|
||||
* @throws if this FileIndex has not indexed the path
|
||||
*/
|
||||
FileHandle openFilePath(const std::string& file_path);
|
||||
|
||||
struct IndexData {
|
||||
/// Lowercase identifying filename
|
||||
std::string filename;
|
||||
/// Original filename
|
||||
std::string originalName;
|
||||
/// Containing directory
|
||||
std::string directory;
|
||||
/// The archive filename (if applicable)
|
||||
std::string archive;
|
||||
};
|
||||
|
||||
/**
|
||||
* Adds the files contained within the given directory tree to the
|
||||
* file index.
|
||||
*/
|
||||
void indexTree(const rwfs::path& root);
|
||||
FileHandle openFileRaw(const std::string &filePath) const;
|
||||
|
||||
/**
|
||||
* Adds the files contained within the given Archive file to the
|
||||
* file index.
|
||||
* @param filePath path to the archive
|
||||
* @throws if this FileIndex has not indexed the archive itself
|
||||
*/
|
||||
void indexArchive(const std::string& archive);
|
||||
void indexArchive(const std::string &filePath);
|
||||
|
||||
/**
|
||||
* Returns a FileHandle for the file if it can be found in the
|
||||
* file index, otherwise an empty FileHandle is returned.
|
||||
* @param filePath name of the file to open
|
||||
* @return FileHandle to the file, nullptr if this FileINdexed has not indexed the path
|
||||
*/
|
||||
FileHandle openFile(const std::string& filename);
|
||||
FileHandle openFile(const std::string &filePath);
|
||||
|
||||
private:
|
||||
std::map<std::string, IndexData> files;
|
||||
/**
|
||||
* @brief Type of the indexed data.
|
||||
*/
|
||||
enum IndexedDataType {
|
||||
/// Is a file on disk
|
||||
FILE,
|
||||
/// Is a member of an archive
|
||||
ARCHIVE,
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief All information of indexed data.
|
||||
*/
|
||||
struct IndexedData {
|
||||
/// Type of indexed data.
|
||||
IndexedDataType type;
|
||||
/// Path of indexed data.
|
||||
std::string path;
|
||||
/// Extra data of assets (FIXME: use c++17 std::variant or std::option)
|
||||
std::string assetData;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief indexedData_ A mapping from filepath (relative to game data path) to an IndexedData item.
|
||||
*/
|
||||
std::unordered_map<std::string, IndexedData> indexedData_;
|
||||
|
||||
/**
|
||||
* @brief getIndexedDataAt Get IndexedData for filePath
|
||||
* @param filePath the file path to get the IndexedData for
|
||||
* @return IndexedData pointer if this FileIndex has indexed the filePath
|
||||
* @throws If this FileIndex has not indexed filePath
|
||||
*/
|
||||
const IndexedData *getIndexedDataAt(const std::string &filePath) const;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -1,10 +1,9 @@
|
||||
#ifndef _LIBRW_BIT_CAST_CPP_
|
||||
#define _LIBRW_BIT_CAST_CPP_
|
||||
#ifndef _LIBRW_BIT_CAST_HPP_
|
||||
#define _LIBRW_BIT_CAST_HPP_
|
||||
|
||||
//Based on https://gist.github.com/socantre/3472964
|
||||
#include <cstring> // memcpy
|
||||
#include <type_traits> // is_trivially_copyable
|
||||
#include "rw/defines.hpp" // RW_ASSERT
|
||||
|
||||
template <class Dest, class Source>
|
||||
inline Dest bit_cast(Source const &source) {
|
@ -1,5 +1,5 @@
|
||||
#ifndef _LIBRW_DEFINES_HPP_
|
||||
#define _LIBRW_DEFINES_HPP_
|
||||
#ifndef _LIBRW_DEBUG_HPP_
|
||||
#define _LIBRW_DEBUG_HPP_
|
||||
|
||||
#if RW_DEBUG
|
||||
#include <cstdlib>
|
@ -5,7 +5,7 @@
|
||||
#include <glm/glm.hpp>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <rw/defines.hpp>
|
||||
#include <rw/debug.hpp>
|
||||
#include <string>
|
||||
|
||||
#define RW_USING(feature) 1 == feature
|
||||
|
@ -8,7 +8,7 @@
|
||||
#include <fstream>
|
||||
#include <map>
|
||||
|
||||
#include <rw/defines.hpp>
|
||||
#include <rw/debug.hpp>
|
||||
#include <rw/filesystem.hpp>
|
||||
|
||||
namespace pt = boost::property_tree;
|
||||
|
@ -2,23 +2,35 @@
|
||||
#include <platform/FileIndex.hpp>
|
||||
#include "test_Globals.hpp"
|
||||
|
||||
#include <rw/filesystem.hpp>
|
||||
namespace fs = rwfs;
|
||||
|
||||
BOOST_AUTO_TEST_SUITE(FileIndexTests)
|
||||
|
||||
#if RW_TEST_WITH_DATA
|
||||
BOOST_AUTO_TEST_CASE(test_directory_paths) {
|
||||
FileIndex index;
|
||||
BOOST_AUTO_TEST_CASE(test_normalizeName) {
|
||||
std::string ref = "a/b/c";
|
||||
{
|
||||
std::string dirty = "a\\b\\c";
|
||||
BOOST_CHECK_EQUAL(ref, FileIndex::normalizeFilePath(dirty));
|
||||
}
|
||||
{
|
||||
std::string dirty = "A/B/C";
|
||||
BOOST_CHECK_EQUAL(ref, FileIndex::normalizeFilePath(dirty));
|
||||
}
|
||||
{
|
||||
std::string dirty = "A\\B\\C";
|
||||
BOOST_CHECK_EQUAL(ref, FileIndex::normalizeFilePath(dirty));
|
||||
}
|
||||
}
|
||||
|
||||
index.indexGameDirectory(Global::getGamePath());
|
||||
#if RW_TEST_WITH_DATA
|
||||
BOOST_AUTO_TEST_CASE(test_indexTree) {
|
||||
FileIndex index;
|
||||
index.indexTree(Global::getGamePath());
|
||||
|
||||
{
|
||||
std::string upperpath{"DATA/CULLZONE.DAT"};
|
||||
auto truepath = index.findFilePath(upperpath);
|
||||
BOOST_ASSERT(!truepath.empty());
|
||||
BOOST_CHECK(upperpath != truepath);
|
||||
fs::path expected{Global::getGamePath()};
|
||||
rwfs::path expected{Global::getGamePath()};
|
||||
expected /= "data/CULLZONE.DAT";
|
||||
BOOST_CHECK_EQUAL(truepath.string(), expected.string());
|
||||
}
|
||||
@ -27,28 +39,35 @@ BOOST_AUTO_TEST_CASE(test_directory_paths) {
|
||||
auto truepath = index.findFilePath(upperpath);
|
||||
BOOST_ASSERT(!truepath.empty());
|
||||
BOOST_CHECK(upperpath != truepath);
|
||||
fs::path expected{Global::getGamePath()};
|
||||
rwfs::path expected{Global::getGamePath()};
|
||||
expected /= "data/maps/comnbtm/comNbtm.ipl";
|
||||
BOOST_CHECK_EQUAL(truepath.string(), expected.string());
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_file) {
|
||||
BOOST_AUTO_TEST_CASE(test_openFile) {
|
||||
FileIndex index;
|
||||
|
||||
index.indexTree(Global::getGamePath() + "/data");
|
||||
|
||||
auto handle = index.openFile("cullzone.dat");
|
||||
BOOST_CHECK(handle != nullptr);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_file_archive) {
|
||||
BOOST_AUTO_TEST_CASE(test_indexArchive) {
|
||||
FileIndex index;
|
||||
index.indexTree(Global::getGamePath());
|
||||
|
||||
index.indexArchive(Global::getGamePath() + "/models/gta3.img");
|
||||
{
|
||||
auto handle = index.openFile("landstal.dff");
|
||||
BOOST_CHECK(handle == nullptr);
|
||||
}
|
||||
|
||||
auto handle = index.openFile("landstal.dff");
|
||||
BOOST_CHECK(handle != nullptr);
|
||||
index.indexArchive("models/gta3.img");
|
||||
|
||||
{
|
||||
auto handle = index.openFile("landstal.dff");
|
||||
BOOST_CHECK(handle != nullptr);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -11,7 +11,7 @@ BOOST_AUTO_TEST_SUITE(TextTests)
|
||||
#if RW_TEST_WITH_DATA
|
||||
BOOST_AUTO_TEST_CASE(load_test) {
|
||||
{
|
||||
auto d = Global::get().e->data->index.openFilePath("text/english.gxt");
|
||||
auto d = Global::get().e->data->index.openFileRaw("text/english.gxt");
|
||||
|
||||
GameTexts texts;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user