diff options
| author | inspectredc <inspectredc@gmail.com> | 2024-04-25 22:52:09 +0100 |
|---|---|---|
| committer | Lywx <kiritodev01@gmail.com> | 2024-04-25 16:25:13 -0600 |
| commit | 4b72a6c401612ea0e74a4a7aaa1bc1848951b786 (patch) | |
| tree | 295d4c1f1d7403bbbbd11e6dc2c64673eb55f4d0 | |
| parent | 32c49216fd5a1d9d5ec48fd93c177da47df3e789 (diff) | |
WaterDroplet Factory
| -rw-r--r-- | src/Companion.cpp | 2 | ||||
| -rw-r--r-- | src/factories/ResourceType.h | 1 | ||||
| -rw-r--r-- | src/factories/sm64/WaterDropletFactory.cpp | 171 | ||||
| -rw-r--r-- | src/factories/sm64/WaterDropletFactory.h | 59 |
4 files changed, 233 insertions, 0 deletions
diff --git a/src/Companion.cpp b/src/Companion.cpp index aed016d..136c536 100644 --- a/src/Companion.cpp +++ b/src/Companion.cpp @@ -42,6 +42,7 @@ #include "factories/sm64/MovtexQuadFactory.h" #include "factories/sm64/PaintingMapFactory.h" #include "factories/sm64/TrajectoryFactory.h" +#include "factories/sm64/WaterDropletFactory.h" #include "factories/mk64/CourseVtx.h" #include "factories/mk64/Waypoints.h" @@ -107,6 +108,7 @@ void Companion::Init(const ExportType type) { this->RegisterFactory("SM64:MOVTEX", std::make_shared<SM64::MovtexFactory>()); this->RegisterFactory("SM64:PAINTING_MAP", std::make_shared<SM64::PaintingMapFactory>()); this->RegisterFactory("SM64:TRAJECTORY", std::make_shared<SM64::TrajectoryFactory>()); + this->RegisterFactory("SM64:WATER_DROPLET", std::make_shared<SM64::WaterDropletFactory>()); // MK64 specific this->RegisterFactory("MK64:COURSE_VTX", std::make_shared<MK64::CourseVtxFactory>()); diff --git a/src/factories/ResourceType.h b/src/factories/ResourceType.h index 716a298..de7f4f9 100644 --- a/src/factories/ResourceType.h +++ b/src/factories/ResourceType.h @@ -37,6 +37,7 @@ enum class ResourceType { MovtexQuad = 0x4D4F5651, // MOVQ PaintingData = 0x5041494E, // PAIN Trajectory = 0x5452414A, // TRAJ + WaterDroplet = 0x57545244, // WTRD // MK64 CourseVertex = 0x43565458, // CVTX diff --git a/src/factories/sm64/WaterDropletFactory.cpp b/src/factories/sm64/WaterDropletFactory.cpp new file mode 100644 index 0000000..ed34e64 --- /dev/null +++ b/src/factories/sm64/WaterDropletFactory.cpp @@ -0,0 +1,171 @@ +#include "WaterDropletFactory.h" +#include "spdlog/spdlog.h" + +#include "Companion.h" +#include "utils/Decompressor.h" +#include "utils/TorchUtils.h" +#include <regex> + +#define FORMAT_FLOAT(x) std::fixed << std::setprecision(1) << x << "f" + +ExportResult SM64::WaterDropletHeaderExporter::Export(std::ostream &write, std::shared_ptr<IParsedData> raw, std::string& entryName, YAML::Node &node, std::string* replacement) { + const auto symbol = GetSafeNode(node, "symbol", entryName); + + if(Companion::Instance->IsOTRMode()){ + write << "static const char " << symbol << "[] = \"__OTR__" << (*replacement) << "\";\n\n"; + return std::nullopt; + } + + write << "extern struct WaterDropletParams " << symbol << "[];\n"; + return std::nullopt; +} + +ExportResult SM64::WaterDropletCodeExporter::Export(std::ostream &write, std::shared_ptr<IParsedData> raw, std::string& entryName, YAML::Node &node, std::string* replacement ) { + const auto symbol = GetSafeNode(node, "symbol", entryName); + const auto offset = GetSafeNode<uint32_t>(node, "offset"); + + auto waterDropletData = std::static_pointer_cast<SM64::WaterDropletData>(raw); + + write << "struct WaterDropletParams " << symbol << " = {\n"; + + std::stringstream flagData; + auto flags = waterDropletData->flags; + bool prevFlag = false; + if (waterDropletData->flags & WATER_DROPLET_FLAG_RAND_ANGLE) { + flags -= WATER_DROPLET_FLAG_RAND_ANGLE; + flagData << "WATER_DROPLET_FLAG_RAND_ANGLE"; + prevFlag = true; + } + if (waterDropletData->flags & WATER_DROPLET_FLAG_RAND_OFFSET_XZ) { + flags -= WATER_DROPLET_FLAG_RAND_OFFSET_XZ; + if (prevFlag) { + flagData << " | "; + } + flagData << "WATER_DROPLET_FLAG_RAND_OFFSET_XZ"; + prevFlag = true; + } + if (waterDropletData->flags & WATER_DROPLET_FLAG_RAND_OFFSET_XYZ) { + flags -= WATER_DROPLET_FLAG_RAND_OFFSET_XYZ; + if (prevFlag) { + flagData << " | "; + } + flagData << "WATER_DROPLET_FLAG_RAND_OFFSET_XYZ"; + prevFlag = true; + } + if (waterDropletData->flags & WATER_DROPLET_FLAG_SET_Y_TO_WATER_LEVEL) { + flags -= WATER_DROPLET_FLAG_SET_Y_TO_WATER_LEVEL; + if (prevFlag) { + flagData << " | "; + } + flagData << "WATER_DROPLET_FLAG_SET_Y_TO_WATER_LEVEL"; + prevFlag = true; + } + if (waterDropletData->flags & WATER_DROPLET_FLAG_RAND_ANGLE_INCR_PLUS_8000) { + flags -= WATER_DROPLET_FLAG_RAND_ANGLE_INCR_PLUS_8000; + if (prevFlag) { + flagData << " | "; + } + flagData << "WATER_DROPLET_FLAG_RAND_ANGLE_INCR_PLUS_8000"; + prevFlag = true; + } + if (waterDropletData->flags & WATER_DROPLET_FLAG_RAND_ANGLE_INCR) { + flags -= WATER_DROPLET_FLAG_RAND_ANGLE_INCR; + if (prevFlag) { + flagData << " | "; + } + flagData << "WATER_DROPLET_FLAG_RAND_ANGLE_INCR"; + } + + if (flags != 0) { + throw std::runtime_error("WaterDropletCodeExporter: Invalid flags field"); + } + + std::stringstream model; + if (waterDropletData->model == MODEL_FISH) { + model << "MODEL_FISH"; + } else if (waterDropletData->model == MODEL_WHITE_PARTICLE_SMALL) { + model << "MODEL_WHITE_PARTICLE_SMALL"; + } else { + model << waterDropletData->model; + } + std::stringstream bhvSymbol; + auto dec = Companion::Instance->GetNodeByAddr(waterDropletData->behavior); + if (dec.has_value()) { + auto bhvNode = std::get<1>(dec.value()); + bhvSymbol << GetSafeNode<std::string>(bhvNode, "symbol"); + } else { + SPDLOG_WARN("Cannot find node for ptr 0x{:X}", waterDropletData->behavior); + bhvSymbol << std::hex << "0x" << waterDropletData->behavior << std::dec; + } + + write << fourSpaceTab << "/* Flags */ " << flagData.str() << ",\n"; + write << fourSpaceTab << "/* Model */ " << model.str() << ",\n"; + write << fourSpaceTab << "/* Behavior */ " << bhvSymbol.str() << ",\n"; + write << fourSpaceTab << "/* Move angle range */ " << std::hex << "0x" << waterDropletData->moveAngleRange << std::dec << ",\n"; + write << fourSpaceTab << "/* Unused (flag-specific) */ " << waterDropletData->moveRange << ",\n"; + write << fourSpaceTab << "/* Random fvel offset, scale */ " << FORMAT_FLOAT(waterDropletData->randForwardVelOffset) << ", " << FORMAT_FLOAT(waterDropletData->randForwardVelScale) << ",\n"; + write << fourSpaceTab << "/* Random yvel offset, scale */ " << FORMAT_FLOAT(waterDropletData->randYVelOffset) << ", " << FORMAT_FLOAT(waterDropletData->randYVelScale) << ",\n"; + write << fourSpaceTab << "/* Random size offset, scale */ " << FORMAT_FLOAT(waterDropletData->randSizeOffset) << ", " << FORMAT_FLOAT(waterDropletData->randSizeScale) << ",\n"; + + write << "};\n"; + + size_t size = 0; + + return offset + size; +} + +ExportResult SM64::WaterDropletBinaryExporter::Export(std::ostream &write, std::shared_ptr<IParsedData> raw, std::string& entryName, YAML::Node &node, std::string* replacement ) { + auto writer = LUS::BinaryWriter(); + auto waterDropletData = std::static_pointer_cast<SM64::WaterDropletData>(raw); + + WriteHeader(writer, LUS::ResourceType::WaterDroplet, 0); + + writer.Write(waterDropletData->flags); + writer.Write(waterDropletData->model); + auto ptr = waterDropletData->behavior; + auto dec = Companion::Instance->GetNodeByAddr(ptr); + if (dec.has_value()) { + uint64_t hash = CRC64(std::get<0>(dec.value()).c_str()); + SPDLOG_INFO("Found Behavior Script: 0x{:X} Hash: 0x{:X} Path: {}", ptr, hash, std::get<0>(dec.value())); + writer.Write(hash); + } else { + SPDLOG_WARN("Could not find Behavior Script at 0x{:X}", ptr); + } + writer.Write(waterDropletData->moveAngleRange); + writer.Write(waterDropletData->moveRange); + writer.Write(waterDropletData->randForwardVelOffset); + writer.Write(waterDropletData->randForwardVelScale); + writer.Write(waterDropletData->randYVelOffset); + writer.Write(waterDropletData->randYVelScale); + writer.Write(waterDropletData->randSizeOffset); + writer.Write(waterDropletData->randSizeScale); + + writer.Finish(write); + return std::nullopt; +} + +std::optional<std::shared_ptr<IParsedData>> SM64::WaterDropletFactory::parse(std::vector<uint8_t>& buffer, YAML::Node& node) { + auto [_, segment] = Decompressor::AutoDecode(node, buffer); + LUS::BinaryReader reader(segment.data, segment.size); + reader.SetEndianness(LUS::Endianness::Big); + + auto flags = reader.ReadInt16(); + auto model = reader.ReadInt16(); + auto behavior = reader.ReadUInt32(); + auto moveAngleRange = reader.ReadInt16(); + auto moveRange = reader.ReadInt16(); + auto randForwardVelOffset = reader.ReadFloat(); + auto randForwardVelScale = reader.ReadFloat(); + auto randYVelOffset = reader.ReadFloat(); + auto randYVelScale = reader.ReadFloat(); + auto randSizeOffset = reader.ReadFloat(); + auto randSizeScale = reader.ReadFloat(); + + // For autogen if desired + // YAML::Node bhvNode; + // bhvNode["type"] = "SM64:BEHAVIOR_SCRIPT"; + // bhvNode["offset"] = behavior; + // Companion::Instance->AddAsset(bhvNode); + + return std::make_shared<SM64::WaterDropletData>(flags, model, behavior, moveAngleRange, moveRange, randForwardVelOffset, randForwardVelScale, randYVelOffset, randYVelScale, randSizeOffset, randSizeScale); +} diff --git a/src/factories/sm64/WaterDropletFactory.h b/src/factories/sm64/WaterDropletFactory.h new file mode 100644 index 0000000..e4f4eff --- /dev/null +++ b/src/factories/sm64/WaterDropletFactory.h @@ -0,0 +1,59 @@ +#pragma once + +#include "factories/BaseFactory.h" + +#define WATER_DROPLET_FLAG_RAND_ANGLE 0x02 +#define WATER_DROPLET_FLAG_RAND_OFFSET_XZ 0x04 // Unused +#define WATER_DROPLET_FLAG_RAND_OFFSET_XYZ 0x08 // Unused +#define WATER_DROPLET_FLAG_SET_Y_TO_WATER_LEVEL 0x20 +#define WATER_DROPLET_FLAG_RAND_ANGLE_INCR_PLUS_8000 0x40 +#define WATER_DROPLET_FLAG_RAND_ANGLE_INCR 0x80 // Unused + +#define MODEL_WHITE_PARTICLE_SMALL 0xA4 +#define MODEL_FISH 0xB9 + +namespace SM64 { + +class WaterDropletData : public IParsedData { +public: + int16_t flags; + int16_t model; + uint32_t behavior; + int16_t moveAngleRange; + int16_t moveRange; + float randForwardVelOffset; + float randForwardVelScale; + float randYVelOffset; + float randYVelScale; + float randSizeOffset; + float randSizeScale; + + WaterDropletData( + int16_t flags, int16_t model, uint32_t behavior, int16_t moveAngleRange, int16_t moveRange, float randForwardVelOffset, float randForwardVelScale, float randYVelOffset, float randYVelScale, float randSizeOffset, float randSizeScale + ) : flags(flags), model(model), behavior(behavior), moveAngleRange(moveAngleRange), moveRange(moveRange), randForwardVelOffset(randForwardVelOffset), randForwardVelScale(randForwardVelScale), randYVelOffset(randYVelOffset), randYVelScale(randYVelScale), randSizeOffset(randSizeOffset), randSizeScale(randSizeScale) {} +}; + +class WaterDropletHeaderExporter : public BaseExporter { + ExportResult Export(std::ostream& write, std::shared_ptr<IParsedData> data, std::string& entryName, YAML::Node& node, std::string* replacement) override; +}; + +class WaterDropletBinaryExporter : public BaseExporter { + ExportResult Export(std::ostream& write, std::shared_ptr<IParsedData> data, std::string& entryName, YAML::Node& node, std::string* replacement) override; +}; + +class WaterDropletCodeExporter : public BaseExporter { + ExportResult Export(std::ostream& write, std::shared_ptr<IParsedData> data, std::string& entryName, YAML::Node& node, std::string* replacement) override; +}; + +class WaterDropletFactory : public BaseFactory { +public: + std::optional<std::shared_ptr<IParsedData>> parse(std::vector<uint8_t>& buffer, YAML::Node& data) override; + inline std::unordered_map<ExportType, std::shared_ptr<BaseExporter>> GetExporters() override { + return { + REGISTER(Code, WaterDropletCodeExporter) + REGISTER(Header, WaterDropletHeaderExporter) + REGISTER(Binary, WaterDropletBinaryExporter) + }; + } +}; +} |
