2
0
mirror of https://github.com/AxioDL/metaforce.git synced 2025-07-05 10:35:52 +00:00

Template instantiation rampage (much lighter common headers)

This commit is contained in:
Jack Andersen 2016-03-01 21:29:19 -10:00
parent 7049ab2b1d
commit 496903047e
13 changed files with 4108 additions and 3795 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -7,15 +7,16 @@ make_dnalist(liblist
add_library(DNACommon
DNACommon.hpp DNACommon.cpp
${liblist}
PAK.hpp
PAK.hpp PAK.cpp
GX.hpp
MLVL.hpp
MLVL.hpp MLVL.cpp
CMDL.cpp
MAPA.cpp
STRG.hpp STRG.cpp
TXTR.hpp TXTR.cpp
ANCS.hpp
ANIM.hpp ANIM.cpp
PART.hpp
PART.hpp PART.cpp
SWHC.hpp
ELSC.hpp
ParticleCommon.cpp

View File

@ -59,17 +59,20 @@ public:
HECL::Database::Project& getProject() const {return m_dataSpec.getProject();}
virtual HECL::ProjectPath getWorking(const UniqueID32&) const
{
LogDNACommon.report(LogVisor::FatalError, "PAKRouter IDType mismatch; expected UniqueID32 specialization");
LogDNACommon.report(LogVisor::FatalError,
"PAKRouter IDType mismatch; expected UniqueID32 specialization");
return HECL::ProjectPath();
}
virtual HECL::ProjectPath getWorking(const UniqueID64&) const
{
LogDNACommon.report(LogVisor::FatalError, "PAKRouter IDType mismatch; expected UniqueID64 specialization");
LogDNACommon.report(LogVisor::FatalError,
"PAKRouter IDType mismatch; expected UniqueID64 specialization");
return HECL::ProjectPath();
}
virtual HECL::ProjectPath getWorking(const UniqueID128&) const
{
LogDNACommon.report(LogVisor::FatalError, "PAKRouter IDType mismatch; expected UniqueID128 specialization");
LogDNACommon.report(LogVisor::FatalError,
"PAKRouter IDType mismatch; expected UniqueID128 specialization");
return HECL::ProjectPath();
}
};

321
DataSpec/DNACommon/MAPA.cpp Normal file
View File

@ -0,0 +1,321 @@
#include "MAPA.hpp"
#include "../DNAMP1/DNAMP1.hpp"
#include "../DNAMP2/DNAMP2.hpp"
#include "../DNAMP3/DNAMP3.hpp"
namespace DataSpec
{
namespace DNAMAPA
{
void MAPA::read(Athena::io::IStreamReader& __dna_reader)
{
/* magic */
magic = __dna_reader.readUint32Big();
if (magic != 0xDEADD00D)
{
LogDNACommon.report(LogVisor::Error, "invalid MAPA magic");
return;
}
/* version */
version = __dna_reader.readUint32Big();
if (version == 2)
header.reset(new HeaderMP1);
else if (version == 3)
header.reset(new HeaderMP2);
else if (version == 5)
header.reset(new HeaderMP3);
else
{
LogDNACommon.report(LogVisor::Error, "invalid MAPA version");
return;
}
header->read(__dna_reader);
for (atUint32 i = 0; i < header->mappableObjectCount(); i++)
{
std::unique_ptr<IMappableObject> mo = nullptr;
if (version != 5)
mo.reset(new MappableObjectMP1_2);
else
mo.reset(new MappableObjectMP3);
mo->read(__dna_reader);
mappableObjects.push_back(std::move(mo));
}
/* vertices */
__dna_reader.enumerateBig(vertices, header->vertexCount());
/* surfaceHeaders */
__dna_reader.enumerate(surfaceHeaders, header->surfaceCount());
/* surfaces */
__dna_reader.enumerate(surfaces, header->surfaceCount());
}
void MAPA::write(Athena::io::IStreamWriter& __dna_writer) const
{
/* magic */
__dna_writer.writeUint32Big(magic);
/* version */
__dna_writer.writeUint32Big(version);
header->write(__dna_writer);
/* mappableObjects */
for (const std::unique_ptr<IMappableObject>& mo : mappableObjects)
mo->write(__dna_writer);
/* vertices */
__dna_writer.enumerateBig(vertices);
/* surfaceHeaders */
__dna_writer.enumerate(surfaceHeaders);
/* surfaces */
__dna_writer.enumerate(surfaces);
}
size_t MAPA::binarySize(size_t __isz) const
{
__isz = header->binarySize(__isz);
for (const std::unique_ptr<IMappableObject>& mo : mappableObjects)
__isz = mo->binarySize(__isz);
__isz += vertices.size() * 12;
__isz = __EnumerateSize(__isz, surfaceHeaders);
__isz = __EnumerateSize(__isz, surfaces);
return __isz + 8;
}
template <typename PAKRouter>
bool ReadMAPAToBlender(HECL::BlenderConnection& conn,
const MAPA& mapa,
const HECL::ProjectPath& outPath,
PAKRouter& pakRouter,
const typename PAKRouter::EntryType& entry,
bool force)
{
/* Rename MAPA for consistency */
HECL::ProjectPath mapaPath(outPath.getParentPath(), _S("!map.blend"));
if (!force && mapaPath.getPathType() == HECL::ProjectPath::Type::File)
return true;
if (!conn.createBlend(mapaPath, HECL::BlenderConnection::BlendType::MapArea))
return false;
HECL::BlenderConnection::PyOutStream os = conn.beginPythonOut(true);
os << "import bpy, bmesh\n"
"from mathutils import Matrix\n"
"\n"
"bpy.types.Object.retro_mappable_type = bpy.props.IntProperty(name='Retro: MAPA object type', default=-1)\n"
"bpy.types.Object.retro_mappable_unk = bpy.props.IntProperty(name='Retro: MAPA object unk')\n"
"bpy.types.Object.retro_mappable_sclyid = bpy.props.StringProperty(name='Retro: MAPA object SCLY ID')\n"
"\n"
"# Clear Scene\n"
"for ob in bpy.data.objects:\n"
" bpy.context.scene.objects.unlink(ob)\n"
" bpy.data.objects.remove(ob)\n"
"\n"
"def add_triangle(bm, verts):\n"
" verts = [bm.verts[vi] for vi in verts]\n"
" face = bm.faces.get(verts)\n"
" if face:\n"
" face = face.copy()\n"
" bm.verts.ensure_lookup_table()\n"
" face.normal_flip()\n"
" else:\n"
" bm.faces.new(verts)\n"
"\n"
"def add_border(bm, verts):\n"
" verts = [bm.verts[vi] for vi in verts]\n"
" edge = bm.edges.get(verts)\n"
" if not edge:\n"
" edge = bm.edges.new(verts)\n"
" edge.seam = True\n"
"\n";
os.format("bpy.context.scene.name = 'MAPA_%s'\n",
entry.id.toString().c_str());
/* Add empties representing MappableObjects */
int moIdx = 0;
for (const std::unique_ptr<MAPA::IMappableObject>& mo : mapa.mappableObjects)
{
const MAPA::MappableObjectMP1_2* moMP12 = dynamic_cast<const MAPA::MappableObjectMP1_2*>(mo.get());
if (moMP12)
{
os.format("obj = bpy.data.objects.new('MAPOBJ_%02d', None)\n"
"bpy.context.scene.objects.link(obj)\n"
"obj.retro_mappable_type = %d\n"
"obj.retro_mappable_unk = %d\n"
"obj.retro_mappable_sclyid = '%08X'\n"
"mtx = Matrix(((%f,%f,%f,%f),(%f,%f,%f,%f),(%f,%f,%f,%f),(0.0,0.0,0.0,1.0)))\n"
"mtxd = mtx.decompose()\n"
"obj.rotation_mode = 'QUATERNION'\n"
"obj.location = mtxd[0]\n"
"obj.rotation_quaternion = mtxd[1]\n"
"obj.scale = mtxd[2]\n",
moIdx, moMP12->type, moMP12->unknown1, moMP12->sclyId,
moMP12->transformMtx[0].vec[0], moMP12->transformMtx[0].vec[1], moMP12->transformMtx[0].vec[2], moMP12->transformMtx[0].vec[3],
moMP12->transformMtx[1].vec[0], moMP12->transformMtx[1].vec[1], moMP12->transformMtx[1].vec[2], moMP12->transformMtx[1].vec[3],
moMP12->transformMtx[2].vec[0], moMP12->transformMtx[2].vec[1], moMP12->transformMtx[2].vec[2], moMP12->transformMtx[2].vec[3]);
++moIdx;
continue;
}
const MAPA::MappableObjectMP3* moMP3 = dynamic_cast<const MAPA::MappableObjectMP3*>(mo.get());
if (moMP3)
{
os.format("obj = bpy.data.objects.new('MAPOBJ_%02d', None)\n"
"bpy.context.scene.objects.link(obj)\n"
"obj.retro_mappable_type = %d\n"
"obj.retro_mappable_unk = %d\n"
"obj.retro_mappable_sclyid = '%08X'\n"
"mtx = Matrix(((%f,%f,%f,%f),(%f,%f,%f,%f),(%f,%f,%f,%f),(0.0,0.0,0.0,1.0)))\n"
"mtxd = mtx.decompose()\n"
"obj.rotation_mode = 'QUATERNION'\n"
"obj.location = mtxd[0]\n"
"obj.rotation_quaternion = mtxd[1]\n"
"obj.scale = mtxd[2]\n",
moIdx, moMP3->type, moMP3->unknown1, moMP3->sclyId,
moMP3->transformMtx[0].vec[0], moMP3->transformMtx[0].vec[1], moMP3->transformMtx[0].vec[2], moMP3->transformMtx[0].vec[3],
moMP3->transformMtx[1].vec[0], moMP3->transformMtx[1].vec[1], moMP3->transformMtx[1].vec[2], moMP3->transformMtx[1].vec[3],
moMP3->transformMtx[2].vec[0], moMP3->transformMtx[2].vec[1], moMP3->transformMtx[2].vec[2], moMP3->transformMtx[2].vec[3]);
++moIdx;
continue;
}
}
os << "# Begin bmesh\n"
"bm = bmesh.new()\n"
"\n";
/* Read in verts */
for (const atVec3f& vert : mapa.vertices)
os.format("bm.verts.new((%f,%f,%f))\n",
vert.vec[0], vert.vec[1], vert.vec[2]);
os << "bm.verts.ensure_lookup_table()\n";
/* Read in surfaces */
for (const typename MAPA::Surface& surf : mapa.surfaces)
{
for (const typename MAPA::Surface::Primitive& prim : surf.primitives)
{
auto iit = prim.indices.cbegin();
/* 3 Prim Verts to start */
int c = 0;
unsigned int primVerts[3] =
{
*iit++,
*iit++,
*iit++
};
if (GX::Primitive(prim.type) == GX::TRIANGLESTRIP)
{
atUint8 flip = 0;
for (size_t v=0 ; v<prim.indexCount-2 ; ++v)
{
if (flip)
{
os.format("add_triangle(bm, (%u,%u,%u))\n",
primVerts[c%3],
primVerts[(c+2)%3],
primVerts[(c+1)%3]);
}
else
{
os.format("add_triangle(bm, (%u,%u,%u))\n",
primVerts[c%3],
primVerts[(c+1)%3],
primVerts[(c+2)%3]);
}
flip ^= 1;
/* Break if done */
if (iit == prim.indices.cend())
break;
bool peek = (v >= prim.indexCount - 3);
/* Advance one prim vert */
if (peek)
primVerts[c%3] = *iit;
else
primVerts[c%3] = *iit++;
++c;
}
}
else if (GX::Primitive(prim.type) == GX::TRIANGLES)
{
for (size_t v=0 ; v<prim.indexCount ; v+=3)
{
os.format("add_triangle(bm, (%u,%u,%u))\n",
primVerts[0],
primVerts[1],
primVerts[2]);
/* Break if done */
if (v+3 >= prim.indexCount)
break;
/* Advance 3 Prim Verts */
for (int pv=0 ; pv<3 ; ++pv)
primVerts[pv] = *iit++;
}
}
}
for (const typename MAPA::Surface::Border& border : surf.borders)
{
auto iit = border.indices.cbegin();
for (size_t i=0 ; i<border.indexCount-1 ; ++i)
{
os.format("add_border(bm, (%u,%u))\n",
*iit, *(iit+1));
++iit;
}
}
}
os << "mesh = bpy.data.meshes.new('MAP')\n"
"obj = bpy.data.objects.new(mesh.name, mesh)\n"
"bm.to_mesh(mesh)\n"
"bpy.context.scene.objects.link(obj)\n"
"bm.free()\n";
/* World background */
HECL::ProjectPath worldBlend(outPath.getParentPath().getParentPath(), "!world.blend");
if (worldBlend.getPathType() == HECL::ProjectPath::Type::File)
os.linkBackground("//../!world.blend", "World");
os.centerView();
os.close();
conn.saveBlend();
return true;
}
template bool ReadMAPAToBlender<PAKRouter<DNAMP1::PAKBridge>>
(HECL::BlenderConnection& conn,
const MAPA& mapa,
const HECL::ProjectPath& outPath,
PAKRouter<DNAMP1::PAKBridge>& pakRouter,
const typename PAKRouter<DNAMP1::PAKBridge>::EntryType& entry,
bool force);
template bool ReadMAPAToBlender<PAKRouter<DNAMP2::PAKBridge>>
(HECL::BlenderConnection& conn,
const MAPA& mapa,
const HECL::ProjectPath& outPath,
PAKRouter<DNAMP2::PAKBridge>& pakRouter,
const typename PAKRouter<DNAMP2::PAKBridge>::EntryType& entry,
bool force);
template bool ReadMAPAToBlender<PAKRouter<DNAMP3::PAKBridge>>
(HECL::BlenderConnection& conn,
const MAPA& mapa,
const HECL::ProjectPath& outPath,
PAKRouter<DNAMP3::PAKBridge>& pakRouter,
const typename PAKRouter<DNAMP3::PAKBridge>::EntryType& entry,
bool force);
}
}

View File

@ -74,81 +74,9 @@ struct MAPA : BigDNA
};
void read(Athena::io::IStreamReader& __dna_reader)
{
/* magic */
magic = __dna_reader.readUint32Big();
if (magic != 0xDEADD00D)
{
LogDNACommon.report(LogVisor::Error, "invalid MAPA magic");
return;
}
/* version */
version = __dna_reader.readUint32Big();
if (version == 2)
header.reset(new HeaderMP1);
else if (version == 3)
header.reset(new HeaderMP2);
else if (version == 5)
header.reset(new HeaderMP3);
else
{
LogDNACommon.report(LogVisor::Error, "invalid MAPA version");
return;
}
header->read(__dna_reader);
for (atUint32 i = 0; i < header->mappableObjectCount(); i++)
{
std::unique_ptr<IMappableObject> mo = nullptr;
if (version != 5)
mo.reset(new MappableObjectMP1_2);
else
mo.reset(new MappableObjectMP3);
mo->read(__dna_reader);
mappableObjects.push_back(std::move(mo));
}
/* vertices */
__dna_reader.enumerateBig(vertices, header->vertexCount());
/* surfaceHeaders */
__dna_reader.enumerate(surfaceHeaders, header->surfaceCount());
/* surfaces */
__dna_reader.enumerate(surfaces, header->surfaceCount());
}
void write(Athena::io::IStreamWriter& __dna_writer) const
{
/* magic */
__dna_writer.writeUint32Big(magic);
/* version */
__dna_writer.writeUint32Big(version);
header->write(__dna_writer);
/* mappableObjects */
for (const std::unique_ptr<IMappableObject>& mo : mappableObjects)
mo->write(__dna_writer);
/* vertices */
__dna_writer.enumerateBig(vertices);
/* surfaceHeaders */
__dna_writer.enumerate(surfaceHeaders);
/* surfaces */
__dna_writer.enumerate(surfaces);
}
size_t binarySize(size_t __isz) const
{
__isz = header->binarySize(__isz);
for (const std::unique_ptr<IMappableObject>& mo : mappableObjects)
__isz = mo->binarySize(__isz);
__isz += vertices.size() * 12;
__isz = __EnumerateSize(__isz, surfaceHeaders);
__isz = __EnumerateSize(__isz, surfaces);
return __isz + 8;
}
void read(Athena::io::IStreamReader& __dna_reader);
void write(Athena::io::IStreamWriter& __dna_writer) const;
size_t binarySize(size_t __isz) const;
std::unique_ptr<IMAPAHeader> header;
@ -257,208 +185,7 @@ bool ReadMAPAToBlender(HECL::BlenderConnection& conn,
const HECL::ProjectPath& outPath,
PAKRouter& pakRouter,
const typename PAKRouter::EntryType& entry,
bool force)
{
/* Rename MAPA for consistency */
HECL::ProjectPath mapaPath(outPath.getParentPath(), _S("!map.blend"));
if (!force && mapaPath.getPathType() == HECL::ProjectPath::Type::File)
return true;
if (!conn.createBlend(mapaPath, HECL::BlenderConnection::BlendType::MapArea))
return false;
HECL::BlenderConnection::PyOutStream os = conn.beginPythonOut(true);
os << "import bpy, bmesh\n"
"from mathutils import Matrix\n"
"\n"
"bpy.types.Object.retro_mappable_type = bpy.props.IntProperty(name='Retro: MAPA object type', default=-1)\n"
"bpy.types.Object.retro_mappable_unk = bpy.props.IntProperty(name='Retro: MAPA object unk')\n"
"bpy.types.Object.retro_mappable_sclyid = bpy.props.StringProperty(name='Retro: MAPA object SCLY ID')\n"
"\n"
"# Clear Scene\n"
"for ob in bpy.data.objects:\n"
" bpy.context.scene.objects.unlink(ob)\n"
" bpy.data.objects.remove(ob)\n"
"\n"
"def add_triangle(bm, verts):\n"
" verts = [bm.verts[vi] for vi in verts]\n"
" face = bm.faces.get(verts)\n"
" if face:\n"
" face = face.copy()\n"
" bm.verts.ensure_lookup_table()\n"
" face.normal_flip()\n"
" else:\n"
" bm.faces.new(verts)\n"
"\n"
"def add_border(bm, verts):\n"
" verts = [bm.verts[vi] for vi in verts]\n"
" edge = bm.edges.get(verts)\n"
" if not edge:\n"
" edge = bm.edges.new(verts)\n"
" edge.seam = True\n"
"\n";
os.format("bpy.context.scene.name = 'MAPA_%s'\n",
entry.id.toString().c_str());
/* Add empties representing MappableObjects */
int moIdx = 0;
for (const std::unique_ptr<MAPA::IMappableObject>& mo : mapa.mappableObjects)
{
const MAPA::MappableObjectMP1_2* moMP12 = dynamic_cast<const MAPA::MappableObjectMP1_2*>(mo.get());
if (moMP12)
{
os.format("obj = bpy.data.objects.new('MAPOBJ_%02d', None)\n"
"bpy.context.scene.objects.link(obj)\n"
"obj.retro_mappable_type = %d\n"
"obj.retro_mappable_unk = %d\n"
"obj.retro_mappable_sclyid = '%08X'\n"
"mtx = Matrix(((%f,%f,%f,%f),(%f,%f,%f,%f),(%f,%f,%f,%f),(0.0,0.0,0.0,1.0)))\n"
"mtxd = mtx.decompose()\n"
"obj.rotation_mode = 'QUATERNION'\n"
"obj.location = mtxd[0]\n"
"obj.rotation_quaternion = mtxd[1]\n"
"obj.scale = mtxd[2]\n",
moIdx, moMP12->type, moMP12->unknown1, moMP12->sclyId,
moMP12->transformMtx[0].vec[0], moMP12->transformMtx[0].vec[1], moMP12->transformMtx[0].vec[2], moMP12->transformMtx[0].vec[3],
moMP12->transformMtx[1].vec[0], moMP12->transformMtx[1].vec[1], moMP12->transformMtx[1].vec[2], moMP12->transformMtx[1].vec[3],
moMP12->transformMtx[2].vec[0], moMP12->transformMtx[2].vec[1], moMP12->transformMtx[2].vec[2], moMP12->transformMtx[2].vec[3]);
++moIdx;
continue;
}
const MAPA::MappableObjectMP3* moMP3 = dynamic_cast<const MAPA::MappableObjectMP3*>(mo.get());
if (moMP3)
{
os.format("obj = bpy.data.objects.new('MAPOBJ_%02d', None)\n"
"bpy.context.scene.objects.link(obj)\n"
"obj.retro_mappable_type = %d\n"
"obj.retro_mappable_unk = %d\n"
"obj.retro_mappable_sclyid = '%08X'\n"
"mtx = Matrix(((%f,%f,%f,%f),(%f,%f,%f,%f),(%f,%f,%f,%f),(0.0,0.0,0.0,1.0)))\n"
"mtxd = mtx.decompose()\n"
"obj.rotation_mode = 'QUATERNION'\n"
"obj.location = mtxd[0]\n"
"obj.rotation_quaternion = mtxd[1]\n"
"obj.scale = mtxd[2]\n",
moIdx, moMP3->type, moMP3->unknown1, moMP3->sclyId,
moMP3->transformMtx[0].vec[0], moMP3->transformMtx[0].vec[1], moMP3->transformMtx[0].vec[2], moMP3->transformMtx[0].vec[3],
moMP3->transformMtx[1].vec[0], moMP3->transformMtx[1].vec[1], moMP3->transformMtx[1].vec[2], moMP3->transformMtx[1].vec[3],
moMP3->transformMtx[2].vec[0], moMP3->transformMtx[2].vec[1], moMP3->transformMtx[2].vec[2], moMP3->transformMtx[2].vec[3]);
++moIdx;
continue;
}
}
os << "# Begin bmesh\n"
"bm = bmesh.new()\n"
"\n";
/* Read in verts */
for (const atVec3f& vert : mapa.vertices)
os.format("bm.verts.new((%f,%f,%f))\n",
vert.vec[0], vert.vec[1], vert.vec[2]);
os << "bm.verts.ensure_lookup_table()\n";
/* Read in surfaces */
for (const typename MAPA::Surface& surf : mapa.surfaces)
{
for (const typename MAPA::Surface::Primitive& prim : surf.primitives)
{
auto iit = prim.indices.cbegin();
/* 3 Prim Verts to start */
int c = 0;
unsigned int primVerts[3] =
{
*iit++,
*iit++,
*iit++
};
if (GX::Primitive(prim.type) == GX::TRIANGLESTRIP)
{
atUint8 flip = 0;
for (size_t v=0 ; v<prim.indexCount-2 ; ++v)
{
if (flip)
{
os.format("add_triangle(bm, (%u,%u,%u))\n",
primVerts[c%3],
primVerts[(c+2)%3],
primVerts[(c+1)%3]);
}
else
{
os.format("add_triangle(bm, (%u,%u,%u))\n",
primVerts[c%3],
primVerts[(c+1)%3],
primVerts[(c+2)%3]);
}
flip ^= 1;
/* Break if done */
if (iit == prim.indices.cend())
break;
bool peek = (v >= prim.indexCount - 3);
/* Advance one prim vert */
if (peek)
primVerts[c%3] = *iit;
else
primVerts[c%3] = *iit++;
++c;
}
}
else if (GX::Primitive(prim.type) == GX::TRIANGLES)
{
for (size_t v=0 ; v<prim.indexCount ; v+=3)
{
os.format("add_triangle(bm, (%u,%u,%u))\n",
primVerts[0],
primVerts[1],
primVerts[2]);
/* Break if done */
if (v+3 >= prim.indexCount)
break;
/* Advance 3 Prim Verts */
for (int pv=0 ; pv<3 ; ++pv)
primVerts[pv] = *iit++;
}
}
}
for (const typename MAPA::Surface::Border& border : surf.borders)
{
auto iit = border.indices.cbegin();
for (size_t i=0 ; i<border.indexCount-1 ; ++i)
{
os.format("add_border(bm, (%u,%u))\n",
*iit, *(iit+1));
++iit;
}
}
}
os << "mesh = bpy.data.meshes.new('MAP')\n"
"obj = bpy.data.objects.new(mesh.name, mesh)\n"
"bm.to_mesh(mesh)\n"
"bpy.context.scene.objects.link(obj)\n"
"bm.free()\n";
/* World background */
HECL::ProjectPath worldBlend(outPath.getParentPath().getParentPath(), "!world.blend");
if (worldBlend.getPathType() == HECL::ProjectPath::Type::File)
os.linkBackground("//../!world.blend", "World");
os.centerView();
os.close();
conn.saveBlend();
return true;
}
bool force);
}
}

132
DataSpec/DNACommon/MLVL.cpp Normal file
View File

@ -0,0 +1,132 @@
#include "MLVL.hpp"
#include "../DNAMP1/MLVL.hpp"
#include "../DNAMP2/MLVL.hpp"
#include "../DNAMP3/MLVL.hpp"
namespace DataSpec
{
namespace DNAMLVL
{
template <class PAKRouter, typename MLVL>
bool ReadMLVLToBlender(HECL::BlenderConnection& conn,
const MLVL& mlvl,
const HECL::ProjectPath& outPath,
PAKRouter& pakRouter,
const typename PAKRouter::EntryType& entry,
bool force,
std::function<void(const HECL::SystemChar*)> fileChanged)
{
/* Rename MLVL for consistency */
HECL::ProjectPath mlvlPath(outPath.getParentPath(), _S("!world.blend"));
if (!force && mlvlPath.getPathType() == HECL::ProjectPath::Type::File)
return true;
/* Create World Blend */
if (!conn.createBlend(mlvlPath, HECL::BlenderConnection::BlendType::World))
return false;
HECL::BlenderConnection::PyOutStream os = conn.beginPythonOut(true);
os.format("import bpy\n"
"import bmesh\n"
"from mathutils import Matrix\n"
"\n"
"bpy.context.scene.name = 'World'\n"
"\n"
"# Clear Scene\n"
"for ob in bpy.data.objects:\n"
" bpy.context.scene.objects.unlink(ob)\n"
" bpy.data.objects.remove(ob)\n");
/* Insert area empties */
int areaIdx = 0;
for (const auto& area : mlvl.areas)
{
const typename PAKRouter::EntryType* mreaEntry = pakRouter.lookupEntry(area.areaMREAId);
HECL::SystemUTF8View areaDirName(*mreaEntry->unique.m_areaName);
os.AABBToBMesh(area.aabb[0], area.aabb[1]);
os.format("box_mesh = bpy.data.meshes.new('''%s''')\n"
"bm.to_mesh(box_mesh)\n"
"bm.free()\n"
"box = bpy.data.objects.new(box_mesh.name, box_mesh)\n"
"bpy.context.scene.objects.link(box)\n"
"mtx = Matrix(((%f,%f,%f,%f),(%f,%f,%f,%f),(%f,%f,%f,%f),(0.0,0.0,0.0,1.0)))\n"
"mtxd = mtx.decompose()\n"
"box.rotation_mode = 'QUATERNION'\n"
"box.location = mtxd[0]\n"
"box.rotation_quaternion = mtxd[1]\n"
"box.scale = mtxd[2]\n",
areaDirName.str().c_str(),
area.transformMtx[0].vec[0], area.transformMtx[0].vec[1], area.transformMtx[0].vec[2], area.transformMtx[0].vec[3],
area.transformMtx[1].vec[0], area.transformMtx[1].vec[1], area.transformMtx[1].vec[2], area.transformMtx[1].vec[3],
area.transformMtx[2].vec[0], area.transformMtx[2].vec[1], area.transformMtx[2].vec[2], area.transformMtx[2].vec[3]);
/* Insert dock planes */
int dockIdx = 0;
for (const auto& dock : area.docks)
{
os << "bm = bmesh.new()\n";
Zeus::CVector3f pvAvg;
for (const atVec3f& pv : dock.planeVerts)
pvAvg += pv;
pvAvg /= dock.planeVerts.size();
int idx = 0;
for (const atVec3f& pv : dock.planeVerts)
{
Zeus::CVector3f pvRel = Zeus::CVector3f(pv) - pvAvg;
os.format("bm.verts.new((%f,%f,%f))\n"
"bm.verts.ensure_lookup_table()\n",
pvRel[0], pvRel[1], pvRel[2]);
if (idx)
os << "bm.edges.new((bm.verts[-2], bm.verts[-1]))\n";
++idx;
}
os << "bm.edges.new((bm.verts[-1], bm.verts[0]))\n";
os.format("dockMesh = bpy.data.meshes.new('DOCK_%02d_%02d')\n", areaIdx, dockIdx);
os << "dockObj = bpy.data.objects.new(dockMesh.name, dockMesh)\n"
"bpy.context.scene.objects.link(dockObj)\n"
"bm.to_mesh(dockMesh)\n"
"bm.free()\n"
"dockObj.parent = box\n";
os.format("dockObj.location = (%f,%f,%f)\n",
pvAvg[0], pvAvg[1], pvAvg[2]);
++dockIdx;
}
++areaIdx;
}
os.centerView();
os.close();
conn.saveBlend();
return true;
}
template bool ReadMLVLToBlender<PAKRouter<DNAMP1::PAKBridge>, DNAMP1::MLVL>
(HECL::BlenderConnection& conn,
const DNAMP1::MLVL& mlvl,
const HECL::ProjectPath& outPath,
PAKRouter<DNAMP1::PAKBridge>& pakRouter,
const typename PAKRouter<DNAMP1::PAKBridge>::EntryType& entry,
bool force,
std::function<void(const HECL::SystemChar*)> fileChanged);
template bool ReadMLVLToBlender<PAKRouter<DNAMP2::PAKBridge>, DNAMP2::MLVL>
(HECL::BlenderConnection& conn,
const DNAMP2::MLVL& mlvl,
const HECL::ProjectPath& outPath,
PAKRouter<DNAMP2::PAKBridge>& pakRouter,
const typename PAKRouter<DNAMP2::PAKBridge>::EntryType& entry,
bool force,
std::function<void(const HECL::SystemChar*)> fileChanged);
template bool ReadMLVLToBlender<PAKRouter<DNAMP3::PAKBridge>, DNAMP3::MLVL>
(HECL::BlenderConnection& conn,
const DNAMP3::MLVL& mlvl,
const HECL::ProjectPath& outPath,
PAKRouter<DNAMP3::PAKBridge>& pakRouter,
const typename PAKRouter<DNAMP3::PAKBridge>::EntryType& entry,
bool force,
std::function<void(const HECL::SystemChar*)> fileChanged);
}
}

