From db2ccd95b76031ef8842b515b805ad8232ddf1bd Mon Sep 17 00:00:00 2001 From: Pepe20129 <72659707+Pepe20129@users.noreply.github.com> Date: Mon, 15 Jan 2024 16:33:21 +0100 Subject: [PATCH] Add Collision Header XML parser (#3396) * Add Collision Header XML parser * Update CollisionHeaderFactory.cpp * Remove "Num" attributes * Fix crashes Prevent crash when the camera setting is negative Change some IntAttributes to UnsignedAttributes --- .../importer/CollisionHeaderFactory.cpp | 136 ++++++++++++++++++ .../importer/CollisionHeaderFactory.h | 3 + soh/src/code/z_camera.c | 3 +- 3 files changed, 141 insertions(+), 1 deletion(-) diff --git a/soh/soh/resource/importer/CollisionHeaderFactory.cpp b/soh/soh/resource/importer/CollisionHeaderFactory.cpp index 3707229e3..9300efdf0 100644 --- a/soh/soh/resource/importer/CollisionHeaderFactory.cpp +++ b/soh/soh/resource/importer/CollisionHeaderFactory.cpp @@ -24,6 +24,27 @@ CollisionHeaderFactory::ReadResource(std::shared_ptr initData, return resource; } +std::shared_ptr +CollisionHeaderFactory::ReadResourceXML(std::shared_ptr initData, tinyxml2::XMLElement *reader) { + auto resource = std::make_shared(initData); + std::shared_ptr factory = nullptr; + + switch (resource->GetInitData()->ResourceVersion) { + case 0: + factory = std::make_shared(); + break; + } + + if (factory == nullptr) { + SPDLOG_ERROR("Failed to load Collision Header with version {}", resource->GetInitData()->ResourceVersion); + return nullptr; + } + + factory->ParseFileXML(reader, resource); + + return resource; +} + void LUS::CollisionHeaderFactoryV0::ParseFileBinary(std::shared_ptr reader, std::shared_ptr resource) { @@ -139,4 +160,119 @@ void LUS::CollisionHeaderFactoryV0::ParseFileBinary(std::shared_ptrcollisionHeaderData.waterBoxes = collisionHeader->waterBoxes.data(); } + +void LUS::CollisionHeaderFactoryV0::ParseFileXML(tinyxml2::XMLElement* reader, std::shared_ptr resource) { + std::shared_ptr collisionHeader = std::static_pointer_cast(resource); + + collisionHeader->collisionHeaderData.minBounds.x = reader->IntAttribute("MinBoundsX"); + collisionHeader->collisionHeaderData.minBounds.y = reader->IntAttribute("MinBoundsY"); + collisionHeader->collisionHeaderData.minBounds.z = reader->IntAttribute("MinBoundsZ"); + + collisionHeader->collisionHeaderData.maxBounds.x = reader->IntAttribute("MaxBoundsX"); + collisionHeader->collisionHeaderData.maxBounds.y = reader->IntAttribute("MaxBoundsY"); + collisionHeader->collisionHeaderData.maxBounds.z = reader->IntAttribute("MaxBoundsZ"); + + Vec3s zero; + zero.x = 0; + zero.y = 0; + zero.z = 0; + collisionHeader->camPosDataZero = zero; + + auto child = reader->FirstChildElement(); + + while (child != nullptr) { + std::string childName = child->Name(); + if (childName == "Vertex") { + Vec3s vtx; + vtx.x = child->IntAttribute("X"); + vtx.y = child->IntAttribute("Y"); + vtx.z = child->IntAttribute("Z"); + collisionHeader->vertices.push_back(vtx); + } else if (childName == "Polygon") { + CollisionPoly polygon; + + polygon.type = child->UnsignedAttribute("Type"); + + polygon.flags_vIA = child->UnsignedAttribute("VertexA"); + polygon.flags_vIB = child->UnsignedAttribute("VertexB"); + polygon.vIC = child->UnsignedAttribute("VertexC"); + + polygon.normal.x = child->IntAttribute("NormalX"); + polygon.normal.y = child->IntAttribute("NormalY"); + polygon.normal.z = child->IntAttribute("NormalZ"); + + polygon.dist = child->IntAttribute("Dist"); + + collisionHeader->polygons.push_back(polygon); + } else if (childName == "PolygonType") { + SurfaceType surfaceType; + + surfaceType.data[0] = child->UnsignedAttribute("Data1"); + surfaceType.data[1] = child->UnsignedAttribute("Data2"); + + collisionHeader->surfaceTypes.push_back(surfaceType); + } else if (childName == "CameraData") { + CamData camDataEntry; + camDataEntry.cameraSType = child->UnsignedAttribute("SType"); + camDataEntry.numCameras = child->IntAttribute("NumData"); + collisionHeader->camData.push_back(camDataEntry); + + int32_t camPosDataIdx = child->IntAttribute("CameraPosDataSeg"); + collisionHeader->camPosDataIndices.push_back(camPosDataIdx); + } else if (childName == "CameraPositionData") { + //each camera position data is made up of 3 Vec3s + Vec3s pos; + pos.x = child->IntAttribute("PosX"); + pos.y = child->IntAttribute("PosY"); + pos.z = child->IntAttribute("PosZ"); + collisionHeader->camPosData.push_back(pos); + Vec3s rot; + rot.x = child->IntAttribute("RotX"); + rot.y = child->IntAttribute("RotY"); + rot.z = child->IntAttribute("RotZ"); + collisionHeader->camPosData.push_back(rot); + Vec3s other; + other.x = child->IntAttribute("FOV"); + other.y = child->IntAttribute("JfifID"); + other.z = child->IntAttribute("Unknown"); + collisionHeader->camPosData.push_back(other); + } else if (childName == "WaterBox") { + WaterBox waterBox; + waterBox.xMin = child->IntAttribute("XMin"); + waterBox.ySurface = child->IntAttribute("Ysurface"); + waterBox.zMin = child->IntAttribute("ZMin"); + waterBox.xLength = child->IntAttribute("XLength"); + waterBox.zLength = child->IntAttribute("ZLength"); + waterBox.properties = child->IntAttribute("Properties"); + + collisionHeader->waterBoxes.push_back(waterBox); + } + + child = child->NextSiblingElement(); + } + + for (size_t i = 0; i < collisionHeader->camData.size(); i++) { + int32_t idx = collisionHeader->camPosDataIndices[i]; + + if (collisionHeader->camPosData.size() > 0) { + collisionHeader->camData[i].camPosData = &collisionHeader->camPosData[idx]; + } else { + collisionHeader->camData[i].camPosData = &collisionHeader->camPosDataZero; + } + } + + collisionHeader->collisionHeaderData.numVertices = collisionHeader->vertices.size(); + collisionHeader->collisionHeaderData.numPolygons = collisionHeader->polygons.size(); + collisionHeader->surfaceTypesCount = collisionHeader->surfaceTypes.size(); + collisionHeader->camDataCount = collisionHeader->camData.size(); + collisionHeader->camPosCount = collisionHeader->camPosData.size(); + collisionHeader->collisionHeaderData.numWaterBoxes = collisionHeader->waterBoxes.size(); + + collisionHeader->collisionHeaderData.vtxList = collisionHeader->vertices.data(); + collisionHeader->collisionHeaderData.polyList = collisionHeader->polygons.data(); + collisionHeader->collisionHeaderData.surfaceTypeList = collisionHeader->surfaceTypes.data(); + collisionHeader->collisionHeaderData.cameraDataList = collisionHeader->camData.data(); + collisionHeader->collisionHeaderData.cameraDataListLen = collisionHeader->camDataCount; + collisionHeader->collisionHeaderData.waterBoxes = collisionHeader->waterBoxes.data(); } +} \ No newline at end of file diff --git a/soh/soh/resource/importer/CollisionHeaderFactory.h b/soh/soh/resource/importer/CollisionHeaderFactory.h index 09d6ba4c5..e0276b38f 100644 --- a/soh/soh/resource/importer/CollisionHeaderFactory.h +++ b/soh/soh/resource/importer/CollisionHeaderFactory.h @@ -8,10 +8,13 @@ class CollisionHeaderFactory : public ResourceFactory { public: std::shared_ptr ReadResource(std::shared_ptr initData, std::shared_ptr reader) override; + std::shared_ptr + ReadResourceXML(std::shared_ptr initData, tinyxml2::XMLElement *reader) override; }; class CollisionHeaderFactoryV0 : public ResourceVersionFactory { public: void ParseFileBinary(std::shared_ptr reader, std::shared_ptr resource) override; + void ParseFileXML(tinyxml2::XMLElement* reader, std::shared_ptr resource) override; }; }; // namespace LUS diff --git a/soh/src/code/z_camera.c b/soh/src/code/z_camera.c index ed8b9c8f4..2b5281037 100644 --- a/soh/src/code/z_camera.c +++ b/soh/src/code/z_camera.c @@ -7933,7 +7933,8 @@ s16 Camera_ChangeSettingFlags(Camera* camera, s16 setting, s16 flags) { return -5; } - if (setting == CAM_SET_NONE || setting >= CAM_SET_MAX) { + //modified from "==" to "<=" to not crash when "setting" is a negative value + if (setting <= CAM_SET_NONE || setting >= CAM_SET_MAX) { osSyncPrintf(VT_COL(RED, WHITE) "camera: error: illegal camera set (%d) !!!!\n" VT_RST, setting); return -99; }