diff --git a/DataSpec/DNACommon/DeafBabe.cpp b/DataSpec/DNACommon/DeafBabe.cpp index c5dd2c992..eaf384e5e 100644 --- a/DataSpec/DNACommon/DeafBabe.cpp +++ b/DataSpec/DNACommon/DeafBabe.cpp @@ -2,13 +2,14 @@ #include "AROTBuilder.hpp" #include "DataSpec/DNAMP1/DeafBabe.hpp" #include "DataSpec/DNAMP2/DeafBabe.hpp" +#include "DataSpec/DNAMP1/DCLN.hpp" #include namespace DataSpec { template -void DeafBabeSendToBlender(hecl::BlenderConnection::PyOutStream& os, const DEAFBABE& db) +void DeafBabeSendToBlender(hecl::BlenderConnection::PyOutStream& os, const DEAFBABE& db, bool isDcln, atInt32 idx) { os << "material_index = []\n" "col_bm = bmesh.new()\n"; @@ -50,8 +51,12 @@ void DeafBabeSendToBlender(hecl::BlenderConnection::PyOutStream& os, const DEAFB db.insertNoClimb(os); - os << "col_mesh = bpy.data.meshes.new('CMESH')\n" - "col_bm.to_mesh(col_mesh)\n" + if (isDcln) + os.format("col_mesh = bpy.data.meshes.new('CMESH_%i')\n", idx); + else + os << "col_mesh = bpy.data.meshes.new('CMESH')\n"; + + os << "col_bm.to_mesh(col_mesh)\n" "col_mesh_obj = bpy.data.objects.new(col_mesh.name, col_mesh)\n" "\n" "for mat_name in material_index:\n" @@ -61,18 +66,22 @@ void DeafBabeSendToBlender(hecl::BlenderConnection::PyOutStream& os, const DEAFB "bpy.context.scene.objects.link(col_mesh_obj)\n" "bpy.context.scene.objects.active = col_mesh_obj\n" "bpy.ops.object.mode_set(mode='EDIT')\n" - "bpy.ops.mesh.tris_convert_to_quads(materials=True)\n" + "bpy.ops.mesh.tris_convert_to_quads()\n" "bpy.ops.object.mode_set(mode='OBJECT')\n" - "bpy.context.scene.objects.active = None\n" - "col_mesh_obj.layers[1] = True\n" - "col_mesh_obj.layers[0] = False\n" - "col_mesh_obj.draw_type = 'SOLID'\n" + "bpy.context.scene.objects.active = None\n"; + if (!isDcln) + os << "col_mesh_obj.layers[1] = True\n" + "col_mesh_obj.layers[0] = False\n"; + + + os << "col_mesh_obj.draw_type = 'SOLID'\n" "col_mesh_obj.game.physics_type = 'STATIC'\n" "\n"; } -template void DeafBabeSendToBlender(hecl::BlenderConnection::PyOutStream& os, const DNAMP1::DeafBabe& db); -template void DeafBabeSendToBlender(hecl::BlenderConnection::PyOutStream& os, const DNAMP2::DeafBabe& db); +template void DeafBabeSendToBlender(hecl::BlenderConnection::PyOutStream& os, const DNAMP1::DeafBabe& db, bool isDcln, atInt32 idx); +template void DeafBabeSendToBlender(hecl::BlenderConnection::PyOutStream& os, const DNAMP2::DeafBabe& db, bool isDcln, atInt32 idx); +template void DeafBabeSendToBlender(hecl::BlenderConnection::PyOutStream& os, const DNAMP1::DCLN::Collision& db, bool isDcln, atInt32 idx); template void DeafBabeBuildFromBlender(DEAFBABE& db, const hecl::BlenderConnection::DataStream::ColMesh& colMesh) diff --git a/DataSpec/DNACommon/DeafBabe.hpp b/DataSpec/DNACommon/DeafBabe.hpp index 864619c83..2fd1cf22d 100644 --- a/DataSpec/DNACommon/DeafBabe.hpp +++ b/DataSpec/DNACommon/DeafBabe.hpp @@ -15,7 +15,7 @@ enum class BspNodeType : atUint32 }; template -void DeafBabeSendToBlender(hecl::BlenderConnection::PyOutStream& os, const DEAFBABE& db); +void DeafBabeSendToBlender(hecl::BlenderConnection::PyOutStream& os, const DEAFBABE& db, bool isDcln = false, atInt32 idx = -1); template void DeafBabeBuildFromBlender(DEAFBABE& db, const hecl::BlenderConnection::DataStream::ColMesh& colMesh); diff --git a/DataSpec/DNAMP1/CMakeLists.txt b/DataSpec/DNAMP1/CMakeLists.txt index f077d18a6..8f09c6ef0 100644 --- a/DataSpec/DNAMP1/CMakeLists.txt +++ b/DataSpec/DNAMP1/CMakeLists.txt @@ -19,6 +19,9 @@ make_dnalist(liblist DNAMP1 FRME SAVW HINT + MazeSeeds + SnowForces + DCLN Tweaks/CTweakGame Tweaks/CTweakParticle Tweaks/CTweakPlayer diff --git a/DataSpec/DNAMP1/DCLN.hpp b/DataSpec/DNAMP1/DCLN.hpp new file mode 100644 index 000000000..9a227b539 --- /dev/null +++ b/DataSpec/DNAMP1/DCLN.hpp @@ -0,0 +1,184 @@ +#ifndef __DNAMP1_DCLN_HPP__ +#define __DNAMP1_DCLN_HPP__ + +#include "../DNACommon/DeafBabe.hpp" +#include "../DNACommon/PAK.hpp" +#include "DNAMP1.hpp" +#include "DeafBabe.hpp" + +namespace DataSpec +{ +namespace DNAMP1 +{ + +struct DCLN : BigDNA +{ + DECL_DNA + Value colCount; + struct Collision : BigDNA + { + using Material = DeafBabe::Material; + using Edge = DeafBabe::Edge; + using Triangle = DeafBabe::Triangle; + + DECL_DNA + Value magic; + Value version; + Value memSize; + Value materialCount; + Vector materials; + Value vertMatsCount; + Vector vertMats; + Value edgeMatsCount; + Vector edgeMats; + Value triMatsCount; + Vector triMats; + Value edgeVertsCount; + Vector edgeVertConnections; + Value triangleEdgesCount; + Vector triangleEdgeConnections; + Value vertCount; + Vector verts; + + struct LeafData : BigDNA + { + DECL_DNA + Value edgeIndexCount; + Vector edgeIndices; + size_t getMemoryUsage() const { return (((edgeIndices.size() * 2) + 16) + 3) & ~3; } + }; + + struct Node : BigDNA + { + Delete _d; + Value xf[3]; + Value origin; + Value isLeaf; + std::unique_ptr leafData; + std::unique_ptr left; + std::unique_ptr right; + + void read(athena::io::IStreamReader & __dna_reader) + { + xf[0] = __dna_reader.readVec4fBig(); + xf[1] = __dna_reader.readVec4fBig(); + xf[2] = __dna_reader.readVec4fBig(); + origin = __dna_reader.readVec3fBig(); + isLeaf = __dna_reader.readBool(); + if (isLeaf) + { + leafData.reset(new LeafData); + leafData->read(__dna_reader); + } + else + { + left.reset(new Node); + left->read(__dna_reader); + right.reset(new Node); + right->read(__dna_reader); + } + } + + void write(athena::io::IStreamWriter & __dna_writer) const + { + __dna_writer.writeVec4fBig(xf[0]); + __dna_writer.writeVec4fBig(xf[1]); + __dna_writer.writeVec4fBig(xf[2]); + __dna_writer.writeVec3fBig(origin); + __dna_writer.writeBool(isLeaf); + if (isLeaf && leafData) + leafData->write(__dna_writer); + else if (!isLeaf && left && right) + { + left->write(__dna_writer); + right->write(__dna_writer); + } + } + + size_t binarySize(size_t __isz) const + { + __isz += 61; + if (isLeaf && leafData) + __isz = leafData->binarySize(__isz); + else if (!isLeaf && left && right) + { + __isz = left->binarySize(__isz); + __isz = right->binarySize(__isz); + } + return __isz; + } + + size_t getMemoryUsage() const + { + size_t ret = 80; + if (isLeaf) + ret += leafData->getMemoryUsage(); + else + { + ret += left->getMemoryUsage(); + ret += right->getMemoryUsage(); + } + + return (ret + 3) & ~3; + } + }; + Node root; + size_t getMemoryUsage() + { + return root.getMemoryUsage(); + } + + /* Dummy MP2 member */ + void insertNoClimb(hecl::BlenderConnection::PyOutStream&) const {} + }; + + + Vector collision; + + void sendToBlender(hecl::BlenderConnection& conn, const std::string& entryName) + { + /* Open Py Stream and read sections */ + hecl::BlenderConnection::PyOutStream os = conn.beginPythonOut(true); + os.format("import bpy\n" + "import bmesh\n" + "from mathutils import Vector\n" + "\n" + "bpy.context.scene.name = '%s'\n" + "# Clear Scene\n" + "for ob in bpy.data.objects:\n" + " if ob.type != 'CAMERA':\n" + " bpy.context.scene.objects.unlink(ob)\n" + " bpy.data.objects.remove(ob)\n", + entryName.c_str()); + + DeafBabe::BlenderInit(os); + atInt32 idx = 0; + for (const Collision& col : collision) + DeafBabeSendToBlender(os, col, true, idx++); + os.centerView(); + os.close(); + } + + static bool Extract(const SpecBase& dataSpec, + PAKEntryReadStream& rs, + const hecl::ProjectPath& outPath, + PAKRouter& pakRouter, + const PAK::Entry& entry, + bool force, + hecl::BlenderToken& btok, + std::function fileChanged) + { + DCLN dcln; + dcln.read(rs); + hecl::BlenderConnection& conn = btok.getBlenderConnection(); + if (!conn.createBlend(outPath, hecl::BlenderConnection::BlendType::Mesh)) + return false; + + dcln.sendToBlender(conn, pakRouter.getBestEntryName(entry, false)); + return conn.saveBlend(); + } +}; + +} +} + #endif // __DNAMP1_DCLN_HPP__ diff --git a/DataSpec/DNAMP1/DNAMP1.cpp b/DataSpec/DNAMP1/DNAMP1.cpp index 645d65b39..5793d616b 100644 --- a/DataSpec/DNAMP1/DNAMP1.cpp +++ b/DataSpec/DNAMP1/DNAMP1.cpp @@ -26,6 +26,7 @@ #include "FRME.hpp" #include "AGSC.hpp" #include "CSNG.hpp" +#include "DCLN.hpp" #include "../DNACommon/Tweaks/TweakWriter.hpp" #include "Tweaks/CTweakPlayerRes.hpp" @@ -42,6 +43,8 @@ #include "Tweaks/CTweakParticle.hpp" #include "Tweaks/CTweakGuiColors.hpp" #include "Tweaks/CTweakPlayerGun.hpp" +#include "MazeSeeds.hpp" +#include "SnowForces.hpp" namespace DataSpec { @@ -348,6 +351,8 @@ ResExtractor PAKBridge::LookupExtractor(const PAK& pak, const PAK::En return {FRME::Extract, {_S(".blend")}, 2}; case SBIG('CMDL'): return {CMDL::Extract, {_S(".blend")}, 1, CMDL::Name}; + case SBIG('DCLN'): + return {DCLN::Extract, {_S(".blend")}}; case SBIG('ANCS'): return {ANCS::Extract, {_S(".yaml"), _S(".blend")}, 2}; case SBIG('MLVL'): @@ -381,6 +386,7 @@ ResExtractor PAKBridge::LookupExtractor(const PAK& pak, const PAK::En case SBIG('ATBL'): return {DNAAudio::ATBL::Extract, {_S(".yaml")}}; case SBIG('CTWK'): + case SBIG('DUMB'): { bool named; std::string name = pak.bestEntryName(entry, named); @@ -414,6 +420,10 @@ ResExtractor PAKBridge::LookupExtractor(const PAK& pak, const PAK::En return {ExtractTweak, {_S(".yaml")}}; if (!name.compare("PlayerGun")) return {ExtractTweak, {_S(".yaml")}}; + if (!name.compare("DUMB_MazeSeeds")) + return {ExtractTweak, {_S(".yaml")}}; + if (!name.compare("DUMB_SnowForces")) + return {ExtractTweak, {_S(".yaml")}}; } break; } diff --git a/DataSpec/DNAMP1/MazeSeeds.hpp b/DataSpec/DNAMP1/MazeSeeds.hpp new file mode 100644 index 000000000..65eaf11ce --- /dev/null +++ b/DataSpec/DNAMP1/MazeSeeds.hpp @@ -0,0 +1,20 @@ +#ifndef __DNAMP1_MAZESEEDS_HPP__ +#define __DNAMP1_MAZESEEDS_HPP__ + +#include + +#include "DNAMP1.hpp" + +namespace DataSpec +{ +namespace DNAMP1 +{ +struct MazeSeeds : BigYAML +{ + DECL_YAML + Value seeds[300]; +}; +} +} + +#endif // __DNAMP1_MAZESEEDS_HPP__ diff --git a/DataSpec/DNAMP1/SnowForces.hpp b/DataSpec/DNAMP1/SnowForces.hpp new file mode 100644 index 000000000..7ebcb9b43 --- /dev/null +++ b/DataSpec/DNAMP1/SnowForces.hpp @@ -0,0 +1,27 @@ +#ifndef __DNAMP1_SNOWFORCES_HPP__ +#define __DNAMP1_SNOWFORCES_HPP__ + +#include + +#include "DNAMP1.hpp" + +namespace DataSpec +{ +namespace DNAMP1 +{ +struct SnowForces : BigYAML +{ + DECL_YAML + struct Force : BigYAML + { + DECL_YAML + Value gravity; + Value wind; + }; + + Value forces[256]; +}; +} +} + +#endif // __DNAMP1_SNOWFORCES_HPP__ diff --git a/DataSpec/SpecMP1.cpp b/DataSpec/SpecMP1.cpp index 333aeb103..11666e48e 100644 --- a/DataSpec/SpecMP1.cpp +++ b/DataSpec/SpecMP1.cpp @@ -40,6 +40,8 @@ #include "DNAMP1/Tweaks/CTweakParticle.hpp" #include "DNAMP1/Tweaks/CTweakGuiColors.hpp" #include "DNAMP1/Tweaks/CTweakPlayerGun.hpp" +#include "DNAMP1/MazeSeeds.hpp" +#include "DNAMP1/SnowForces.hpp" #include "hecl/ClientProcess.hpp" @@ -468,6 +470,10 @@ struct SpecMP1 : SpecBase return true; else if (!strcmp(classType, DNAMP1::EVNT::DNAType())) return true; + else if (!strcmp(classType, DNAMP1::MazeSeeds::DNAType())) + return true; + else if (!strcmp(classType, DNAMP1::SnowForces::DNAType())) + return true; else if (!strcmp(classType, "ATBL")) return true; else if (!strcmp(classType, "MP1OriginalIDs")) @@ -641,6 +647,12 @@ struct SpecMP1 : SpecBase resTag.type = SBIG('CTWK'); return true; } + else if (!strcmp(className, DataSpec::DNAMP1::MazeSeeds::DNAType()) || + !strcmp(className, DataSpec::DNAMP1::SnowForces::DNAType())) + { + resTag.type = SBIG('DUMB'); + return true; + } else if (!strcmp(className, DataSpec::DNAMP1::HINT::DNAType())) { resTag.type = SBIG('HINT'); @@ -948,6 +960,18 @@ struct SpecMP1 : SpecBase pControl.read(reader); WriteTweak(pControl, out); } + else if (!classStr.compare(DNAMP1::MazeSeeds::DNAType())) + { + DNAMP1::MazeSeeds mSeeds; + mSeeds.read(reader); + WriteTweak(mSeeds, out); + } + else if (!classStr.compare(DNAMP1::MazeSeeds::DNAType())) + { + DNAMP1::SnowForces sForces; + sForces.read(reader); + WriteTweak(sForces, out); + } else if (!classStr.compare(DNAMP1::HINT::DNAType())) { DNAMP1::HINT::Cook(in, out); diff --git a/Runtime/Collision/COBBTree.cpp b/Runtime/Collision/COBBTree.cpp index 1555bdefc..a49d88c09 100644 --- a/Runtime/Collision/COBBTree.cpp +++ b/Runtime/Collision/COBBTree.cpp @@ -142,19 +142,16 @@ size_t COBBTree::CNode::GetMemoryUsage() const { size_t ret = 0; if (x3c_isLeaf) - ret = x48_leaf->GetMemoryUsage() + 80; + ret = x48_leaf->GetMemoryUsage() + /*sizeof(CNode)*/ 80; else { if (x40_left) - ret = x40_left->GetMemoryUsage() + 80; + ret = x40_left->GetMemoryUsage() + /*sizeof(CNode)*/ 80; if (x44_right) ret += x44_right->GetMemoryUsage(); } - if (!(ret & 3)) - return ret; - - return ret + ((ret & 3) - 4); + return (ret + 3) & ~3; } COBBTree::CLeafData::CLeafData(const std::vector& surface) @@ -169,10 +166,8 @@ const std::vector& COBBTree::CLeafData::GetSurfaceVector() const size_t COBBTree::CLeafData::GetMemoryUsage() const { - size_t ret = (x0_surface.size() * 2) + 16; - if (!(ret & 3)) - return ret; - return ret + ((ret & 3) - 4); + size_t ret = (x0_surface.size() * 2) + /*sizeof(CLeafData)*/ 16; + return (ret + 3) & ~3; } COBBTree::CLeafData::CLeafData(CInputStream& in) diff --git a/Runtime/MP1/MP1.hpp b/Runtime/MP1/MP1.hpp index 5612b5507..ba076873d 100644 --- a/Runtime/MP1/MP1.hpp +++ b/Runtime/MP1/MP1.hpp @@ -36,6 +36,7 @@ #include "GuiSys/CTextExecuteBuffer.hpp" #include "DataSpec/DNAMP1/Tweaks/CTweakPlayer.hpp" #include "DataSpec/DNAMP1/Tweaks/CTweakGame.hpp" +#include "World/CScriptMazeNode.hpp" namespace urde { @@ -90,6 +91,7 @@ public: { LoadStringTable(); m_renderer.reset(AllocateRenderer(xcc_simplePool, x4_resFactory)); + CScriptMazeNode::LoadMazeSeeds(); } void ResetGameState() diff --git a/Runtime/World/CScriptMazeNode.cpp b/Runtime/World/CScriptMazeNode.cpp index f10a4fc86..f062af69f 100644 --- a/Runtime/World/CScriptMazeNode.cpp +++ b/Runtime/World/CScriptMazeNode.cpp @@ -2,10 +2,13 @@ #include "Character/CModelData.hpp" #include "GameGlobalObjects.hpp" #include "CActorParameters.hpp" +#include "TCastTo.hpp" namespace urde { +atUint32 CScriptMazeNode::sMazeSeeds[300] = {0}; + CScriptMazeNode::CScriptMazeNode(TUniqueId uid, const std::string& name, const CEntityInfo& info, const zeus::CTransform& xf, bool active, s32 w1, s32 w2, s32 w3, const zeus::CVector3f& vec1, const zeus::CVector3f& vec2, const zeus::CVector3f& vec3) @@ -21,7 +24,12 @@ CScriptMazeNode::CScriptMazeNode(TUniqueId uid, const std::string& name, const C x13c_24_ = true; } -void CScriptMazeNode::LoadSeeds() +void CScriptMazeNode::Accept(IVisitor& visitor) +{ + visitor.Visit(this); +} + +void CScriptMazeNode::LoadMazeSeeds() { const SObjectTag* tag = g_ResFactory->GetResourceIdByName("DUMB_MazeSeeds"); u32 resSize = g_ResFactory->ResourceSize(*tag); diff --git a/Runtime/World/CScriptMazeNode.hpp b/Runtime/World/CScriptMazeNode.hpp index 6feed3af6..6ff694361 100644 --- a/Runtime/World/CScriptMazeNode.hpp +++ b/Runtime/World/CScriptMazeNode.hpp @@ -5,7 +5,7 @@ namespace urde { -class CScriptMazeNode : CActor +class CScriptMazeNode : public CActor { static u32 sMazeSeeds[300]; s32 xe8_; @@ -36,7 +36,8 @@ public: CScriptMazeNode(TUniqueId, const std::string&, const CEntityInfo&, const zeus::CTransform&, bool, s32, s32, s32, const zeus::CVector3f&, const zeus::CVector3f&, const zeus::CVector3f&); - void LoadSeeds(); + void Accept(IVisitor &visitor); + static void LoadMazeSeeds(); }; } diff --git a/Runtime/World/ScriptLoader.cpp b/Runtime/World/ScriptLoader.cpp index a559f3aed..138e9c225 100644 --- a/Runtime/World/ScriptLoader.cpp +++ b/Runtime/World/ScriptLoader.cpp @@ -59,6 +59,7 @@ #include "CScriptCameraHintTrigger.hpp" #include "CScriptVisorFlare.hpp" #include "CScriptBeam.hpp" +#include "CScriptMazeNode.hpp" #include "Camera/CCinematicCamera.hpp" #include "MP1/World/CNewIntroBoss.hpp" #include "MP1/World/CBeetle.hpp" @@ -2340,7 +2341,20 @@ CEntity* ScriptLoader::LoadMetroidPrimeStage1(CStateManager& mgr, CInputStream& CEntity* ScriptLoader::LoadMazeNode(CStateManager& mgr, CInputStream& in, int propCount, const CEntityInfo& info) { - return nullptr; + if (!EnsurePropertyCount(propCount, 10, "MazeNode")) + return nullptr; + + SActorHead aHead = LoadActorHead(in, mgr); + bool active = in.readBool(); + u32 w1 = in.readUint32Big(); + u32 w2 = in.readUint32Big(); + u32 w3 = in.readUint32Big(); + zeus::CVector3f vec1 = zeus::CVector3f::ReadBig(in); + zeus::CVector3f vec2 = zeus::CVector3f::ReadBig(in); + zeus::CVector3f vec3 = zeus::CVector3f::ReadBig(in); + + return new CScriptMazeNode(mgr.AllocateUniqueId(), aHead.x0_name, info, aHead.x10_transform, active, w1, w2, w3, + vec1, vec2, vec3); } CEntity* ScriptLoader::LoadOmegaPirate(CStateManager& mgr, CInputStream& in, int propCount, const CEntityInfo& info) diff --git a/hecl b/hecl index b7e8c42c0..f2fe82d9d 160000 --- a/hecl +++ b/hecl @@ -1 +1 @@ -Subproject commit b7e8c42c02313e4a9a86aa9de072888c8ec576e7 +Subproject commit f2fe82d9dd4a0b8dbfa5ec556fddc009d68ddda9 diff --git a/nod b/nod index e494dbba9..bc38896a2 160000 --- a/nod +++ b/nod @@ -1 +1 @@ -Subproject commit e494dbba9f29634ccbd2b9af203b86d11d5466d5 +Subproject commit bc38896a2ba2b6c35a45aff3ca2acae11bc51dd2