View File

@ -17,91 +17,7 @@ bool ReadMLVLToBlender(HECL::BlenderConnection& conn,
PAKRouter& pakRouter,
const typename PAKRouter::EntryType& entry,
bool force,
std::function<void(const HECL::SystemChar*)> fileChanged)
{
/* Rename MLVL for consistency */
HECL::ProjectPath mlvlPath(outPath.getParentPath(), _S("!world.blend"));
if (!force && mlvlPath.getPathType() == HECL::ProjectPath::Type::File)
return true;
/* Create World Blend */
if (!conn.createBlend(mlvlPath, HECL::BlenderConnection::BlendType::World))
return false;
HECL::BlenderConnection::PyOutStream os = conn.beginPythonOut(true);
os.format("import bpy\n"
"import bmesh\n"
"from mathutils import Matrix\n"
"\n"
"bpy.context.scene.name = 'World'\n"
"\n"
"# Clear Scene\n"
"for ob in bpy.data.objects:\n"
" bpy.context.scene.objects.unlink(ob)\n"
" bpy.data.objects.remove(ob)\n");
/* Insert area empties */
int areaIdx = 0;
for (const auto& area : mlvl.areas)
{
const typename PAKRouter::EntryType* mreaEntry = pakRouter.lookupEntry(area.areaMREAId);
HECL::SystemUTF8View areaDirName(*mreaEntry->unique.m_areaName);
os.AABBToBMesh(area.aabb[0], area.aabb[1]);
os.format("box_mesh = bpy.data.meshes.new('''%s''')\n"
"bm.to_mesh(box_mesh)\n"
"bm.free()\n"
"box = bpy.data.objects.new(box_mesh.name, box_mesh)\n"
"bpy.context.scene.objects.link(box)\n"
"mtx = Matrix(((%f,%f,%f,%f),(%f,%f,%f,%f),(%f,%f,%f,%f),(0.0,0.0,0.0,1.0)))\n"
"mtxd = mtx.decompose()\n"
"box.rotation_mode = 'QUATERNION'\n"
"box.location = mtxd[0]\n"
"box.rotation_quaternion = mtxd[1]\n"
"box.scale = mtxd[2]\n",
areaDirName.str().c_str(),
area.transformMtx[0].vec[0], area.transformMtx[0].vec[1], area.transformMtx[0].vec[2], area.transformMtx[0].vec[3],
area.transformMtx[1].vec[0], area.transformMtx[1].vec[1], area.transformMtx[1].vec[2], area.transformMtx[1].vec[3],
area.transformMtx[2].vec[0], area.transformMtx[2].vec[1], area.transformMtx[2].vec[2], area.transformMtx[2].vec[3]);
/* Insert dock planes */
int dockIdx = 0;
for (const auto& dock : area.docks)
{
os << "bm = bmesh.new()\n";
Zeus::CVector3f pvAvg;
for (const atVec3f& pv : dock.planeVerts)
pvAvg += pv;
pvAvg /= dock.planeVerts.size();
int idx = 0;
for (const atVec3f& pv : dock.planeVerts)
{
Zeus::CVector3f pvRel = Zeus::CVector3f(pv) - pvAvg;
os.format("bm.verts.new((%f,%f,%f))\n"
"bm.verts.ensure_lookup_table()\n",
pvRel[0], pvRel[1], pvRel[2]);
if (idx)
os << "bm.edges.new((bm.verts[-2], bm.verts[-1]))\n";
++idx;
}
os << "bm.edges.new((bm.verts[-1], bm.verts[0]))\n";
os.format("dockMesh = bpy.data.meshes.new('DOCK_%02d_%02d')\n", areaIdx, dockIdx);
os << "dockObj = bpy.data.objects.new(dockMesh.name, dockMesh)\n"
"bpy.context.scene.objects.link(dockObj)\n"
"bm.to_mesh(dockMesh)\n"
"bm.free()\n"
"dockObj.parent = box\n";
os.format("dockObj.location = (%f,%f,%f)\n",
pvAvg[0], pvAvg[1], pvAvg[2]);
++dockIdx;
}
++areaIdx;
}
os.centerView();
os.close();
conn.saveBlend();
return true;
}
std::function<void(const HECL::SystemChar*)> fileChanged);
}
}

588
DataSpec/DNACommon/PAK.cpp Normal file
View File

@ -0,0 +1,588 @@
#include "PAK.hpp"
#include "../DNAMP1/DNAMP1.hpp"
#include "../DNAMP2/DNAMP2.hpp"
#include "../DNAMP3/DNAMP3.hpp"
namespace DataSpec
{
template <class PAKBRIDGE>
void UniqueResult::checkEntry(const PAKBRIDGE& pakBridge, const typename PAKBRIDGE::PAKType::Entry& entry)
{
UniqueResult::Type resultType = UniqueResult::Type::NotFound;
bool foundOneLayer = false;
const HECL::SystemString* levelName = nullptr;
typename PAKBRIDGE::PAKType::IDType levelId;
typename PAKBRIDGE::PAKType::IDType areaId;
unsigned layerIdx;
for (const auto& lpair : pakBridge.m_levelDeps)
{
if (entry.id == lpair.first)
{
levelName = &lpair.second.name;
resultType = UniqueResult::Type::Level;
break;
}
for (const auto& pair : lpair.second.areas)
{
unsigned l=0;
for (const auto& layer : pair.second.layers)
{
if (layer.resources.find(entry.id) != layer.resources.end())
{
if (foundOneLayer)
{
if (areaId == pair.first)
{
resultType = UniqueResult::Type::Area;
}
else if (levelId == lpair.first)
{
resultType = UniqueResult::Type::Level;
break;
}
else
{
m_type = UniqueResult::Type::Pak;
return;
}
continue;
}
else
resultType = UniqueResult::Type::Layer;
levelName = &lpair.second.name;
levelId = lpair.first;
areaId = pair.first;
layerIdx = l;
foundOneLayer = true;
}
++l;
}
if (pair.second.resources.find(entry.id) != pair.second.resources.end())
{
if (foundOneLayer)
{
if (areaId == pair.first)
{
resultType = UniqueResult::Type::Area;
}
else if (levelId == lpair.first)
{
resultType = UniqueResult::Type::Level;
break;
}
else
{
m_type = UniqueResult::Type::Pak;
return;
}
continue;
}
else
resultType = UniqueResult::Type::Area;
levelName = &lpair.second.name;
levelId = lpair.first;
areaId = pair.first;
foundOneLayer = true;
}
}
}
m_type = resultType;
m_levelName = levelName;
if (resultType == UniqueResult::Type::Layer || resultType == UniqueResult::Type::Area)
{
const typename PAKBRIDGE::Level::Area& area = pakBridge.m_levelDeps.at(levelId).areas.at(areaId);
m_areaName = &area.name;
if (resultType == UniqueResult::Type::Layer)
{
const typename PAKBRIDGE::Level::Area::Layer& layer = area.layers[layerIdx];
m_layerName = &layer.name;
}
}
}
template void UniqueResult::checkEntry(const DNAMP1::PAKBridge& pakBridge,
const DNAMP1::PAKBridge::PAKType::Entry& entry);
template void UniqueResult::checkEntry(const DNAMP2::PAKBridge& pakBridge,
const DNAMP2::PAKBridge::PAKType::Entry& entry);
template void UniqueResult::checkEntry(const DNAMP3::PAKBridge& pakBridge,
const DNAMP3::PAKBridge::PAKType::Entry& entry);
HECL::ProjectPath UniqueResult::uniquePath(const HECL::ProjectPath& pakPath) const
{
if (m_type == Type::Pak)
return pakPath;
HECL::ProjectPath levelDir;
if (m_levelName)
levelDir.assign(pakPath, *m_levelName);
else
levelDir = pakPath;
levelDir.makeDir();
if (m_type == Type::Area)
{
HECL::ProjectPath areaDir(levelDir, *m_areaName);
areaDir.makeDir();
return areaDir;
}
else if (m_type == Type::Layer)
{
HECL::ProjectPath areaDir(levelDir, *m_areaName);
areaDir.makeDir();
HECL::ProjectPath layerDir(areaDir, *m_layerName);
layerDir.makeDir();
return layerDir;
}
return levelDir;
}
template <class BRIDGETYPE>
void PAKRouter<BRIDGETYPE>::build(std::vector<BRIDGETYPE>& bridges, std::function<void(float)> progress)
{
m_bridges = &bridges;
m_bridgePaths.clear();
m_uniqueEntries.clear();
m_sharedEntries.clear();
m_cmdlRigs.clear();
size_t count = 0;
float bridgesSz = bridges.size();
/* Route entries unique/shared per-pak */
size_t bridgeIdx = 0;
for (BRIDGETYPE& bridge : bridges)
{
const std::string& name = bridge.getName();
HECL::SystemStringView sysName(name);
HECL::SystemString::const_iterator extit = sysName.sys_str().end() - 4;
HECL::SystemString baseName(sysName.sys_str().begin(), extit);
m_bridgePaths.emplace_back(std::make_pair(HECL::ProjectPath(m_gameWorking, baseName),
HECL::ProjectPath(m_gameCooked, baseName)));
/* Index this PAK */
bridge.build();
/* Add to global entry lookup */
const typename BRIDGETYPE::PAKType& pak = bridge.getPAK();
for (const auto& entry : pak.m_idMap)
{
if (!pak.m_noShare)
{
auto sSearch = m_sharedEntries.find(entry.first);
if (sSearch != m_sharedEntries.end())
continue;
auto uSearch = m_uniqueEntries.find(entry.first);
if (uSearch != m_uniqueEntries.end())
{
m_uniqueEntries.erase(uSearch);
m_sharedEntries[entry.first] = std::make_pair(bridgeIdx, entry.second);
}
else
m_uniqueEntries[entry.first] = std::make_pair(bridgeIdx, entry.second);
}
else
m_uniqueEntries[entry.first] = std::make_pair(bridgeIdx, entry.second);
}
/* Add RigPairs to global map */
bridge.addCMDLRigPairs(*this, m_cmdlRigs);
progress(++count / bridgesSz);
++bridgeIdx;
}
/* Add named resources to catalog YAML files */
for (BRIDGETYPE& bridge : bridges)
{
Athena::io::YAMLDocWriter catalogWriter(nullptr);
enterPAKBridge(bridge);
const typename BRIDGETYPE::PAKType& pak = bridge.getPAK();
for (const auto& namedEntry : pak.m_nameEntries)
{
catalogWriter.enterSubRecord(namedEntry.name.c_str());
catalogWriter.writeString(nullptr, getWorking(namedEntry.id).getRelativePathUTF8().c_str());
catalogWriter.leaveSubRecord();
}
/* Write catalog */
const HECL::ProjectPath& pakPath = m_bridgePaths[m_curBridgeIdx].first;
HECL::SystemString catalogPath = HECL::ProjectPath(pakPath, "catalog.yaml").getAbsolutePath();
FILE* catalog = HECL::Fopen(catalogPath.c_str(), _S("w"));
yaml_emitter_set_output_file(catalogWriter.getEmitter(), catalog);
catalogWriter.finish();
fclose(catalog);
}
}
template <class BRIDGETYPE>
void PAKRouter<BRIDGETYPE>::enterPAKBridge(const BRIDGETYPE& pakBridge)
{
g_PakRouter = this;
auto pit = m_bridgePaths.begin();
size_t bridgeIdx = 0;
for (const BRIDGETYPE& bridge : *m_bridges)
{
if (&bridge == &pakBridge)
{
pit->first.makeDir();
pit->second.makeDir();
m_pak = &pakBridge.getPAK();
m_node = &pakBridge.getNode();
m_curBridgeIdx = bridgeIdx;
return;
}
++pit;
++bridgeIdx;
}
LogDNACommon.report(LogVisor::FatalError,
"PAKBridge provided to PAKRouter::enterPAKBridge() was not part of build()");
}
template <class BRIDGETYPE>
HECL::ProjectPath PAKRouter<BRIDGETYPE>::getWorking(const EntryType* entry,
const ResExtractor<BRIDGETYPE>& extractor) const
{
if (!entry)
return HECL::ProjectPath();
if (!m_pak)
LogDNACommon.report(LogVisor::FatalError,
"PAKRouter::enterPAKBridge() must be called before PAKRouter::getWorkingPath()");
if (m_pak->m_noShare)
{
const EntryType* singleSearch = m_pak->lookupEntry(entry->id);
if (singleSearch)
{
const HECL::ProjectPath& pakPath = m_bridgePaths[m_curBridgeIdx].first;
pakPath.makeDir();
#if HECL_UCS2
HECL::SystemString entName = HECL::UTF8ToWide(getBestEntryName(*entry));
#else
HECL::SystemString entName = getBestEntryName(*entry);
#endif
if (extractor.fileExts[0] && !extractor.fileExts[1])
entName += extractor.fileExts[0];
return HECL::ProjectPath(pakPath, entName);
}
}
auto uniqueSearch = m_uniqueEntries.find(entry->id);
if (uniqueSearch != m_uniqueEntries.end())
{
const HECL::ProjectPath& pakPath = m_bridgePaths[uniqueSearch->second.first].first;
pakPath.makeDir();
HECL::ProjectPath uniquePath = entry->unique.uniquePath(pakPath);
#if HECL_UCS2
HECL::SystemString entName = HECL::UTF8ToWide(getBestEntryName(*entry));
#else
HECL::SystemString entName = getBestEntryName(*entry);
#endif
if (extractor.fileExts[0] && !extractor.fileExts[1])
entName += extractor.fileExts[0];
return HECL::ProjectPath(uniquePath, entName);
}
auto sharedSearch = m_sharedEntries.find(entry->id);
if (sharedSearch != m_sharedEntries.end())
{
#if HECL_UCS2
HECL::SystemString entBase = HECL::UTF8ToWide(getBestEntryName(*entry));
#else
HECL::SystemString entBase = getBestEntryName(*entry);
#endif
HECL::SystemString entName = entBase;
if (extractor.fileExts[0] && !extractor.fileExts[1])
entName += extractor.fileExts[0];
HECL::ProjectPath sharedPath(m_sharedWorking, entName);
m_sharedWorking.makeDir();
return sharedPath;
}
LogDNACommon.report(LogVisor::FatalError, "Unable to find entry %s", entry->id.toString().c_str());
return HECL::ProjectPath();
}
template <class BRIDGETYPE>
HECL::ProjectPath PAKRouter<BRIDGETYPE>::getWorking(const EntryType* entry) const
{
if (!entry)
return HECL::ProjectPath();
return getWorking(entry, BRIDGETYPE::LookupExtractor(*entry));
}
template <class BRIDGETYPE>
HECL::ProjectPath PAKRouter<BRIDGETYPE>::getWorking(const IDType& id) const
{
return getWorking(lookupEntry(id));
}
template <class BRIDGETYPE>
HECL::ProjectPath PAKRouter<BRIDGETYPE>::getCooked(const EntryType* entry) const
{
if (!entry)
return HECL::ProjectPath();
if (!m_pak)
LogDNACommon.report(LogVisor::FatalError,
"PAKRouter::enterPAKBridge() must be called before PAKRouter::getCookedPath()");
if (m_pak->m_noShare)
{
const EntryType* singleSearch = m_pak->lookupEntry(entry->id);
if (singleSearch)
{
const HECL::ProjectPath& pakPath = m_bridgePaths[m_curBridgeIdx].second;
pakPath.makeDir();
return HECL::ProjectPath(pakPath, getBestEntryName(*entry));
}
}
auto uniqueSearch = m_uniqueEntries.find(entry->id);
if (uniqueSearch != m_uniqueEntries.end())
{
const HECL::ProjectPath& pakPath = m_bridgePaths[uniqueSearch->second.first].second;
pakPath.makeDir();
HECL::ProjectPath uniquePath = entry->unique.uniquePath(pakPath);
return HECL::ProjectPath(uniquePath, getBestEntryName(*entry));
}
auto sharedSearch = m_sharedEntries.find(entry->id);
if (sharedSearch != m_sharedEntries.end())
{
m_sharedCooked.makeDir();
return HECL::ProjectPath(m_sharedCooked, getBestEntryName(*entry));
}
LogDNACommon.report(LogVisor::FatalError, "Unable to find entry %s", entry->id.toString().c_str());
return HECL::ProjectPath();
}
template <class BRIDGETYPE>
HECL::ProjectPath PAKRouter<BRIDGETYPE>::getCooked(const IDType& id) const
{
return getCooked(lookupEntry(id));
}
template <class BRIDGETYPE>
HECL::SystemString PAKRouter<BRIDGETYPE>::getResourceRelativePath(const EntryType& a, const IDType& b) const
{
if (!m_pak)
LogDNACommon.report(LogVisor::FatalError,
"PAKRouter::enterPAKBridge() must be called before PAKRouter::getResourceRelativePath()");
const typename BRIDGETYPE::PAKType::Entry* be = lookupEntry(b);
if (!be)
return HECL::SystemString();
HECL::ProjectPath aPath = getWorking(&a, BRIDGETYPE::LookupExtractor(a));
HECL::SystemString ret;
for (int i=0 ; i<aPath.levelCount() ; ++i)
ret += _S("../");
HECL::ProjectPath bPath = getWorking(be, BRIDGETYPE::LookupExtractor(*be));
ret += bPath.getRelativePath();
return ret;
}
template <class BRIDGETYPE>
std::string PAKRouter<BRIDGETYPE>::getBestEntryName(const EntryType& entry) const
{
std::string name;
for (const BRIDGETYPE& bridge : *m_bridges)
{
const typename BRIDGETYPE::PAKType& pak = bridge.getPAK();
bool named;
name = pak.bestEntryName(entry, named);
if (named)
return name;
}
return name;
}
template <class BRIDGETYPE>
std::string PAKRouter<BRIDGETYPE>::getBestEntryName(const IDType& entry) const
{
std::string name;
for (const BRIDGETYPE& bridge : *m_bridges)
{
const typename BRIDGETYPE::PAKType& pak = bridge.getPAK();
const typename BRIDGETYPE::PAKType::Entry* e = pak.lookupEntry(entry);
if (!e)
continue;
bool named;
name = pak.bestEntryName(*e, named);
if (named)
return name;
}
return name;
}
template <class BRIDGETYPE>
bool PAKRouter<BRIDGETYPE>::extractResources(const BRIDGETYPE& pakBridge, bool force,
std::function<void(const HECL::SystemChar*, float)> progress)
{
enterPAKBridge(pakBridge);
size_t count = 0;
size_t sz = m_pak->m_idMap.size();
float fsz = sz;
for (unsigned w=0 ; count<sz ; ++w)
{
for (const auto& item : m_pak->m_firstEntries)
{
ResExtractor<BRIDGETYPE> extractor = BRIDGETYPE::LookupExtractor(*item);
if (extractor.weight != w)
continue;
std::string bestName = getBestEntryName(*item);
HECL::SystemStringView bestNameView(bestName);
float thisFac = ++count / fsz;
progress(bestNameView.sys_str().c_str(), thisFac);
/* Extract first, so they start out invalid */
HECL::ProjectPath cooked = getCooked(item);
if (force || cooked.getPathType() == HECL::ProjectPath::Type::None)
{
PAKEntryReadStream s = item->beginReadStream(*m_node);
FILE* fout = HECL::Fopen(cooked.getAbsolutePath().c_str(), _S("wb"));
fwrite(s.data(), 1, s.length(), fout);
fclose(fout);
}
HECL::ProjectPath working = getWorking(item, extractor);
if (extractor.func_a) /* Doesn't need PAKRouter access */
{
if (force || working.getPathType() == HECL::ProjectPath::Type::None)
{
PAKEntryReadStream s = item->beginReadStream(*m_node);
extractor.func_a(s, working);
}
}
else if (extractor.func_b) /* Needs PAKRouter access */
{
if (force || working.getPathType() == HECL::ProjectPath::Type::None)
{
PAKEntryReadStream s = item->beginReadStream(*m_node);
extractor.func_b(m_dataSpec, s, working, *this, *item, force,
[&progress, thisFac](const HECL::SystemChar* update)
{
progress(update, thisFac);
});
}
}
}
}
return true;
}
template <class BRIDGETYPE>
const typename BRIDGETYPE::PAKType::Entry* PAKRouter<BRIDGETYPE>::lookupEntry(const IDType& entry,
const NOD::Node** nodeOut,
bool silenceWarnings,
bool currentPAK) const
{
if (!entry)
return nullptr;
if (!m_bridges)
LogDNACommon.report(LogVisor::FatalError,
"PAKRouter::build() must be called before PAKRouter::lookupEntry()");
if (m_pak)
{
const EntryType* ent = m_pak->lookupEntry(entry);
if (ent)
{
if (nodeOut)
*nodeOut = m_node;
return ent;
}
}
if (currentPAK)
{
if (!silenceWarnings)
LogDNACommon.report(LogVisor::Warning,
"unable to find PAK entry %s in current PAK", entry.toString().c_str());
return nullptr;
}
for (const BRIDGETYPE& bridge : *m_bridges)
{
const PAKType& pak = bridge.getPAK();
const EntryType* ent = pak.lookupEntry(entry);
if (ent)
{
if (nodeOut)
*nodeOut = &bridge.getNode();
return ent;
}
}
if (!silenceWarnings)
LogDNACommon.report(LogVisor::Warning,
"unable to find PAK entry %s", entry.toString().c_str());
if (nodeOut)
*nodeOut = nullptr;
return nullptr;
}
template <class BRIDGETYPE>
const typename PAKRouter<BRIDGETYPE>::RigPair* PAKRouter<BRIDGETYPE>::lookupCMDLRigPair(const IDType& id) const
{
auto search = m_cmdlRigs.find(id);
if (search == m_cmdlRigs.end())
return nullptr;
return &search->second;
}
template <class BRIDGETYPE>
HECL::ProjectPath PAKRouter<BRIDGETYPE>::getAreaLayerWorking(const IDType& areaId, int layerIdx) const
{
if (!m_bridges)
LogDNACommon.report(LogVisor::FatalError,
"PAKRouter::build() must be called before PAKRouter::getAreaLayerWorking()");
auto bridgePathIt = m_bridgePaths.cbegin();
for (const BRIDGETYPE& bridge : *m_bridges)
{
for (const auto& level : bridge.m_levelDeps)
for (const auto& area : level.second.areas)
if (area.first == areaId)
{
HECL::ProjectPath levelPath(bridgePathIt->first, level.second.name);
HECL::ProjectPath areaPath(levelPath, area.second.name);
if (layerIdx < 0)
return areaPath;
return HECL::ProjectPath(areaPath, area.second.layers.at(layerIdx).name);
}
++bridgePathIt;
}
return HECL::ProjectPath();
}
template <class BRIDGETYPE>
HECL::ProjectPath PAKRouter<BRIDGETYPE>::getAreaLayerCooked(const IDType& areaId, int layerIdx) const
{
if (!m_bridges)
LogDNACommon.report(LogVisor::FatalError,
"PAKRouter::build() must be called before PAKRouter::getAreaLayerCooked()");
auto bridgePathIt = m_bridgePaths.cbegin();
for (const BRIDGETYPE& bridge : *m_bridges)
{
for (const auto& level : bridge.m_levelDeps)
for (const auto& area : level.second.areas)
if (area.first == areaId)
{
HECL::ProjectPath levelPath(bridgePathIt->second, level.second.name);
HECL::ProjectPath areaPath(levelPath, area.second.name);
if (layerIdx < 0)
return areaPath;
return HECL::ProjectPath(areaPath, area.second.layers.at(layerIdx).name);
}
++bridgePathIt;
}
return HECL::ProjectPath();
}
template class PAKRouter<DNAMP1::PAKBridge>;
template class PAKRouter<DNAMP2::PAKBridge>;
template class PAKRouter<DNAMP3::PAKBridge>;
}

