mirror of
https://github.com/arabine/open-story-teller.git
synced 2025-12-06 17:09:06 +01:00
Import commercial nearly complete
This commit is contained in:
parent
59921fe9fd
commit
879f5fbdbc
9 changed files with 235 additions and 157 deletions
|
|
@ -1,6 +1,8 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <ranges>
|
||||||
|
|
||||||
class IStoryDb
|
class IStoryDb
|
||||||
{
|
{
|
||||||
|
|
@ -19,6 +21,8 @@ public:
|
||||||
|
|
||||||
virtual ~IStoryDb() {}
|
virtual ~IStoryDb() {}
|
||||||
|
|
||||||
|
using ViewType = std::ranges::ref_view<std::vector<IStoryDb::Info>>;
|
||||||
|
|
||||||
|
|
||||||
virtual bool FindStory(const std::string &uuid, Info &info) = 0;
|
virtual bool FindStory(const std::string &uuid, Info &info) = 0;
|
||||||
virtual void AddStory(IStoryDb::Info &info, int origin) = 0;
|
virtual void AddStory(IStoryDb::Info &info, int origin) = 0;
|
||||||
|
|
|
||||||
|
|
@ -169,6 +169,20 @@ void StoryProject::DeleteNode(const std::string_view &page_uuid, const std::stri
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<StoryPage> StoryProject::GetPage(const std::string &uuid)
|
||||||
|
{
|
||||||
|
for (const auto & p : m_pages)
|
||||||
|
{
|
||||||
|
if (p->Uuid() == uuid)
|
||||||
|
{
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
void StoryProject::DeleteLink(const std::string_view &page_uuid, std::shared_ptr<Connection> c)
|
void StoryProject::DeleteLink(const std::string_view &page_uuid, std::shared_ptr<Connection> c)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -114,6 +114,7 @@ public:
|
||||||
|
|
||||||
void SetTitleImage(const std::string &titleImage);
|
void SetTitleImage(const std::string &titleImage);
|
||||||
void SetTitleSound(const std::string &titleSound);
|
void SetTitleSound(const std::string &titleSound);
|
||||||
|
void SetDescription(const std::string &description) { m_description = description; }
|
||||||
|
|
||||||
std::string GetTitleImage() const { return m_titleImage; }
|
std::string GetTitleImage() const { return m_titleImage; }
|
||||||
std::string GetTitleSound() const { return m_titleSound; }
|
std::string GetTitleSound() const { return m_titleSound; }
|
||||||
|
|
@ -130,6 +131,8 @@ public:
|
||||||
|
|
||||||
// Node interaction
|
// Node interaction
|
||||||
std::shared_ptr<StoryPage> CreatePage(const std::string &uuid);
|
std::shared_ptr<StoryPage> CreatePage(const std::string &uuid);
|
||||||
|
std::shared_ptr<StoryPage> GetPage(const std::string &uuid);
|
||||||
|
|
||||||
std::shared_ptr<BaseNode> CreateNode(const std::string_view &page, const std::string &type);
|
std::shared_ptr<BaseNode> CreateNode(const std::string_view &page, const std::string &type);
|
||||||
void AddConnection(const std::string_view &page, std::shared_ptr<Connection> c);
|
void AddConnection(const std::string_view &page, std::shared_ptr<Connection> c);
|
||||||
void DeleteNode(const std::string_view &page, const std::string &id);
|
void DeleteNode(const std::string_view &page, const std::string &id);
|
||||||
|
|
|
||||||
|
|
@ -245,6 +245,8 @@ void LibraryManager::ParseCommercialStore(const std::string &jsonFileName)
|
||||||
const auto& response = j["response"];
|
const auto& response = j["response"];
|
||||||
m_storyDb.ClearCommercial();
|
m_storyDb.ClearCommercial();
|
||||||
|
|
||||||
|
std::cout << "Found " << response.size() << " commercial stories" << std::endl;
|
||||||
|
|
||||||
for (auto it = response.begin(); it != response.end(); ++it)
|
for (auto it = response.begin(); it != response.end(); ++it)
|
||||||
{
|
{
|
||||||
const auto& pack = it.value();
|
const auto& pack = it.value();
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,11 @@ struct Media {
|
||||||
class ResourceManager
|
class ResourceManager
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
enum KindOfInfo {
|
||||||
|
InfoFormat = 0, // mp3, jpg ...
|
||||||
|
InfoType = 1, // image or sound
|
||||||
|
};
|
||||||
|
|
||||||
ResourceManager(ILogger &log)
|
ResourceManager(ILogger &log)
|
||||||
: m_log(log)
|
: m_log(log)
|
||||||
, m_images(filter("image"))
|
, m_images(filter("image"))
|
||||||
|
|
|
||||||
|
|
@ -34,10 +34,18 @@ include(cmake/CPM.cmake)
|
||||||
# =========================================================================================================================
|
# =========================================================================================================================
|
||||||
# MBedTLS
|
# MBedTLS
|
||||||
# =========================================================================================================================
|
# =========================================================================================================================
|
||||||
CPMAddPackage("gh:Mbed-TLS/mbedtls#v3.6.2")
|
CPMAddPackage(
|
||||||
|
NAME mbedtls
|
||||||
|
GITHUB_REPOSITORY Mbed-TLS/mbedtls
|
||||||
|
VERSION 3.6.2
|
||||||
|
OPTIONS
|
||||||
|
"USE_STATIC_MBEDTLS_LIBRARY ON"
|
||||||
|
"ENABLE_PROGRAMS OFF"
|
||||||
|
"ENABLE_TESTING OFF"
|
||||||
|
)
|
||||||
|
|
||||||
find_package(MbedTLS REQUIRED)
|
find_package(MbedTLS REQUIRED)
|
||||||
include_directories(${MbedTLS_INCLUDE_DIR})
|
include_directories(${mbedtls_INCLUDE_DIR})
|
||||||
# set(MBEDTLS_STATIC_LIBRARY ON)
|
# set(MBEDTLS_STATIC_LIBRARY ON)
|
||||||
|
|
||||||
# =========================================================================================================================
|
# =========================================================================================================================
|
||||||
|
|
@ -336,7 +344,7 @@ if(UNIX)
|
||||||
SDL3_image::SDL3_image
|
SDL3_image::SDL3_image
|
||||||
SDL3_mixer::SDL3_mixer
|
SDL3_mixer::SDL3_mixer
|
||||||
libcurl_static
|
libcurl_static
|
||||||
MbedTLS::mbedtls
|
mbedtls
|
||||||
civetweb-cpp
|
civetweb-cpp
|
||||||
pthread
|
pthread
|
||||||
OpenGL::GL
|
OpenGL::GL
|
||||||
|
|
|
||||||
|
|
@ -136,7 +136,7 @@ void PackArchive::DecipherFiles(const std::string &directory, const std::string
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::string> PackArchive::FilesToJson(const std::string &type, const uint8_t *data, uint32_t nb_elements)
|
std::vector<std::string> PackArchive::FilesInMemory(const std::string &type, const uint8_t *data, uint32_t nb_elements)
|
||||||
{
|
{
|
||||||
char res_file[13]; // 12 + \0
|
char res_file[13]; // 12 + \0
|
||||||
std::vector<std::string> resList;
|
std::vector<std::string> resList;
|
||||||
|
|
@ -150,111 +150,75 @@ std::vector<std::string> PackArchive::FilesToJson(const std::string &type, const
|
||||||
SysLib::ReplaceCharacter(res_file_string, "\\", "/");
|
SysLib::ReplaceCharacter(res_file_string, "\\", "/");
|
||||||
|
|
||||||
resList.push_back(res_file_string);
|
resList.push_back(res_file_string);
|
||||||
|
|
||||||
m_resources[type + std::to_string(i)] = res_file_string;
|
|
||||||
}
|
}
|
||||||
return resList;
|
return resList;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PackArchive::ImportCommercialFormat(const std::string &packFileName, const std::string &outputDir)
|
void PackArchive::ConvertCommercialFormat(StoryProject &proj, const std::string &basePath)
|
||||||
{
|
{
|
||||||
auto uuid = Uuid().String();
|
ResourceManager res(m_log);
|
||||||
std::string basePath = outputDir + "/" + uuid;
|
|
||||||
|
|
||||||
Unzip(packFileName, basePath);
|
|
||||||
LoadNiFile(packFileName);
|
|
||||||
|
|
||||||
std::string path = basePath + "/" + mPackName + "/rf";
|
|
||||||
for (const auto & entry : std::filesystem::directory_iterator(path))
|
|
||||||
{
|
|
||||||
if (entry.is_directory())
|
|
||||||
{
|
|
||||||
std::cout << entry.path() << std::endl;
|
|
||||||
DecipherFiles(entry.path().generic_string(), ".bmp");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
path = basePath + "/" + mPackName + "/sf";
|
|
||||||
for (const auto & entry : std::filesystem::directory_iterator(path))
|
|
||||||
{
|
|
||||||
if (entry.is_directory())
|
|
||||||
{
|
|
||||||
std::cout << entry.path() << std::endl;
|
|
||||||
DecipherFiles(entry.path().generic_string(), ".mp3");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
nlohmann::json j;
|
|
||||||
|
|
||||||
std::ofstream chip32("pack.chip32");
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
$imageBird DC8 "example.bmp", 8 ; data
|
|
||||||
$someConstant DC32 12456789
|
|
||||||
|
|
||||||
; DSxx to declare a variable in RAM, followed by the number of elements
|
|
||||||
$RamData1 DV32 1 ; one 32-bit integer
|
|
||||||
$MyArray DV8 10 ; array of 10 bytes
|
|
||||||
|
|
||||||
; label definition
|
|
||||||
.entry: ;; comment here should work
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
// RI file is not ciphered
|
// RI file is not ciphered
|
||||||
uint8_t data[512];
|
uint8_t data[512];
|
||||||
uint32_t size = ni_get_ri_block(data);
|
uint32_t size = ni_get_ri_block(data);
|
||||||
// WriteDataOnDisk(mPackName + "/ri", data, size);
|
|
||||||
|
|
||||||
StoryProject proj(m_log);
|
auto page = proj.GetPage(proj.MainUuid());
|
||||||
ResourceManager res(m_log);
|
|
||||||
|
|
||||||
std::shared_ptr<StoryPage> page = proj.CreatePage(proj.MainUuid());
|
// Images resources
|
||||||
|
|
||||||
|
|
||||||
proj.New(uuid, outputDir);
|
|
||||||
proj.SetName(j["title"].get<std::string>());
|
|
||||||
|
|
||||||
nlohmann::json jsonImages;
|
|
||||||
{
|
{
|
||||||
|
std::vector<std::string> lst = FilesInMemory("ri", data, mNiFile.image_assets_count);
|
||||||
std::vector<std::string> lst = FilesToJson("ri", data, mNiFile.image_assets_count);
|
|
||||||
|
|
||||||
for (auto &l : lst)
|
for (auto &l : lst)
|
||||||
{
|
{
|
||||||
nlohmann::json obj;
|
// Le path est de la forme "000/AE123245" où 000 est un répertoire
|
||||||
obj["file"] = l;
|
|
||||||
obj["description"] = "";
|
auto rData = std::make_shared<Resource>();
|
||||||
obj["format"] = "bmp";
|
|
||||||
jsonImages.push_back(obj);
|
// origin
|
||||||
|
auto from = std::filesystem::path(basePath) / mPackName / "rf" / l;
|
||||||
|
from += ".bmp";
|
||||||
|
|
||||||
|
// destination
|
||||||
|
auto filename = SysLib::GetFileName(l) + ".bmp";
|
||||||
|
auto to = proj.AssetsPath() / filename;
|
||||||
|
|
||||||
|
rData->file = filename;
|
||||||
|
rData->type = ResourceManager::ExtentionInfo(rData->file, ResourceManager::InfoType);
|
||||||
|
rData->format = ResourceManager::ExtentionInfo(rData->file, ResourceManager::InfoFormat);
|
||||||
|
res.Add(rData);
|
||||||
|
|
||||||
|
std::filesystem::copy(from, to, std::filesystem::copy_options::overwrite_existing);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
j["images"] = jsonImages;
|
|
||||||
|
|
||||||
size = ni_get_si_block(data);
|
size = ni_get_si_block(data);
|
||||||
// WriteDataOnDisk(mPackName + "/si", data, size);
|
|
||||||
|
|
||||||
|
// Sound files
|
||||||
nlohmann::json jsonSounds;
|
|
||||||
{
|
{
|
||||||
nlohmann::json obj;
|
std::vector<std::string> lst = FilesInMemory("si", data, mNiFile.sound_assets_count);
|
||||||
std::vector<std::string> lst = FilesToJson("si", data, mNiFile.sound_assets_count);
|
|
||||||
|
|
||||||
for (auto &l : lst)
|
for (auto &l : lst)
|
||||||
{
|
{
|
||||||
nlohmann::json obj;
|
auto rData = std::make_shared<Resource>();
|
||||||
obj["file"] = l;
|
|
||||||
obj["description"] = "";
|
// origin
|
||||||
obj["format"] = "mp3";
|
auto from = std::filesystem::path(basePath) / mPackName / "sf" / l;
|
||||||
jsonSounds.push_back(obj);
|
from += ".mp3";
|
||||||
|
|
||||||
|
// destination
|
||||||
|
auto filename = SysLib::GetFileName(l) + ".mp3";
|
||||||
|
auto to = proj.AssetsPath() / filename;
|
||||||
|
|
||||||
|
rData->file = filename;
|
||||||
|
rData->type = ResourceManager::ExtentionInfo(rData->file, ResourceManager::InfoType);
|
||||||
|
rData->format = ResourceManager::ExtentionInfo(rData->file, ResourceManager::InfoFormat);
|
||||||
|
res.Add(rData);
|
||||||
|
|
||||||
|
std::filesystem::copy(from, to, std::filesystem::copy_options::overwrite_existing);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
j["sounds"] = jsonSounds;
|
|
||||||
|
|
||||||
size = ni_get_li_block(data);
|
size = ni_get_li_block(data);
|
||||||
// WriteDataOnDisk(mPackName + "/li", data, size);
|
|
||||||
|
|
||||||
|
|
||||||
std::vector<uint32_t> transitions;
|
std::vector<uint32_t> transitions;
|
||||||
// each entry of the transitions array is a 32-bit integer
|
// each entry of the transitions array is a 32-bit integer
|
||||||
|
|
@ -264,87 +228,89 @@ $MyArray DV8 10 ; array of 10 bytes
|
||||||
i += 4;
|
i += 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Transform into JSON
|
node_info_t node_info;
|
||||||
node_info_t node;
|
|
||||||
nlohmann::json jsonNodes;
|
// key: node index, value: node uuidV4
|
||||||
|
std::map<int, std::string> nodeIds;
|
||||||
|
|
||||||
|
// key: node index, value: list of transitions
|
||||||
|
std::map<int, std::vector<uint32_t>> nodeTransitions;
|
||||||
|
|
||||||
for (int i = 0; i < mNiFile.node_size; i++)
|
for (int i = 0; i < mNiFile.node_size; i++)
|
||||||
{
|
{
|
||||||
nlohmann::json jNode;
|
ni_get_node_info(i, &node_info);
|
||||||
ni_get_node_info(i, &node);
|
|
||||||
|
|
||||||
jNode["id"] = i;
|
auto node = proj.CreateNode(proj.MainUuid(), "media-node");
|
||||||
jNode["image"] = static_cast<int>(node.current->image_asset_index_in_ri);
|
|
||||||
jNode["sound"] = static_cast<int>(node.current->sound_asset_index_in_si);
|
|
||||||
jNode["auto_jump"] = node.current->auto_play == 1 ? true : false;
|
|
||||||
|
|
||||||
nlohmann::json jumpArray;
|
if (node)
|
||||||
|
|
||||||
for (int jIndex = 0; jIndex < node.current->ok_transition_number_of_options; jIndex++)
|
|
||||||
{
|
{
|
||||||
jumpArray.push_back(transitions[node.current->ok_transition_action_node_index_in_li + jIndex]);
|
// On sauvegarde la relation entre l'index du noeud et son UUID
|
||||||
}
|
nodeIds[i] = node->GetId();
|
||||||
|
|
||||||
jNode["jumps"] = jumpArray;
|
node->SetPosition(80 * i, 80 * i);
|
||||||
|
|
||||||
// Autre cas
|
nlohmann::json internalData;
|
||||||
if (node.current->ok_transition_number_of_options >= 5)
|
auto img = SysLib::GetFileName(node_info.ri_file);
|
||||||
{
|
auto snd = SysLib::GetFileName(node_info.si_file);
|
||||||
// For now, consider that this is a bad format
|
internalData["image"] = img.size() > 0 ? img + ".bmp" : "";
|
||||||
// In the future, consider using ok_transition_selected_option_index when ok_transition_number_of_options == 10
|
internalData["sound"] = snd.size() > 0 ? snd + ".mp3" : "";
|
||||||
|
|
||||||
// 00 00 00 00 ==> ok transition à zéro
|
node->SetInternalData(internalData);
|
||||||
// 0A 00 00 00 ==> nombre spécial, ou vraiment l'offset dans le fichier LI ?
|
|
||||||
// 01 00 00 00 ==> l'index dans le fichier LI à l'offset (disons, le premier élément)
|
|
||||||
|
|
||||||
|
std::vector<uint32_t> jumpArray;
|
||||||
|
|
||||||
std::cout << "!!!!!!!!!!!!!!!!!!" << std::endl;
|
// Autre cas
|
||||||
}
|
if (node_info.current->ok_transition_number_of_options == 10)
|
||||||
|
|
||||||
chip32 << ".node" << std::to_string(i) << ":\r\n";
|
|
||||||
if (node.current->image_asset_index_in_ri != 0xFFFFFFFF)
|
|
||||||
{
|
|
||||||
// Image index is in register R0
|
|
||||||
chip32 << "\tmov " << "r0, " << "$ri" << std::to_string(node.current->image_asset_index_in_ri) << "\r\n";
|
|
||||||
// print image syscall
|
|
||||||
chip32 << "\tsyscall 1\r\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (node.current->sound_asset_index_in_si != 0xFFFFFFFF)
|
|
||||||
{
|
|
||||||
// Image index is in register R0
|
|
||||||
chip32 << "\tmov " << "r0, " << "$si" << std::to_string(node.current->sound_asset_index_in_si) << "\r\n";
|
|
||||||
// print image syscall
|
|
||||||
chip32 << "\tsyscall 2\r\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
chip32 << "$li" << std::to_string(i) << " DC8 ";
|
|
||||||
size = ni_get_li_block(data);
|
|
||||||
for (int tr = 0; tr < node.current->ok_transition_number_of_options; tr++)
|
|
||||||
{
|
|
||||||
uint32_t val = leu32_get(&data[(node.current->ok_transition_action_node_index_in_li + tr) * 4]);
|
|
||||||
chip32 << std::to_string(val);
|
|
||||||
|
|
||||||
if (tr < (node.current->ok_transition_number_of_options - 1))
|
|
||||||
{
|
{
|
||||||
chip32 << ", ";
|
// For now, consider that this is a bad format
|
||||||
|
// In the future, consider using ok_transition_selected_option_index when ok_transition_number_of_options == 10
|
||||||
|
|
||||||
|
// 00 00 00 00 ==> ok transition à zéro
|
||||||
|
// 0A 00 00 00 ==> nombre spécial, ou vraiment l'offset dans le fichier LI ?
|
||||||
|
// 01 00 00 00 ==> l'index dans le fichier LI à l'offset (disons, le premier élément)
|
||||||
|
|
||||||
|
|
||||||
|
jumpArray.push_back(transitions[node_info.current->ok_transition_action_node_index_in_li]);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Vraies transitions
|
||||||
|
for (int jIndex = 0; jIndex < node_info.current->ok_transition_number_of_options; jIndex++)
|
||||||
|
{
|
||||||
|
jumpArray.push_back(transitions[node_info.current->ok_transition_action_node_index_in_li + jIndex]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
nodeTransitions[i] = jumpArray;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::cout << "Node not created" << std::endl;
|
||||||
|
m_log.Log("Node not created");
|
||||||
}
|
}
|
||||||
chip32 << "\r\n";
|
|
||||||
|
|
||||||
chip32 << "\tsyscall 3\r\n"; // wait select
|
|
||||||
|
|
||||||
// TODO: tester le retour d'un wait event
|
|
||||||
|
|
||||||
jsonNodes.push_back(jNode);
|
|
||||||
}
|
}
|
||||||
j["nodes"] = jsonNodes;
|
|
||||||
j["code"] = mPackName;
|
|
||||||
j["name"] = "";
|
|
||||||
j["type"] = "lunii";
|
|
||||||
|
|
||||||
|
// Create links, parse again the nodes
|
||||||
|
for (int i = 0; i < mNiFile.node_size; i++)
|
||||||
|
{
|
||||||
|
|
||||||
|
for (auto &j : nodeTransitions[i])
|
||||||
|
{
|
||||||
|
auto c = std::make_shared<Connection>();
|
||||||
|
|
||||||
|
c->outNodeId = nodeIds[i];
|
||||||
|
c->outPortIndex = 0;
|
||||||
|
c->inNodeId = nodeIds[j];
|
||||||
|
c->inPortIndex = 0;
|
||||||
|
|
||||||
|
page->AddLink(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
proj.Save(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool PackArchive::LoadNiFile(const std::string &filePath)
|
bool PackArchive::LoadNiFile(const std::string &filePath)
|
||||||
{
|
{
|
||||||
bool success = false;
|
bool success = false;
|
||||||
|
|
@ -411,12 +377,11 @@ bool PackArchive::ConvertJsonStudioToOst(const std::string &basePath, const std:
|
||||||
{
|
{
|
||||||
if (std::filesystem::is_regular_file(entry.path()))
|
if (std::filesystem::is_regular_file(entry.path()))
|
||||||
{
|
{
|
||||||
// Si c'est un sous-répertoire, récursivement scanner le contenu
|
|
||||||
auto rData = std::make_shared<Resource>();
|
auto rData = std::make_shared<Resource>();
|
||||||
|
|
||||||
rData->file = entry.path().filename().generic_string();
|
rData->file = entry.path().filename().generic_string();
|
||||||
rData->type = ResourceManager::ExtentionInfo(entry.path().extension().generic_string(), 1);
|
rData->type = ResourceManager::ExtentionInfo(entry.path().extension().generic_string(), ResourceManager::InfoType);
|
||||||
rData->format = ResourceManager::ExtentionInfo(entry.path().extension().generic_string(), 0);
|
rData->format = ResourceManager::ExtentionInfo(entry.path().extension().generic_string(), ResourceManager::InfoFormat);
|
||||||
res.Add(rData);
|
res.Add(rData);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,17 @@
|
||||||
#ifndef PACK_ARCHIVE_H
|
#ifndef PACK_ARCHIVE_H
|
||||||
#define PACK_ARCHIVE_H
|
#define PACK_ARCHIVE_H
|
||||||
|
|
||||||
|
#include <ranges>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include "zip.h"
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include "zip.h"
|
||||||
#include "ni_parser.h"
|
#include "ni_parser.h"
|
||||||
#include "json.hpp"
|
#include "json.hpp"
|
||||||
|
#include "uuid.h"
|
||||||
#include "i_logger.h"
|
#include "i_logger.h"
|
||||||
|
#include "i_story_db.h"
|
||||||
|
#include "story_project.h"
|
||||||
|
|
||||||
class PackArchive
|
class PackArchive
|
||||||
{
|
{
|
||||||
|
|
@ -17,7 +22,59 @@ public:
|
||||||
std::string OpenImage(const std::string &fileName);
|
std::string OpenImage(const std::string &fileName);
|
||||||
|
|
||||||
bool ImportStudioFormat(const std::string &fileName, const std::string &outputDir);
|
bool ImportStudioFormat(const std::string &fileName, const std::string &outputDir);
|
||||||
void ImportCommercialFormat(const std::string &packFileName, const std::string &outputDir);
|
|
||||||
|
template<typename Range>
|
||||||
|
// requires std::ranges::range<Range>
|
||||||
|
void ImportCommercialFormat(const std::string &packFileName, const std::string &outputDir, Range&& range)
|
||||||
|
{
|
||||||
|
auto uuid = Uuid().String();
|
||||||
|
std::string basePath = outputDir + "/" + uuid;
|
||||||
|
|
||||||
|
Unzip(packFileName, basePath);
|
||||||
|
LoadNiFile(packFileName);
|
||||||
|
|
||||||
|
StoryProject proj(m_log);
|
||||||
|
proj.New(uuid, outputDir);
|
||||||
|
|
||||||
|
auto packUuidv4 = normalizeUUID(mPackName);
|
||||||
|
for (auto &info : range)
|
||||||
|
{
|
||||||
|
std::cout << info.uuid << std::endl;
|
||||||
|
if (info.uuid == packUuidv4)
|
||||||
|
{
|
||||||
|
m_log.Log("Found commercial story: " + info.title);
|
||||||
|
proj.SetName(info.title);
|
||||||
|
proj.SetDescription(info.description);
|
||||||
|
|
||||||
|
// FIXME: download image and sound
|
||||||
|
proj.SetTitleImage(info.image_url);
|
||||||
|
proj.SetTitleSound(info.sound);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string path = basePath + "/" + mPackName + "/rf";
|
||||||
|
for (const auto & entry : std::filesystem::directory_iterator(path))
|
||||||
|
{
|
||||||
|
if (entry.is_directory())
|
||||||
|
{
|
||||||
|
std::cout << entry.path() << std::endl;
|
||||||
|
DecipherFiles(entry.path().generic_string(), ".bmp");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
path = basePath + "/" + mPackName + "/sf";
|
||||||
|
for (const auto & entry : std::filesystem::directory_iterator(path))
|
||||||
|
{
|
||||||
|
if (entry.is_directory())
|
||||||
|
{
|
||||||
|
std::cout << entry.path() << std::endl;
|
||||||
|
DecipherFiles(entry.path().generic_string(), ".mp3");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ConvertCommercialFormat(proj, basePath);
|
||||||
|
}
|
||||||
|
|
||||||
std::string CurrentImage();
|
std::string CurrentImage();
|
||||||
std::string CurrentSound();
|
std::string CurrentSound();
|
||||||
|
|
@ -46,16 +103,36 @@ private:
|
||||||
node_info_t mCurrentNode;
|
node_info_t mCurrentNode;
|
||||||
ni_file_t mNiFile;
|
ni_file_t mNiFile;
|
||||||
|
|
||||||
// key: resource tag
|
void ConvertCommercialFormat(StoryProject &proj, const std::string &basePath);
|
||||||
// value: resource file name
|
|
||||||
std::map<std::string, std::string> m_resources;
|
|
||||||
|
|
||||||
bool ParseNIFile(const std::string &root);
|
bool ParseNIFile(const std::string &root);
|
||||||
|
|
||||||
|
// Convertit un UUID de type "3ADE540306254FFFA22B9025AC3678D9"
|
||||||
|
// en standard : 3ade5403-0625-4fff-a22b-9025ac3678d9
|
||||||
|
std::string normalizeUUID(const std::string& uuid) {
|
||||||
|
// Check if the input length is correct for a UUID without dashes
|
||||||
|
if (uuid.length() != 32) {
|
||||||
|
throw std::invalid_argument("Invalid UUID length");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert to lowercase
|
||||||
|
std::string lowerUuid = uuid;
|
||||||
|
std::transform(lowerUuid.begin(), lowerUuid.end(), lowerUuid.begin(), ::tolower);
|
||||||
|
|
||||||
|
// Insert dashes at appropriate positions
|
||||||
|
std::ostringstream oss;
|
||||||
|
oss << lowerUuid.substr(0, 8) << '-'
|
||||||
|
<< lowerUuid.substr(8, 4) << '-'
|
||||||
|
<< lowerUuid.substr(12, 4) << '-'
|
||||||
|
<< lowerUuid.substr(16, 4) << '-'
|
||||||
|
<< lowerUuid.substr(20);
|
||||||
|
|
||||||
|
return oss.str();
|
||||||
|
}
|
||||||
|
|
||||||
void DecipherFileOnDisk(const std::string &fileName);
|
void DecipherFileOnDisk(const std::string &fileName);
|
||||||
void DecipherFiles(const std::string &directory, const std::string &suffix);
|
void DecipherFiles(const std::string &directory, const std::string &suffix);
|
||||||
std::vector<std::string> FilesToJson(const std::string &type, const uint8_t *data, uint32_t nb_elements);
|
std::vector<std::string> FilesInMemory(const std::string &type, const uint8_t *data, uint32_t nb_elements);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // PACK_ARCHIVE_H
|
#endif // PACK_ARCHIVE_H
|
||||||
|
|
|
||||||
|
|
@ -803,7 +803,7 @@ void MainWindow::ImportProject(const std::string &fileName, int format)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
archive.ImportCommercialFormat(fileName, m_libraryManager.LibraryPath());
|
archive.ImportCommercialFormat(fileName, m_libraryManager.LibraryPath(), m_libraryManager.CommercialDbView());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue