metaforce/DataSpec/DNAMP1/AGSC.cpp

262 lines
13 KiB
C++

#include "AGSC.hpp"
#include "amuse/AudioGroup.hpp"
#include "amuse/AudioGroupData.hpp"
extern "C" const uint8_t Atomic_H[];
extern "C" const uint8_t BetaBeetle_H[];
extern "C" const uint8_t Bird_H[];
extern "C" const uint8_t BloodFlower_H[];
extern "C" const uint8_t Burrower_H[];
extern "C" const uint8_t ChozoGhost_H[];
extern "C" const uint8_t ChubbWeed_H[];
extern "C" const uint8_t CineBoots_H[];
extern "C" const uint8_t CineGeneral_H[];
extern "C" const uint8_t CineGun_H[];
extern "C" const uint8_t CineMorphball_H[];
extern "C" const uint8_t CineSuit_H[];
extern "C" const uint8_t CineVisor_H[];
extern "C" const uint8_t Crater_H[];
extern "C" const uint8_t Crystallite_H[];
extern "C" const uint8_t Drones_H[];
extern "C" const uint8_t EliteSpacePirate_H[];
extern "C" const uint8_t FireFlea_H[];
extern "C" const uint8_t Flaaghra_H[];
extern "C" const uint8_t FlickerBat_H[];
extern "C" const uint8_t FlyingPirate_H[];
extern "C" const uint8_t FrontEnd_H[];
extern "C" const uint8_t GagantuanBeatle_H[];
extern "C" const uint8_t Gnats_H[];
extern "C" const uint8_t Gryzbee_H[];
extern "C" const uint8_t IceCrack_H[];
extern "C" const uint8_t IceWorld_H[];
extern "C" const uint8_t InjuredPirates_H[];
extern "C" const uint8_t IntroBoss_H[];
extern "C" const uint8_t IntroWorld_H[];
extern "C" const uint8_t JellyZap_H[];
extern "C" const uint8_t LavaWorld_H[];
extern "C" const uint8_t Magdolite_H[];
extern "C" const uint8_t Metaree_H[];
extern "C" const uint8_t MetroidPrime_H[];
extern "C" const uint8_t Metroid_H[];
extern "C" const uint8_t MinesWorld_H[];
extern "C" const uint8_t MiscSamus_H[];
extern "C" const uint8_t Misc_H[];
extern "C" const uint8_t OmegaPirate_H[];
extern "C" const uint8_t OverWorld_H[];
extern "C" const uint8_t Parasite_H[];
extern "C" const uint8_t PhazonGun_H[];
extern "C" const uint8_t Phazon_H[];
extern "C" const uint8_t PuddleSpore_H[];
extern "C" const uint8_t PuddleToad_H[];
extern "C" const uint8_t Puffer_H[];
extern "C" const uint8_t ReactorDoor_H[];
extern "C" const uint8_t Ridley_H[];
extern "C" const uint8_t Ripper_H[];
extern "C" const uint8_t RuinsWorld_H[];
extern "C" const uint8_t SamusShip_H[];
extern "C" const uint8_t Scarab_H[];
extern "C" const uint8_t Seedling_H[];
extern "C" const uint8_t SheeGoth_H[];
extern "C" const uint8_t SnakeWeed_H[];
extern "C" const uint8_t Sova_H[];
extern "C" const uint8_t SpacePirate_H[];
extern "C" const uint8_t SpankWeed_H[];
extern "C" const uint8_t Thardus_H[];
extern "C" const uint8_t TheEnd_H[];
extern "C" const uint8_t Torobyte_H[];
extern "C" const uint8_t Triclops_H[];
extern "C" const uint8_t Turret_H[];
extern "C" const uint8_t UI_H[];
extern "C" const uint8_t WarWasp_H[];
extern "C" const uint8_t Weapons_H[];
extern "C" const uint8_t ZZZ_H[];
extern "C" const uint8_t Zoomer_H[];
extern "C" const uint8_t lumigek_H[];
extern "C" const uint8_t test_H[];
namespace DataSpec::DNAMP1 {
using namespace std::literals;
static const std::pair<std::string_view, const uint8_t*> Headers[] = {{"Atomic"sv, Atomic_H},
{"BetaBeetle"sv, BetaBeetle_H},
{"Bird"sv, Bird_H},
{"BloodFlower"sv, BloodFlower_H},
{"Burrower"sv, Burrower_H},
{"ChozoGhost"sv, ChozoGhost_H},
{"ChubbWeed"sv, ChubbWeed_H},
{"CineBoots"sv, CineBoots_H},
{"CineGeneral"sv, CineGeneral_H},
{"CineGun"sv, CineGun_H},
{"CineMorphball"sv, CineMorphball_H},
{"CineSuit"sv, CineSuit_H},
{"CineVisor"sv, CineVisor_H},
{"Crater"sv, Crater_H},
{"Crystallite"sv, Crystallite_H},
{"Drones"sv, Drones_H},
{"EliteSpacePirate"sv, EliteSpacePirate_H},
{"FireFlea"sv, FireFlea_H},
{"Flaaghra"sv, Flaaghra_H},
{"FlickerBat"sv, FlickerBat_H},
{"FlyingPirate"sv, FlyingPirate_H},
{"FrontEnd"sv, FrontEnd_H},
{"GagantuanBeatle"sv, GagantuanBeatle_H},
{"Gnats"sv, Gnats_H},
{"Gryzbee"sv, Gryzbee_H},
{"IceCrack"sv, IceCrack_H},
{"IceWorld"sv, IceWorld_H},
{"InjuredPirates"sv, InjuredPirates_H},
{"IntroBoss"sv, IntroBoss_H},
{"IntroWorld"sv, IntroWorld_H},
{"JellyZap"sv, JellyZap_H},
{"LavaWorld"sv, LavaWorld_H},
{"Magdolite"sv, Magdolite_H},
{"Metaree"sv, Metaree_H},
{"MetroidPrime"sv, MetroidPrime_H},
{"Metroid"sv, Metroid_H},
{"MinesWorld"sv, MinesWorld_H},
{"MiscSamus"sv, MiscSamus_H},
{"Misc"sv, Misc_H},
{"OmegaPirate"sv, OmegaPirate_H},
{"OverWorld"sv, OverWorld_H},
{"Parasite"sv, Parasite_H},
{"Phazon"sv, Phazon_H},
{"PhazonGun"sv, PhazonGun_H},
{"PuddleSpore"sv, PuddleSpore_H},
{"PuddleToad"sv, PuddleToad_H},
{"Puffer"sv, Puffer_H},
{"ReactorDoor"sv, ReactorDoor_H},
{"Ridley"sv, Ridley_H},
{"Ripper"sv, Ripper_H},
{"RuinsWorld"sv, RuinsWorld_H},
{"SamusShip"sv, SamusShip_H},
{"Scarab"sv, Scarab_H},
{"Seedling"sv, Seedling_H},
{"SheeGoth"sv, SheeGoth_H},
{"SnakeWeed"sv, SnakeWeed_H},
{"Sova"sv, Sova_H},
{"SpacePirate"sv, SpacePirate_H},
{"SpankWeed"sv, SpankWeed_H},
{"Thardus"sv, Thardus_H},
{"TheEnd"sv, TheEnd_H},
{"Torobyte"sv, Torobyte_H},
{"Triclops"sv, Triclops_H},
{"Turret"sv, Turret_H},
{"UI"sv, UI_H},
{"WarWasp"sv, WarWasp_H},
{"Weapons"sv, Weapons_H},
{"ZZZ"sv, ZZZ_H},
{"Zoomer"sv, Zoomer_H},
{"lumigek"sv, lumigek_H},
{"test"sv, test_H}};
bool AGSC::Extract(PAKEntryReadStream& rs, const hecl::ProjectPath& dir) {
dir.makeDirChain(true);
Header head;
head.read(rs);
uint32_t poolLen = rs.readUint32Big();
auto pool = rs.readUBytes(poolLen);
uint32_t projLen = rs.readUint32Big();
auto proj = rs.readUBytes(projLen);
uint32_t sampLen = rs.readUint32Big();
auto samp = rs.readUBytes(sampLen);
uint32_t sdirLen = rs.readUint32Big();
auto sdir = rs.readUBytes(sdirLen);
amuse::AudioGroupData data(proj.get(), projLen, pool.get(), poolLen, sdir.get(), sdirLen, samp.get(), sampLen,
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());
/* Import C headers */
auto lastComp = dir.getLastComponent();
auto search = std::lower_bound(std::cbegin(Headers), std::cend(Headers), lastComp,
[](const auto& a, const auto& b) { return a.first < b; });
if (search != std::cend(Headers) && search->first == lastComp)
group.importCHeader((char*)search->second);
/* Write out project/pool */
{
auto projd = group.getProj().toYAML();
athena::io::FileWriter fo(hecl::ProjectPath(dir, "!project.yaml").getAbsolutePath());
if (fo.hasError())
return false;
fo.writeUBytes(projd.data(), projd.size());
}
{
auto poold = group.getPool().toYAML();
athena::io::FileWriter fo(hecl::ProjectPath(dir, "!pool.yaml").getAbsolutePath());
if (fo.hasError())
return false;
fo.writeUBytes(poold.data(), poold.size());
}
return true;
}
static std::atomic_bool DidCook = {false};
bool AGSC::Cook(const hecl::ProjectPath& dir, const hecl::ProjectPath& refOutPath) {
/* This will cook all AGSCs in the local directory, ensuring unique ObjectIDs
* across all Amuse subprojects */
if (DidCook.exchange(true))
return true; /* We've already cooked all AGSCs */
amuse::ProjectDatabase projDb;
projDb.setIdDatabases();
auto parentDir = dir.getParentPath();
auto outParentDir = refOutPath.getParentPath();
for (const auto& ent : dir.getParentPath().enumerateDir()) {
if (!ent.m_isDir)
continue;
hecl::ProjectPath path(parentDir, ent.m_name);
if (IsPathAudioGroup(path)) {
hecl::ProjectPath outPath(outParentDir, ent.m_name);
athena::io::FileWriter w(outPath.getAbsolutePath());
if (w.hasError())
return false;
Header head;
head.audioDir = "Audio/"sv;
head.groupName = path.getLastComponent();
head.write(w);
amuse::AudioGroupDatabase group(path.getAbsolutePath());
auto proj = group.getProj().toGCNData(group.getPool(), group.getSdir());
auto pool = group.getPool().toData<athena::Endian::Big>();
auto sdirSamp = group.getSdir().toGCNData(group);
w.writeUint32Big(pool.size());
w.writeUBytes(pool.data(), pool.size());
w.writeUint32Big(proj.size());
w.writeUBytes(proj.data(), proj.size());
w.writeUint32Big(sdirSamp.second.size());
w.writeUBytes(sdirSamp.second.data(), sdirSamp.second.size());
w.writeUint32Big(sdirSamp.first.size());
w.writeUBytes(sdirSamp.first.data(), sdirSamp.first.size());
}
}
return true;
}
} // namespace DataSpec::DNAMP1