feat: replace ArchiveFile with FolderFile for media asset loading

Replace the ArchiveFile-based media asset loading system with a new
FolderFile implementation that reads files directly from a folder
structure instead of from compressed .arc archives. This change
simplifies asset management and eliminates the need for pre-packaged
media archives.

Key changes:
- Added FolderFile class that indexes and reads files from a folder
- Updated Consoles_App to use FolderFile instead of ArchiveFile
- Modified CMake asset copy configuration to exclude platform-specific
  media folders instead of .arc files
- Updated platform-specific media path references to point to folders
  instead of .arc files

This enables easier development and debugging by allowing direct access
to media files without requiring archive extraction or repackaging.
This commit is contained in:
George V.
2026-04-10 20:59:46 +03:00
parent a175854dab
commit bb04d465db
6 changed files with 233 additions and 22 deletions

View File

@@ -0,0 +1,181 @@
#include "stdafx.h"
#include "../Minecraft.World/StringHelpers.h"
#include "../Minecraft.World/compression.h"
#include "FolderFile.h"
void FolderFile::_buildFileIndex()
{
wstring searchPath = m_folderPath + L"\\*";
WIN32_FIND_DATAW findData;
HANDLE hFind = FindFirstFileW(searchPath.c_str(), &findData);
if (hFind == INVALID_HANDLE_VALUE)
{
app.DebugPrintf("Failed to open folder: %ls\n", m_folderPath.c_str());
return;
}
do
{
if (!(findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
{
wstring filename = findData.cFileName;
wstring fullPath = m_folderPath + L"\\" + filename;
// Store filename without path for compatibility with existing code
m_filePaths[filename] = fullPath;
}
} while (FindNextFileW(hFind, &findData));
FindClose(hFind);
app.DebugPrintf("Indexed %d files from folder\n", (int)m_filePaths.size());
}
FolderFile::FolderFile(wstring folderPath)
{
m_folderPath = folderPath;
app.DebugPrintf("Loading folder file...\n");
#ifndef _CONTENT_PACKAGE
char buf[256];
wcstombs(buf, folderPath.c_str(), 256);
app.DebugPrintf("folder path - %s\n", buf);
#endif
// Check if folder exists
DWORD attrib = GetFileAttributesW(folderPath.c_str());
if (attrib == INVALID_FILE_ATTRIBUTES || !(attrib & FILE_ATTRIBUTE_DIRECTORY))
{
app.DebugPrintf("Failed to load folder - directory doesn't exist!\n");
app.FatalLoadError();
}
_buildFileIndex();
app.DebugPrintf("Finished loading folder file\n");
}
FolderFile::~FolderFile()
{
}
vector<wstring>* FolderFile::getFileList()
{
vector<wstring>* out = new vector<wstring>();
for (const auto& it : m_filePaths)
{
out->push_back(it.first);
}
return out;
}
bool FolderFile::hasFile(const wstring &filename)
{
return m_filePaths.find(filename) != m_filePaths.end();
}
int FolderFile::getFileSize(const wstring &filename)
{
auto it = m_filePaths.find(filename);
if (it == m_filePaths.end())
{
return -1;
}
WIN32_FILE_ATTRIBUTE_DATA fileData;
if (GetFileAttributesExW(it->second.c_str(), GetFileExInfoStandard, &fileData))
{
return (int)fileData.nFileSizeLow;
}
return -1;
}
byteArray FolderFile::getFile(const wstring &filename)
{
byteArray out;
auto it = m_filePaths.find(filename);
if (it == m_filePaths.end())
{
app.DebugPrintf("Couldn't find file in folder\n");
app.DebugPrintf("Failed to find file '%ls' in folder\n", filename.c_str());
#ifndef _CONTENT_PACKAGE
__debugbreak();
#endif
app.FatalLoadError();
return out;
}
HANDLE hFile = CreateFileW(
it->second.c_str(),
GENERIC_READ,
FILE_SHARE_READ,
nullptr,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
nullptr
);
if (hFile == INVALID_HANDLE_VALUE)
{
app.DebugPrintf("Failed to open file: %ls\n", it->second.c_str());
app.FatalLoadError();
return out;
}
DWORD fileSize = GetFileSize(hFile, nullptr);
if (fileSize == INVALID_FILE_SIZE)
{
app.DebugPrintf("Failed to get file size: %ls\n", it->second.c_str());
CloseHandle(hFile);
app.FatalLoadError();
return out;
}
PBYTE pData = new BYTE[fileSize];
DWORD bytesRead = 0;
BOOL success = ReadFile(hFile, pData, fileSize, &bytesRead, nullptr);
CloseHandle(hFile);
if (!success || bytesRead != fileSize)
{
app.DebugPrintf("Failed to read file: %ls\n", it->second.c_str());
delete[] pData;
app.FatalLoadError();
return out;
}
out = byteArray(pData, fileSize);
// Compressed filenames are preceeded with an asterisk.
if (filename[0] == L'*' && out.data != nullptr)
{
/* 4J-JEV:
* If a compressed file is accessed before compression object is
* initialized it will crash here (Compression::getCompression).
*/
///4 279 553 556
ByteArrayInputStream bais(out);
DataInputStream dis(&bais);
unsigned int decompressedSize = dis.readInt();
dis.close();
PBYTE uncompressedBuffer = new BYTE[decompressedSize];
Compression::getCompression()->Decompress(uncompressedBuffer, &decompressedSize, out.data + 4, out.length - 4);
delete[] out.data;
out.data = uncompressedBuffer;
out.length = decompressedSize;
}
return out;
}