summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorinspectredc <inspectredc@gmail.com>2024-04-25 22:52:09 +0100
committerLywx <kiritodev01@gmail.com>2024-04-25 16:25:13 -0600
commit4b72a6c401612ea0e74a4a7aaa1bc1848951b786 (patch)
tree295d4c1f1d7403bbbbd11e6dc2c64673eb55f4d0
parent32c49216fd5a1d9d5ec48fd93c177da47df3e789 (diff)
WaterDroplet Factory
-rw-r--r--src/Companion.cpp2
-rw-r--r--src/factories/ResourceType.h1
-rw-r--r--src/factories/sm64/WaterDropletFactory.cpp171
-rw-r--r--src/factories/sm64/WaterDropletFactory.h59
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)
+ };
+ }
+};
+}