mirror of
https://github.com/AxioDL/metaforce.git
synced 2025-12-08 14:24:56 +00:00
Integrate Amuse into hecl cook/extract for MP1/2
This commit is contained in:
@@ -1,92 +1,82 @@
|
||||
#include "AGSC.hpp"
|
||||
#include "amuse/AudioGroup.hpp"
|
||||
#include "amuse/AudioGroupData.hpp"
|
||||
|
||||
namespace DataSpec::DNAMP2
|
||||
{
|
||||
|
||||
bool AGSC::Extract(PAKEntryReadStream& rs, const hecl::ProjectPath& outPath)
|
||||
bool AGSC::Extract(PAKEntryReadStream& rs, const hecl::ProjectPath& dir)
|
||||
{
|
||||
dir.makeDirChain(true);
|
||||
|
||||
Header head;
|
||||
head.read(rs);
|
||||
|
||||
auto pool = rs.readUBytes(head.poolSz);
|
||||
auto proj = rs.readUBytes(head.projSz);
|
||||
auto sdir = rs.readUBytes(head.sdirSz);
|
||||
auto samp = rs.readUBytes(head.sampSz);
|
||||
|
||||
amuse::AudioGroupData data(proj.get(), head.projSz, pool.get(), head.poolSz,
|
||||
sdir.get(), head.sdirSz, samp.get(), head.sampSz, amuse::GCNDataTag{});
|
||||
|
||||
/* Load into amuse representation */
|
||||
amuse::ProjectDatabase projDb;
|
||||
projDb.setIdDatabases();
|
||||
amuse::AudioGroupDatabase group(data);
|
||||
group.setGroupPath(dir.getAbsolutePath());
|
||||
|
||||
/* Extract samples */
|
||||
group.getSdir().extractAllCompressed(dir.getAbsolutePath(), data.getSamp());
|
||||
|
||||
/* Write out project/pool */
|
||||
{
|
||||
hecl::ProjectPath poolPath = outPath.getWithExtension(_S(".pool"), true);
|
||||
athena::io::FileWriter w(poolPath.getAbsolutePath());
|
||||
w.writeBytes(rs.readBytes(head.poolSz).get(), head.poolSz);
|
||||
auto projd = group.getProj().toYAML();
|
||||
athena::io::FileWriter fo(hecl::ProjectPath(dir, _S("!project.yaml")).getAbsolutePath());
|
||||
if (fo.hasError())
|
||||
return false;
|
||||
fo.writeUBytes(projd.data(), projd.size());
|
||||
}
|
||||
|
||||
{
|
||||
hecl::ProjectPath projPath = outPath.getWithExtension(_S(".proj"), true);
|
||||
athena::io::FileWriter w(projPath.getAbsolutePath());
|
||||
w.writeBytes(rs.readBytes(head.projSz).get(), head.projSz);
|
||||
}
|
||||
|
||||
{
|
||||
hecl::ProjectPath sdirPath = outPath.getWithExtension(_S(".sdir"), true);
|
||||
athena::io::FileWriter w(sdirPath.getAbsolutePath());
|
||||
w.writeBytes(rs.readBytes(head.sdirSz).get(), head.sdirSz);
|
||||
}
|
||||
|
||||
{
|
||||
hecl::ProjectPath sampPath = outPath.getWithExtension(_S(".samp"), true);
|
||||
athena::io::FileWriter w(sampPath.getAbsolutePath());
|
||||
w.writeBytes(rs.readBytes(head.sampSz).get(), head.sampSz);
|
||||
auto poold = group.getPool().toYAML();
|
||||
athena::io::FileWriter fo(hecl::ProjectPath(dir, _S("!pool.yaml")).getAbsolutePath());
|
||||
if (fo.hasError())
|
||||
return false;
|
||||
fo.writeUBytes(poold.data(), poold.size());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AGSC::Cook(const hecl::ProjectPath& inPath, const hecl::ProjectPath& outPath)
|
||||
bool AGSC::Cook(const hecl::ProjectPath& dir, const hecl::ProjectPath& outPath)
|
||||
{
|
||||
athena::io::FileWriter w(outPath.getAbsolutePath());
|
||||
if (w.hasError())
|
||||
return false;
|
||||
|
||||
hecl::ProjectPath woExt = inPath.getWithExtension(nullptr, true);
|
||||
std::string lastComp = std::string(woExt.getLastComponentUTF8());
|
||||
if (hecl::StringUtils::EndsWith(lastComp, "_AGSC"))
|
||||
lastComp.assign(lastComp.cbegin(), lastComp.cend() - 5);
|
||||
amuse::ProjectDatabase projDb;
|
||||
projDb.setIdDatabases();
|
||||
amuse::AudioGroupDatabase group(dir.getAbsolutePath());
|
||||
|
||||
hecl::ProjectPath poolPath = inPath.getWithExtension(_S(".pool"), true);
|
||||
athena::io::FileReader poolR(poolPath.getAbsolutePath());
|
||||
if (poolR.hasError())
|
||||
return false;
|
||||
uint32_t poolLen = poolR.length();
|
||||
|
||||
hecl::ProjectPath projPath = inPath.getWithExtension(_S(".proj"), true);
|
||||
athena::io::FileReader projR(projPath.getAbsolutePath());
|
||||
if (projR.hasError())
|
||||
return false;
|
||||
uint32_t projLen = projR.length();
|
||||
|
||||
hecl::ProjectPath sdirPath = inPath.getWithExtension(_S(".sdir"), true);
|
||||
athena::io::FileReader sdirR(sdirPath.getAbsolutePath());
|
||||
if (sdirR.hasError())
|
||||
return false;
|
||||
uint32_t sdirLen = sdirR.length();
|
||||
|
||||
hecl::ProjectPath sampPath = inPath.getWithExtension(_S(".samp"), true);
|
||||
athena::io::FileReader sampR(sampPath.getAbsolutePath());
|
||||
if (sampR.hasError())
|
||||
return false;
|
||||
uint32_t sampLen = sampR.length();
|
||||
|
||||
projR.seek(4, athena::SeekOrigin::Begin);
|
||||
uint16_t groupId = projR.readUint16Big();
|
||||
projR.seek(0, athena::SeekOrigin::Begin);
|
||||
auto proj = group.getProj().toGCNData(group.getPool(), group.getSdir());
|
||||
auto pool = group.getPool().toData<athena::Big>();
|
||||
auto sdirSamp = group.getSdir().toGCNData(group);
|
||||
|
||||
Header head;
|
||||
head.groupName = lastComp;
|
||||
head.groupId = groupId;
|
||||
head.poolSz = poolLen;
|
||||
head.projSz = projLen;
|
||||
head.sdirSz = sdirLen;
|
||||
head.sampSz = sampLen;
|
||||
head.groupName = dir.getLastComponentUTF8();
|
||||
for (const auto& p : group.getProj().sfxGroups())
|
||||
head.groupId = p.first.id;
|
||||
head.poolSz = pool.size();
|
||||
head.projSz = proj.size();
|
||||
head.sdirSz = sdirSamp.first.size();
|
||||
head.sampSz = sdirSamp.second.size();
|
||||
head.write(w);
|
||||
|
||||
w.writeBytes(poolR.readBytes(poolLen).get(), poolLen);
|
||||
w.writeBytes(projR.readBytes(projLen).get(), projLen);
|
||||
w.writeBytes(sdirR.readBytes(sdirLen).get(), sdirLen);
|
||||
w.writeBytes(sampR.readBytes(sampLen).get(), sampLen);
|
||||
w.writeUBytes(pool.data(), pool.size());
|
||||
w.writeUBytes(proj.data(), proj.size());
|
||||
w.writeUBytes(sdirSamp.first.data(), sdirSamp.first.size());
|
||||
w.writeUBytes(sdirSamp.second.data(), sdirSamp.second.size());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ namespace DataSpec::DNAMP2
|
||||
|
||||
class AGSC
|
||||
{
|
||||
public:
|
||||
struct Header : BigDNA
|
||||
{
|
||||
AT_DECL_DNA
|
||||
@@ -20,7 +21,6 @@ class AGSC
|
||||
Value<atUint32> sdirSz = 0;
|
||||
Value<atUint32> sampSz = 0;
|
||||
};
|
||||
public:
|
||||
static bool Extract(PAKEntryReadStream& rs, const hecl::ProjectPath& outPath);
|
||||
static bool Cook(const hecl::ProjectPath& inPath, const hecl::ProjectPath& outPath);
|
||||
};
|
||||
|
||||
@@ -221,7 +221,7 @@ struct ANCS : BigDNA
|
||||
PAKEntryReadStream& rs,
|
||||
const hecl::ProjectPath& outPath,
|
||||
PAKRouter<PAKBridge>& pakRouter,
|
||||
const DNAMP1::PAK::Entry& entry,
|
||||
const DNAMP2::PAK::Entry& entry,
|
||||
bool force,
|
||||
hecl::blender::Token& btok,
|
||||
std::function<void(const hecl::SystemChar*)> fileChanged)
|
||||
|
||||
@@ -8,7 +8,7 @@ bool CMDL::Extract(const SpecBase& dataSpec,
|
||||
PAKEntryReadStream& rs,
|
||||
const hecl::ProjectPath& outPath,
|
||||
PAKRouter<PAKBridge>& pakRouter,
|
||||
const DNAMP1::PAK::Entry& entry,
|
||||
const DNAMP2::PAK::Entry& entry,
|
||||
bool,
|
||||
hecl::blender::Token& btok,
|
||||
std::function<void(const hecl::SystemChar*)>)
|
||||
|
||||
@@ -17,7 +17,7 @@ struct CMDL
|
||||
PAKEntryReadStream& rs,
|
||||
const hecl::ProjectPath& outPath,
|
||||
PAKRouter<PAKBridge>& pakRouter,
|
||||
const DNAMP1::PAK::Entry& entry,
|
||||
const DNAMP2::PAK::Entry& entry,
|
||||
bool,
|
||||
hecl::blender::Token& btok,
|
||||
std::function<void(const hecl::SystemChar*)>);
|
||||
|
||||
@@ -13,6 +13,7 @@ make_dnalist(liblist DNAMP2
|
||||
set(DNAMP2_SOURCES
|
||||
DNAMP2.hpp DNAMP2.cpp
|
||||
DeafBabe.cpp
|
||||
PAK.cpp
|
||||
ANIM.cpp
|
||||
AGSC.cpp
|
||||
CINF.cpp
|
||||
|
||||
@@ -42,13 +42,13 @@ PAKBridge::PAKBridge(const nod::Node& node,
|
||||
/* Append Level String */
|
||||
for (const auto& entry : m_pak.m_entries)
|
||||
{
|
||||
const DNAMP1::PAK::Entry& e = entry.second;
|
||||
const DNAMP2::PAK::Entry& e = entry.second;
|
||||
if (e.type == FOURCC('MLVL'))
|
||||
{
|
||||
PAKEntryReadStream rs = e.beginReadStream(m_node);
|
||||
MLVL mlvl;
|
||||
mlvl.read(rs);
|
||||
const DNAMP1::PAK::Entry* nameEnt = m_pak.lookupEntry(mlvl.worldNameId);
|
||||
const DNAMP2::PAK::Entry* nameEnt = m_pak.lookupEntry(mlvl.worldNameId);
|
||||
if (nameEnt)
|
||||
{
|
||||
PAKEntryReadStream rs = nameEnt->beginReadStream(m_node);
|
||||
@@ -76,7 +76,7 @@ void PAKBridge::build()
|
||||
/* First pass: build per-area/per-layer dependency map */
|
||||
for (const auto& entry : m_pak.m_entries)
|
||||
{
|
||||
const DNAMP1::PAK::Entry& e = entry.second;
|
||||
const DNAMP2::PAK::Entry& e = entry.second;
|
||||
if (e.type == FOURCC('MLVL'))
|
||||
{
|
||||
Level& level = m_levelDeps[e.id];
|
||||
@@ -87,13 +87,13 @@ void PAKBridge::build()
|
||||
mlvl.read(rs);
|
||||
}
|
||||
bool named;
|
||||
std::string bestName = m_pak.bestEntryName(e, named);
|
||||
std::string bestName = m_pak.bestEntryName(m_node, e, named);
|
||||
level.name = hecl::SystemStringConv(bestName).sys_str();
|
||||
level.areas.reserve(mlvl.areaCount);
|
||||
unsigned layerIdx = 0;
|
||||
|
||||
/* Make MAPW available to lookup MAPAs */
|
||||
const DNAMP1::PAK::Entry* worldMapEnt = m_pak.lookupEntry(mlvl.worldMap);
|
||||
const DNAMP2::PAK::Entry* worldMapEnt = m_pak.lookupEntry(mlvl.worldMap);
|
||||
std::vector<UniqueID32> mapw;
|
||||
if (worldMapEnt)
|
||||
{
|
||||
@@ -111,7 +111,7 @@ void PAKBridge::build()
|
||||
{
|
||||
Level::Area& areaDeps = level.areas[area.areaMREAId];
|
||||
MLVL::LayerFlags& layerFlags = mlvl.layerFlags[ai];
|
||||
const DNAMP1::PAK::Entry* areaNameEnt = m_pak.lookupEntry(area.areaNameId);
|
||||
const DNAMP2::PAK::Entry* areaNameEnt = m_pak.lookupEntry(area.areaNameId);
|
||||
if (areaNameEnt)
|
||||
{
|
||||
STRG areaName;
|
||||
@@ -173,7 +173,7 @@ void PAKBridge::addCMDLRigPairs(PAKRouter<PAKBridge>& pakRouter,
|
||||
std::unordered_map<UniqueID32, std::pair<UniqueID32, UniqueID32>>& addTo,
|
||||
std::unordered_map<UniqueID32, std::pair<UniqueID32, std::string>>& cskrCinfToAncs) const
|
||||
{
|
||||
for (const std::pair<UniqueID32, DNAMP1::PAK::Entry>& entry : m_pak.m_entries)
|
||||
for (const std::pair<UniqueID32, DNAMP2::PAK::Entry>& entry : m_pak.m_entries)
|
||||
{
|
||||
if (entry.second.type == FOURCC('ANCS'))
|
||||
{
|
||||
@@ -201,7 +201,7 @@ void PAKBridge::addMAPATransforms(PAKRouter<PAKBridge>& pakRouter,
|
||||
std::unordered_map<UniqueID32, zeus::CMatrix4f>& addTo,
|
||||
std::unordered_map<UniqueID32, hecl::ProjectPath>& pathOverrides) const
|
||||
{
|
||||
for (const std::pair<UniqueID32, DNAMP1::PAK::Entry>& entry : m_pak.m_entries)
|
||||
for (const std::pair<UniqueID32, DNAMP2::PAK::Entry>& entry : m_pak.m_entries)
|
||||
{
|
||||
if (entry.second.type == FOURCC('MLVL'))
|
||||
{
|
||||
@@ -225,7 +225,7 @@ void PAKBridge::addMAPATransforms(PAKRouter<PAKBridge>& pakRouter,
|
||||
if (mlvl.worldMap)
|
||||
{
|
||||
const nod::Node* mapNode;
|
||||
const DNAMP1::PAK::Entry* mapEntry = pakRouter.lookupEntry(mlvl.worldMap, &mapNode);
|
||||
const DNAMP2::PAK::Entry* mapEntry = pakRouter.lookupEntry(mlvl.worldMap, &mapNode);
|
||||
if (mapEntry)
|
||||
{
|
||||
PAKEntryReadStream rs = mapEntry->beginReadStream(*mapNode);
|
||||
@@ -252,7 +252,8 @@ void PAKBridge::addMAPATransforms(PAKRouter<PAKBridge>& pakRouter,
|
||||
}
|
||||
}
|
||||
|
||||
ResExtractor<PAKBridge> PAKBridge::LookupExtractor(const DNAMP1::PAK& pak, const DNAMP1::PAK::Entry& entry)
|
||||
ResExtractor<PAKBridge> PAKBridge::LookupExtractor(const nod::Node& pakNode, const DNAMP2::PAK& pak,
|
||||
const DNAMP2::PAK::Entry& entry)
|
||||
{
|
||||
switch (entry.type)
|
||||
{
|
||||
@@ -285,7 +286,7 @@ ResExtractor<PAKBridge> PAKBridge::LookupExtractor(const DNAMP1::PAK& pak, const
|
||||
case SBIG('DGRP'):
|
||||
return {DNADGRP::ExtractDGRP<UniqueID32>, {_S(".yaml")}};
|
||||
case SBIG('AGSC'):
|
||||
return {AGSC::Extract, {_S(".pool"), _S(".proj"), _S(".samp"), _S(".sdir")}};
|
||||
return {AGSC::Extract, {}};
|
||||
case SBIG('CSNG'):
|
||||
return {DNAMP1::CSNG::Extract, {_S(".mid"), _S(".yaml")}};
|
||||
case SBIG('ATBL'):
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#define __DNAMP2_HPP__
|
||||
|
||||
#include "DataSpec/DNACommon/DNACommon.hpp"
|
||||
#include "../DNAMP1/PAK.hpp"
|
||||
#include "PAK.hpp"
|
||||
|
||||
namespace DataSpec::DNAMP2
|
||||
{
|
||||
@@ -13,7 +13,7 @@ extern logvisor::Module Log;
|
||||
class PAKBridge
|
||||
{
|
||||
const nod::Node& m_node;
|
||||
DNAMP1::PAK m_pak;
|
||||
DNAMP2::PAK m_pak;
|
||||
public:
|
||||
bool m_doExtract;
|
||||
using Level = DataSpec::Level<UniqueID32>;
|
||||
@@ -22,11 +22,12 @@ public:
|
||||
|
||||
PAKBridge(const nod::Node& node, bool doExtract=true);
|
||||
void build();
|
||||
static ResExtractor<PAKBridge> LookupExtractor(const DNAMP1::PAK& pak, const DNAMP1::PAK::Entry& entry);
|
||||
static ResExtractor<PAKBridge> LookupExtractor(const nod::Node& pakNode,
|
||||
const DNAMP2::PAK& pak, const DNAMP2::PAK::Entry& entry);
|
||||
std::string_view getName() const {return m_node.getName();}
|
||||
hecl::SystemStringView getLevelString() const {return m_levelString;}
|
||||
|
||||
using PAKType = DNAMP1::PAK;
|
||||
using PAKType = DNAMP2::PAK;
|
||||
const PAKType& getPAK() const {return m_pak;}
|
||||
const nod::Node& getNode() const {return m_node;}
|
||||
|
||||
|
||||
@@ -96,7 +96,7 @@ struct DeafBabe : BigDNA
|
||||
bool surfaceMud() const { return false; }
|
||||
void setSurfaceMud(bool v) {}
|
||||
bool surfaceStoneRock() const { return false; }
|
||||
void setSurfaceStoneRock(bool v) {}
|
||||
void setSurfaceLavaStone(bool v) {}
|
||||
bool solid() const { return false; }
|
||||
void setSolid(bool v) {}
|
||||
bool noPlatformCollision() const { return false; }
|
||||
|
||||
@@ -13,7 +13,7 @@ struct MAPA : DNAMAPA::MAPA
|
||||
PAKEntryReadStream& rs,
|
||||
const hecl::ProjectPath& outPath,
|
||||
PAKRouter<PAKBridge>& pakRouter,
|
||||
const DNAMP1::PAK::Entry& entry,
|
||||
const DNAMP2::PAK::Entry& entry,
|
||||
bool force,
|
||||
hecl::blender::Token& btok,
|
||||
std::function<void(const hecl::SystemChar*)> fileChanged)
|
||||
|
||||
@@ -16,7 +16,7 @@ struct MAPU : DNAMAPU::MAPU
|
||||
PAKEntryReadStream& rs,
|
||||
const hecl::ProjectPath& outPath,
|
||||
PAKRouter<PAKBridge>& pakRouter,
|
||||
const DNAMP1::PAK::Entry& entry,
|
||||
const DNAMP2::PAK::Entry& entry,
|
||||
bool force,
|
||||
hecl::blender::Token& btok,
|
||||
std::function<void(const hecl::SystemChar*)> fileChanged)
|
||||
|
||||
@@ -96,7 +96,7 @@ struct MLVL : BigDNA
|
||||
PAKEntryReadStream& rs,
|
||||
const hecl::ProjectPath& outPath,
|
||||
PAKRouter<PAKBridge>& pakRouter,
|
||||
const DNAMP1::PAK::Entry& entry,
|
||||
const DNAMP2::PAK::Entry& entry,
|
||||
bool force,
|
||||
hecl::blender::Token& btok,
|
||||
std::function<void(const hecl::SystemChar*)> fileChanged)
|
||||
|
||||
@@ -164,7 +164,7 @@ bool MREA::Extract(const SpecBase& dataSpec,
|
||||
PAKEntryReadStream& rs,
|
||||
const hecl::ProjectPath& outPath,
|
||||
PAKRouter<PAKBridge>& pakRouter,
|
||||
const DNAMP1::PAK::Entry& entry,
|
||||
const DNAMP2::PAK::Entry& entry,
|
||||
bool force,
|
||||
hecl::blender::Token& btok,
|
||||
std::function<void(const hecl::SystemChar*)>)
|
||||
|
||||
@@ -119,7 +119,7 @@ struct MREA
|
||||
PAKEntryReadStream& rs,
|
||||
const hecl::ProjectPath& outPath,
|
||||
PAKRouter<PAKBridge>& pakRouter,
|
||||
const DNAMP1::PAK::Entry& entry,
|
||||
const DNAMP2::PAK::Entry& entry,
|
||||
bool,
|
||||
hecl::blender::Token& btok,
|
||||
std::function<void(const hecl::SystemChar*)>);
|
||||
|
||||
23
DataSpec/DNAMP2/PAK.cpp
Normal file
23
DataSpec/DNAMP2/PAK.cpp
Normal file
@@ -0,0 +1,23 @@
|
||||
#include "PAK.hpp"
|
||||
#include "AGSC.hpp"
|
||||
|
||||
namespace DataSpec::DNAMP2
|
||||
{
|
||||
|
||||
std::string PAK::bestEntryName(const nod::Node& pakNode, const Entry& entry, bool& named) const
|
||||
{
|
||||
std::unordered_map<UniqueID32, Entry>::const_iterator search;
|
||||
if (entry.type == FOURCC('AGSC') && (search = m_entries.find(entry.id)) != m_entries.cend())
|
||||
{
|
||||
/* Use internal AGSC name for entry */
|
||||
auto rs = search->second.beginReadStream(pakNode);
|
||||
AGSC::Header header;
|
||||
header.read(rs);
|
||||
named = true;
|
||||
return header.groupName;
|
||||
}
|
||||
|
||||
return DNAMP1::PAK::bestEntryName(pakNode, entry, named);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -3,11 +3,15 @@
|
||||
|
||||
#include "../DNAMP1/PAK.hpp"
|
||||
|
||||
namespace urde::DNAMP2
|
||||
namespace DataSpec::DNAMP2
|
||||
{
|
||||
|
||||
/* Same PAK format as MP1 */
|
||||
using PAK = DNAMP1::PAK;
|
||||
struct PAK : DNAMP1::PAK
|
||||
{
|
||||
using DNAMP1::PAK::PAK;
|
||||
std::string bestEntryName(const nod::Node& pakNode, const Entry& entry, bool& named) const;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user