View File

@ -66,131 +66,10 @@ struct UniqueResult
UniqueResult() = default;
UniqueResult(Type tp) : m_type(tp) {}
template<class PAKBRIDGE>
void checkEntry(const PAKBRIDGE& pakBridge, const typename PAKBRIDGE::PAKType::Entry& entry)
{
UniqueResult::Type resultType = UniqueResult::Type::NotFound;
bool foundOneLayer = false;
const HECL::SystemString* levelName = nullptr;
typename PAKBRIDGE::PAKType::IDType levelId;
typename PAKBRIDGE::PAKType::IDType areaId;
unsigned layerIdx;
for (const auto& lpair : pakBridge.m_levelDeps)
{
if (entry.id == lpair.first)
{
levelName = &lpair.second.name;
resultType = UniqueResult::Type::Level;
break;
}
template <class PAKBRIDGE>
void checkEntry(const PAKBRIDGE& pakBridge, const typename PAKBRIDGE::PAKType::Entry& entry);
for (const auto& pair : lpair.second.areas)
{
unsigned l=0;
for (const auto& layer : pair.second.layers)
{
if (layer.resources.find(entry.id) != layer.resources.end())
{
if (foundOneLayer)
{
if (areaId == pair.first)
{
resultType = UniqueResult::Type::Area;
}
else if (levelId == lpair.first)
{
resultType = UniqueResult::Type::Level;
break;
}
else
{
m_type = UniqueResult::Type::Pak;
return;
}
continue;
}
else
resultType = UniqueResult::Type::Layer;
levelName = &lpair.second.name;
levelId = lpair.first;
areaId = pair.first;
layerIdx = l;
foundOneLayer = true;
}
++l;
}
if (pair.second.resources.find(entry.id) != pair.second.resources.end())
{
if (foundOneLayer)
{
if (areaId == pair.first)
{
resultType = UniqueResult::Type::Area;
}
else if (levelId == lpair.first)
{
resultType = UniqueResult::Type::Level;
break;
}
else
{
m_type = UniqueResult::Type::Pak;
return;
}
continue;
}
else
resultType = UniqueResult::Type::Area;
levelName = &lpair.second.name;
levelId = lpair.first;
areaId = pair.first;
foundOneLayer = true;
}
}
}
m_type = resultType;
m_levelName = levelName;
if (resultType == UniqueResult::Type::Layer || resultType == UniqueResult::Type::Area)
{
const typename PAKBRIDGE::Level::Area& area = pakBridge.m_levelDeps.at(levelId).areas.at(areaId);
m_areaName = &area.name;
if (resultType == UniqueResult::Type::Layer)
{
const typename PAKBRIDGE::Level::Area::Layer& layer = area.layers[layerIdx];
m_layerName = &layer.name;
}
}
}
HECL::ProjectPath uniquePath(const HECL::ProjectPath& pakPath) const
{
if (m_type == Type::Pak)
return pakPath;
HECL::ProjectPath levelDir;
if (m_levelName)
levelDir.assign(pakPath, *m_levelName);
else
levelDir = pakPath;
levelDir.makeDir();
if (m_type == Type::Area)
{
HECL::ProjectPath areaDir(levelDir, *m_areaName);
areaDir.makeDir();
return areaDir;
}
else if (m_type == Type::Layer)
{
HECL::ProjectPath areaDir(levelDir, *m_areaName);
areaDir.makeDir();
HECL::ProjectPath layerDir(areaDir, *m_layerName);
layerDir.makeDir();
return layerDir;
}
return levelDir;
}
HECL::ProjectPath uniquePath(const HECL::ProjectPath& pakPath) const;
};
template <class BRIDGETYPE>
@ -258,375 +137,29 @@ public:
m_gameWorking(working), m_gameCooked(cooked),
m_sharedWorking(working, "Shared"), m_sharedCooked(cooked, "Shared") {}
void build(std::vector<BRIDGETYPE>& bridges, std::function<void(float)> progress)
{
m_bridges = &bridges;
m_bridgePaths.clear();
void build(std::vector<BRIDGETYPE>& bridges, std::function<void(float)> progress);
m_uniqueEntries.clear();
m_sharedEntries.clear();
m_cmdlRigs.clear();
size_t count = 0;
float bridgesSz = bridges.size();
/* Route entries unique/shared per-pak */
size_t bridgeIdx = 0;
for (BRIDGETYPE& bridge : bridges)
{
const std::string& name = bridge.getName();
HECL::SystemStringView sysName(name);
HECL::SystemString::const_iterator extit = sysName.sys_str().end() - 4;
HECL::SystemString baseName(sysName.sys_str().begin(), extit);
m_bridgePaths.emplace_back(std::make_pair(HECL::ProjectPath(m_gameWorking, baseName),
HECL::ProjectPath(m_gameCooked, baseName)));
/* Index this PAK */
bridge.build();
/* Add to global entry lookup */
const typename BRIDGETYPE::PAKType& pak = bridge.getPAK();
for (const auto& entry : pak.m_idMap)
{
if (!pak.m_noShare)
{
auto sSearch = m_sharedEntries.find(entry.first);
if (sSearch != m_sharedEntries.end())
continue;
auto uSearch = m_uniqueEntries.find(entry.first);
if (uSearch != m_uniqueEntries.end())
{
m_uniqueEntries.erase(uSearch);
m_sharedEntries[entry.first] = std::make_pair(bridgeIdx, entry.second);
}
else
m_uniqueEntries[entry.first] = std::make_pair(bridgeIdx, entry.second);
}
else
m_uniqueEntries[entry.first] = std::make_pair(bridgeIdx, entry.second);
}
/* Add RigPairs to global map */
bridge.addCMDLRigPairs(*this, m_cmdlRigs);
progress(++count / bridgesSz);
++bridgeIdx;
}
/* Add named resources to catalog YAML files */
for (BRIDGETYPE& bridge : bridges)
{
Athena::io::YAMLDocWriter catalogWriter(nullptr);
enterPAKBridge(bridge);
const typename BRIDGETYPE::PAKType& pak = bridge.getPAK();
for (const auto& namedEntry : pak.m_nameEntries)
{
catalogWriter.enterSubRecord(namedEntry.name.c_str());
catalogWriter.writeString(nullptr, getWorking(namedEntry.id).getRelativePathUTF8().c_str());
catalogWriter.leaveSubRecord();
}
/* Write catalog */
const HECL::ProjectPath& pakPath = m_bridgePaths[m_curBridgeIdx].first;
HECL::SystemString catalogPath = HECL::ProjectPath(pakPath, "catalog.yaml").getAbsolutePath();
FILE* catalog = HECL::Fopen(catalogPath.c_str(), _S("w"));
yaml_emitter_set_output_file(catalogWriter.getEmitter(), catalog);
catalogWriter.finish();
fclose(catalog);
}
}
void enterPAKBridge(const BRIDGETYPE& pakBridge)
{
g_PakRouter = this;
auto pit = m_bridgePaths.begin();
size_t bridgeIdx = 0;
for (const BRIDGETYPE& bridge : *m_bridges)
{
if (&bridge == &pakBridge)
{
pit->first.makeDir();
pit->second.makeDir();
m_pak = &pakBridge.getPAK();
m_node = &pakBridge.getNode();
m_curBridgeIdx = bridgeIdx;
return;
}
++pit;
++bridgeIdx;
}
LogDNACommon.report(LogVisor::FatalError, "PAKBridge provided to PAKRouter::enterPAKBridge() was not part of build()");
}
void enterPAKBridge(const BRIDGETYPE& pakBridge);
HECL::ProjectPath getWorking(const EntryType* entry,
const ResExtractor<BRIDGETYPE>& extractor) const
{
if (!entry)
return HECL::ProjectPath();
if (!m_pak)
LogDNACommon.report(LogVisor::FatalError,
"PAKRouter::enterPAKBridge() must be called before PAKRouter::getWorkingPath()");
if (m_pak->m_noShare)
{
const EntryType* singleSearch = m_pak->lookupEntry(entry->id);
if (singleSearch)
{
const HECL::ProjectPath& pakPath = m_bridgePaths[m_curBridgeIdx].first;
pakPath.makeDir();
#if HECL_UCS2
HECL::SystemString entName = HECL::UTF8ToWide(getBestEntryName(*entry));
#else
HECL::SystemString entName = getBestEntryName(*entry);
#endif
if (extractor.fileExts[0] && !extractor.fileExts[1])
entName += extractor.fileExts[0];
return HECL::ProjectPath(pakPath, entName);
}
}
const ResExtractor<BRIDGETYPE>& extractor) const;
HECL::ProjectPath getWorking(const EntryType* entry) const;
HECL::ProjectPath getWorking(const IDType& id) const;
HECL::ProjectPath getCooked(const EntryType* entry) const;
HECL::ProjectPath getCooked(const IDType& id) const;
auto uniqueSearch = m_uniqueEntries.find(entry->id);
if (uniqueSearch != m_uniqueEntries.end())
{
const HECL::ProjectPath& pakPath = m_bridgePaths[uniqueSearch->second.first].first;
pakPath.makeDir();
HECL::ProjectPath uniquePath = entry->unique.uniquePath(pakPath);
#if HECL_UCS2
HECL::SystemString entName = HECL::UTF8ToWide(getBestEntryName(*entry));
#else
HECL::SystemString entName = getBestEntryName(*entry);
#endif
if (extractor.fileExts[0] && !extractor.fileExts[1])
entName += extractor.fileExts[0];
return HECL::ProjectPath(uniquePath, entName);
}
HECL::SystemString getResourceRelativePath(const EntryType& a, const IDType& b) const;
auto sharedSearch = m_sharedEntries.find(entry->id);
if (sharedSearch != m_sharedEntries.end())
{
#if HECL_UCS2
HECL::SystemString entBase = HECL::UTF8ToWide(getBestEntryName(*entry));
#else
HECL::SystemString entBase = getBestEntryName(*entry);
#endif
HECL::SystemString entName = entBase;
if (extractor.fileExts[0] && !extractor.fileExts[1])
entName += extractor.fileExts[0];
HECL::ProjectPath sharedPath(m_sharedWorking, entName);
m_sharedWorking.makeDir();
return sharedPath;
}
LogDNACommon.report(LogVisor::FatalError, "Unable to find entry %s", entry->id.toString().c_str());
return HECL::ProjectPath();
}
HECL::ProjectPath getWorking(const EntryType* entry) const
{
if (!entry)
return HECL::ProjectPath();
return getWorking(entry, BRIDGETYPE::LookupExtractor(*entry));
}
HECL::ProjectPath getWorking(const IDType& id) const
{
return getWorking(lookupEntry(id));
}
HECL::ProjectPath getCooked(const EntryType* entry) const
{
if (!entry)
return HECL::ProjectPath();
if (!m_pak)
LogDNACommon.report(LogVisor::FatalError,
"PAKRouter::enterPAKBridge() must be called before PAKRouter::getCookedPath()");
if (m_pak->m_noShare)
{
const EntryType* singleSearch = m_pak->lookupEntry(entry->id);
if (singleSearch)
{
const HECL::ProjectPath& pakPath = m_bridgePaths[m_curBridgeIdx].second;
pakPath.makeDir();
return HECL::ProjectPath(pakPath, getBestEntryName(*entry));
}
}
auto uniqueSearch = m_uniqueEntries.find(entry->id);
if (uniqueSearch != m_uniqueEntries.end())
{
const HECL::ProjectPath& pakPath = m_bridgePaths[uniqueSearch->second.first].second;
pakPath.makeDir();
HECL::ProjectPath uniquePath = entry->unique.uniquePath(pakPath);
return HECL::ProjectPath(uniquePath, getBestEntryName(*entry));
}
auto sharedSearch = m_sharedEntries.find(entry->id);
if (sharedSearch != m_sharedEntries.end())
{
m_sharedCooked.makeDir();
return HECL::ProjectPath(m_sharedCooked, getBestEntryName(*entry));
}
LogDNACommon.report(LogVisor::FatalError, "Unable to find entry %s", entry->id.toString().c_str());
return HECL::ProjectPath();
}
HECL::ProjectPath getCooked(const IDType& id) const
{
return getCooked(lookupEntry(id));
}
HECL::SystemString getResourceRelativePath(const EntryType& a, const IDType& b) const
{
if (!m_pak)
LogDNACommon.report(LogVisor::FatalError,
"PAKRouter::enterPAKBridge() must be called before PAKRouter::getResourceRelativePath()");
const typename BRIDGETYPE::PAKType::Entry* be = lookupEntry(b);
if (!be)
return HECL::SystemString();
HECL::ProjectPath aPath = getWorking(&a, BRIDGETYPE::LookupExtractor(a));
HECL::SystemString ret;
for (int i=0 ; i<aPath.levelCount() ; ++i)
ret += _S("../");
HECL::ProjectPath bPath = getWorking(be, BRIDGETYPE::LookupExtractor(*be));
ret += bPath.getRelativePath();
return ret;
}
std::string getBestEntryName(const EntryType& entry) const
{
std::string name;
for (const BRIDGETYPE& bridge : *m_bridges)
{
const typename BRIDGETYPE::PAKType& pak = bridge.getPAK();
bool named;
name = pak.bestEntryName(entry, named);
if (named)
return name;
}
return name;
}
std::string getBestEntryName(const IDType& entry) const
{
std::string name;
for (const BRIDGETYPE& bridge : *m_bridges)
{
const typename BRIDGETYPE::PAKType& pak = bridge.getPAK();
const typename BRIDGETYPE::PAKType::Entry* e = pak.lookupEntry(entry);
if (!e)
continue;
bool named;
name = pak.bestEntryName(*e, named);
if (named)
return name;
}
return name;
}
std::string getBestEntryName(const EntryType& entry) const;
std::string getBestEntryName(const IDType& entry) const;
bool extractResources(const BRIDGETYPE& pakBridge, bool force,
std::function<void(const HECL::SystemChar*, float)> progress)
{
enterPAKBridge(pakBridge);
size_t count = 0;
size_t sz = m_pak->m_idMap.size();
float fsz = sz;
for (unsigned w=0 ; count<sz ; ++w)
{
for (const auto& item : m_pak->m_firstEntries)
{
ResExtractor<BRIDGETYPE> extractor = BRIDGETYPE::LookupExtractor(*item);
if (extractor.weight != w)
continue;
std::string bestName = getBestEntryName(*item);
HECL::SystemStringView bestNameView(bestName);
float thisFac = ++count / fsz;
progress(bestNameView.sys_str().c_str(), thisFac);
/* Extract first, so they start out invalid */
HECL::ProjectPath cooked = getCooked(item);
if (force || cooked.getPathType() == HECL::ProjectPath::Type::None)
{
PAKEntryReadStream s = item->beginReadStream(*m_node);
FILE* fout = HECL::Fopen(cooked.getAbsolutePath().c_str(), _S("wb"));
fwrite(s.data(), 1, s.length(), fout);
fclose(fout);
}
HECL::ProjectPath working = getWorking(item, extractor);
if (extractor.func_a) /* Doesn't need PAKRouter access */
{
if (force || working.getPathType() == HECL::ProjectPath::Type::None)
{
PAKEntryReadStream s = item->beginReadStream(*m_node);
extractor.func_a(s, working);
}
}
else if (extractor.func_b) /* Needs PAKRouter access */
{
if (force || working.getPathType() == HECL::ProjectPath::Type::None)
{
PAKEntryReadStream s = item->beginReadStream(*m_node);
extractor.func_b(m_dataSpec, s, working, *this, *item, force,
[&progress, thisFac](const HECL::SystemChar* update)
{
progress(update, thisFac);
});
}
}
}
}
return true;
}
std::function<void(const HECL::SystemChar*, float)> progress);
const typename BRIDGETYPE::PAKType::Entry* lookupEntry(const IDType& entry,
const NOD::Node** nodeOut=nullptr,
bool silenceWarnings=false,
bool currentPAK=false) const
{
if (!entry)
return nullptr;
if (!m_bridges)
LogDNACommon.report(LogVisor::FatalError,
"PAKRouter::build() must be called before PAKRouter::lookupEntry()");
if (m_pak)
{
const EntryType* ent = m_pak->lookupEntry(entry);
if (ent)
{
if (nodeOut)
*nodeOut = m_node;
return ent;
}
}
if (currentPAK)
{
if (!silenceWarnings)
LogDNACommon.report(LogVisor::Warning, "unable to find PAK entry %s in current PAK", entry.toString().c_str());
return nullptr;
}
for (const BRIDGETYPE& bridge : *m_bridges)
{
const PAKType& pak = bridge.getPAK();
const EntryType* ent = pak.lookupEntry(entry);
if (ent)
{
if (nodeOut)
*nodeOut = &bridge.getNode();
return ent;
}
}
if (!silenceWarnings)
LogDNACommon.report(LogVisor::Warning, "unable to find PAK entry %s", entry.toString().c_str());
if (nodeOut)
*nodeOut = nullptr;
return nullptr;
}
bool currentPAK=false) const;
template <typename DNA>
bool lookupAndReadDNA(const IDType& id, DNA& out, bool silenceWarnings=false)
@ -640,59 +173,10 @@ public:
return true;
}
const RigPair* lookupCMDLRigPair(const IDType& id) const
{
auto search = m_cmdlRigs.find(id);
if (search == m_cmdlRigs.end())
return nullptr;
return &search->second;
}
const RigPair* lookupCMDLRigPair(const IDType& id) const;
HECL::ProjectPath getAreaLayerWorking(const IDType& areaId, int layerIdx) const
{
if (!m_bridges)
LogDNACommon.report(LogVisor::FatalError,
"PAKRouter::build() must be called before PAKRouter::getAreaLayerWorking()");
auto bridgePathIt = m_bridgePaths.cbegin();
for (const BRIDGETYPE& bridge : *m_bridges)
{
for (const auto& level : bridge.m_levelDeps)
for (const auto& area : level.second.areas)
if (area.first == areaId)
{
HECL::ProjectPath levelPath(bridgePathIt->first, level.second.name);
HECL::ProjectPath areaPath(levelPath, area.second.name);
if (layerIdx < 0)
return areaPath;
return HECL::ProjectPath(areaPath, area.second.layers.at(layerIdx).name);
}
++bridgePathIt;
}
return HECL::ProjectPath();
}
HECL::ProjectPath getAreaLayerCooked(const IDType& areaId, int layerIdx) const
{
if (!m_bridges)
LogDNACommon.report(LogVisor::FatalError,
"PAKRouter::build() must be called before PAKRouter::getAreaLayerCooked()");
auto bridgePathIt = m_bridgePaths.cbegin();
for (const BRIDGETYPE& bridge : *m_bridges)
{
for (const auto& level : bridge.m_levelDeps)
for (const auto& area : level.second.areas)
if (area.first == areaId)
{
HECL::ProjectPath levelPath(bridgePathIt->second, level.second.name);
HECL::ProjectPath areaPath(levelPath, area.second.name);
if (layerIdx < 0)
return areaPath;
return HECL::ProjectPath(areaPath, area.second.layers.at(layerIdx).name);
}
++bridgePathIt;
}
return HECL::ProjectPath();
}
HECL::ProjectPath getAreaLayerWorking(const IDType& areaId, int layerIdx) const;
HECL::ProjectPath getAreaLayerCooked(const IDType& areaId, int layerIdx) const;
};
}

1571
DataSpec/DNACommon/PART.cpp Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff