Skip to content
This repository has been archived by the owner on Aug 23, 2023. It is now read-only.

Commit

Permalink
VFS: 5/5 - Resource Manager
Browse files Browse the repository at this point in the history
  • Loading branch information
corwinn committed Jan 23, 2023
1 parent 1b051bc commit 5e81be2
Show file tree
Hide file tree
Showing 15 changed files with 624 additions and 84 deletions.
49 changes: 36 additions & 13 deletions game/h3r_lodfs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,36 +43,39 @@ static int const H3R_LOD_UNK1 {4}; // unknown 4 bytes
static int const H3R_LOD_UNK2 {80};// unknown 80 bytes

LodFS::LodFS(const String & fname)
: VFS {fname}, _s {fname, H3R_NS::OS::FileStream::Mode::ReadOnly},
_rrs {&_s, 0, 0}, _zis {&_rrs, 0, 0}
: VFS {fname}
{
H3R_CREATE_OBJECT(_s, OS::FileStream)
{fname, H3R_NS::OS::FileStream::Mode::ReadOnly};
if (! *_s) return;

union { int isign; unsigned char sign[4]; };
int cnt {0};
var FN_cleanup {fname.AsZStr ()};
var FN {FN_cleanup.Data ()};

Stream::Read (_s, &isign);
Stream::Read (*_s, &isign);
if (H3R_LOD_SIGN != isign) {
Log::Err (String::Format ("%s: Unknown signature: %00000008Xd" EOL,
FN, isign));
}
OS::Log_stdout ("%s: sign: %s" EOL, FN, sign);

_s.Seek (H3R_LOD_UNK1); //TODO what are those? - c8 @ H3bitmap.lod
_s->Seek (H3R_LOD_UNK1); //TODO what are those? - c8 @ H3bitmap.lod

Stream::Read (_s, &cnt);
Stream::Read (*_s, &cnt);
if (cnt <= 0 || cnt > H3R_LOD_MAX_ENTRIES) {
Log::Err (
String::Format ("%s: Suspicious entry count: %d" EOL, FN, cnt));
return;
}
OS::Log_stdout ("%s: entries: %d" EOL, FN, cnt);

_s.Seek (H3R_LOD_UNK2); //TODO what are those? H3bitmap.lod
_s->Seek (H3R_LOD_UNK2); //TODO what are those? H3bitmap.lod

_entries.Resize (cnt);
var data = static_cast<LodFS::Entry *>(_entries);
Stream::Read (_s, data, cnt);
Stream::Read (*_s, data, cnt);
//TODO validate entries
/*int i {0};
for (const var & e : _entries)
Expand All @@ -82,10 +85,18 @@ LodFS::LodFS(const String & fname)
e.SizeC, e.SizeU, e.Name);*/
//LATER if (! sorted) sort (); contract with the binary search below;
// or hash (you should have a DLL already)

H3R_CREATE_OBJECT(_rrs, RefReadStream) {_s, 0, 0};
H3R_CREATE_OBJECT(_zis, ZipInflateStream) {_rrs, 0, 0};
_usable = true;
}// LodFS::LodFS()

LodFS::~LodFS() {}
LodFS::~LodFS()
{
H3R_DESTROY_OBJECT(_zis, ZipInflateStream)
H3R_DESTROY_OBJECT(_rrs, RefReadStream)
H3R_DESTROY_OBJECT(_s, FileStream)
}

Stream & LodFS::GetStream(const LodFS::Entry & e)
{
Expand All @@ -95,31 +106,43 @@ Stream & LodFS::GetStream(const LodFS::Entry & e)
/*OS::Log_stdout ("LodFS::GetStream: compressed: %s" EOL,
(compressed ? "true" : "false"));*/
//np start: e.Ofs, size: (compressed ? e.SizeC : e.SizeU)
_rrs.ResetTo (e.Ofs, (compressed ? e.SizeC : e.SizeU));
_rrs->ResetTo (e.Ofs, (compressed ? e.SizeC : e.SizeU));
return compressed
//np size: e.SizeC, usize: e.SizeU
? _zis.ResetTo (e.SizeC, e.SizeU)
? _zis->ResetTo (e.SizeC, e.SizeU)
//np start: e.Ofs, size: e.SizeU
: _rrs.ResetTo (e.Ofs, e.SizeU);
: _rrs->ResetTo (e.Ofs, e.SizeU);
}

Stream & LodFS::Get(const String & res)
Stream * LodFS::Get(const String & res)
{
//LATER binary search; sort the entry list (I think they're sorted already);
// What?! - you expected a hash? - there will be one sooner or later,
// no worries.
for (const var & e : _entries)
if (res.EqualsZStr ((const char *)e.Name)) return GetStream (e);
if (res.EqualsZStr ((const char *)e.Name)) return &(GetStream (e));
return VFS::Get (res);
}

void LodFS::Walk(bool (*on_entry)(Stream &, const VFS::Entry &))
{
static VFS::Entry vfs_e {};
var prev_info = VFS::VFSInfo {0, vfs_e.Name};
var all = _entries.Length ();
var i = all-all;
for (const var & e : _entries) {
vfs_e.Name = reinterpret_cast<const char *>(e.Name);
vfs_e.Size = e.SizeU;
if (! on_entry (GetStream (e), vfs_e)) break;

//TODO there is definitely a field for improvements
var new_info = VFS::VFSInfo {
static_cast<int>(0.5+(1.0*i++/all*100)), vfs_e.Name};
if (TaskState::Changed (prev_info, new_info)) {
new_info.SetChanged (true);
prev_info = new_info;
OnProgress.Do (&new_info);
}
}
}

Expand Down
45 changes: 32 additions & 13 deletions game/h3r_lodfs.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,19 +44,25 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "h3r_refreadstream.h"
#include "h3r_zipinflatestream.h"

// placement new
#include <new>

H3R_NAMESPACE

// On 2nd thought this shouldn't be final, should one decide to use own,
// extended format (better compression for one, and or hashed names, etc.).
class LodFS : public VFS
{
protected: OS::FileStream _s;
protected: bool _usable {false};
#define public public:
#define protected protected:

protected OS::FileStream * _s {};
protected bool _usable {false};
// 1 stream for now
protected: RefReadStream _rrs;
protected: ZipInflateStream _zis;
protected RefReadStream * _rrs {};
protected ZipInflateStream * _zis {};
#pragma pack(push, 1)
protected: struct Entry final
protected struct Entry final
{
unsigned char Name[16];
int Ofs; // SEEK_SET
Expand All @@ -65,16 +71,29 @@ class LodFS : public VFS
int SizeC; // Compressed size [bytes]
};
#pragma pack(pop)
protected: Array<LodFS::Entry> _entries {};
protected: virtual Stream & GetStream(const LodFS::Entry &);
public: LodFS(const String & path);
public: ~LodFS() override;
public: virtual Stream & Get(const String & name) override;
public: virtual inline operator bool() const override { return _usable; }
protected Array<LodFS::Entry> _entries {};
protected virtual Stream & GetStream(const LodFS::Entry &);
public LodFS(const String & path);
public ~LodFS() override;
public virtual Stream * Get(const String & name) override;
public virtual inline operator bool() const override { return _usable; }

public: virtual void Walk(bool (*)(Stream &, const VFS::Entry &)) override;
};
public virtual void Walk(bool (*)(Stream &, const VFS::Entry &)) override;

public LodFS() : VFS {} {}
public inline virtual VFS * TryLoad(const String & path) override
{
if (! path.ToLower ().EndsWith (".lod")) return nullptr;
LodFS * result {};
H3R_CREATE_OBJECT(result, LodFS) {path};
if (*result) return result;
H3R_DESTROY_OBJECT(result, LodFS)
return nullptr;
}
};// LodFS

#undef public
#undef protected
NAMESPACE_H3R

#endif
69 changes: 69 additions & 0 deletions game/h3r_resmanager.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/**** BEGIN LICENSE BLOCK ****
BSD 3-Clause License
Copyright (c) 2021-2023, the wind.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**** END LICENCE BLOCK ****/

#include "h3r_resmanager.h"
#include "h3r_game.h"

H3R_NAMESPACE

OS::CriticalSection ResManager::_task_info_gate {};

ResManager::~ResManager()//TODO shouldn't I be an IAsyncTask?
{
for (var * obj : _vfs_objects) H3R_DESTROY_OBJECT(obj, VFS)
for (var * obj : _vfs_registry) H3R_DESTROY_OBJECT(obj, VFS)
}

const ResManager::RMTaskInfo & ResManager::GetResource(const String & name)
{
Game::IOThread.Task = _get_task.SetName (name);
return _get_task.State;
}

const ResManager::RMTaskInfo & ResManager::Enumerate(
bool (*on_entry)(Stream &, const VFS::Entry &))
{
Game::IOThread.Task = _walk_task.SetCallback (on_entry);
return _walk_task.State;
}

const ResManager::RMTaskInfo & ResManager::Load(const String & path)
{
Game::IOThread.Task = _load_task.SetPath (path);
return _load_task.State;
}

bool ResManager::TaskComplete() { return Game::IOThread.Done (); }

NAMESPACE_H3R

0 comments on commit 5e81be2

Please sign in to comment.