diff options
| author | inspectredc <inspectredc@gmail.com> | 2024-04-25 17:32:49 +0100 |
|---|---|---|
| committer | Lywx <kiritodev01@gmail.com> | 2024-04-25 10:41:49 -0600 |
| commit | ceca1c3e45995a0b43fac2a292634ec6063d7b83 (patch) | |
| tree | 5f98d62e52a920292adcf909a7785008cc4cea47 /src | |
| parent | e8d296c3e197d4f3280ccec515513c5a373ee9fb (diff) | |
Behavior Script Factory
Diffstat (limited to 'src')
| -rw-r--r-- | src/Companion.cpp | 2 | ||||
| -rw-r--r-- | src/factories/ResourceType.h | 23 | ||||
| -rw-r--r-- | src/factories/sm64/BehaviorScriptFactory.cpp | 489 | ||||
| -rw-r--r-- | src/factories/sm64/BehaviorScriptFactory.h | 51 | ||||
| -rw-r--r-- | src/factories/sm64/behavior/BehaviorCommand.h | 261 |
5 files changed, 815 insertions, 11 deletions
diff --git a/src/Companion.cpp b/src/Companion.cpp index bc218b5..9d8f3b1 100644 --- a/src/Companion.cpp +++ b/src/Companion.cpp @@ -30,6 +30,7 @@ #include "factories/AssetArrayFactory.h" #include "factories/sm64/AnimationFactory.h" +#include "factories/sm64/BehaviorScriptFactory.h" #include "factories/sm64/CollisionFactory.h" #include "factories/sm64/DialogFactory.h" #include "factories/sm64/DictionaryFactory.h" @@ -97,6 +98,7 @@ void Companion::Init(const ExportType type) { this->RegisterFactory("SM64:TEXT", std::make_shared<SM64::TextFactory>()); this->RegisterFactory("SM64:DICTIONARY", std::make_shared<SM64::DictionaryFactory>()); this->RegisterFactory("SM64:ANIM", std::make_shared<SM64::AnimationFactory>()); + this->RegisterFactory("SM64:BEHAVIOR_SCRIPT", std::make_shared<SM64::TrajectoryFactory>()); this->RegisterFactory("SM64:COLLISION", std::make_shared<SM64::CollisionFactory>()); this->RegisterFactory("SM64:GEO_LAYOUT", std::make_shared<SM64::GeoLayoutFactory>()); this->RegisterFactory("SM64:LEVEL_SCRIPT", std::make_shared<SM64::LevelScriptFactory>()); diff --git a/src/factories/ResourceType.h b/src/factories/ResourceType.h index 98c8cf5..6ba4b1d 100644 --- a/src/factories/ResourceType.h +++ b/src/factories/ResourceType.h @@ -25,17 +25,18 @@ enum class ResourceType { AssetArray = 0x41415252, // AARR // SM64 - Anim = 0x414E494D, // ANIM - SDialog = 0x53444C47, // SDLG - Dictionary = 0x44494354, // DICT - GeoLayout = 0x47454F20, // GEO - Collision = 0x434F4C20, // COL - LevelScript = 0x4C564C53, // LVLS - MacroObject = 0x4D41434F, // MACO - Movtex = 0x4D4F5654, // MOVT - MovtexQuad = 0x4D4F5651, // MOVQ - PaintingData = 0x5041494E, // PAIN - Trajectory = 0x5452414A, // TRAJ + Anim = 0x414E494D, // ANIM + BehaviorScript = 0x42485653, // BHVS + SDialog = 0x53444C47, // SDLG + Dictionary = 0x44494354, // DICT + GeoLayout = 0x47454F20, // GEO + Collision = 0x434F4C20, // COL + LevelScript = 0x4C564C53, // LVLS + MacroObject = 0x4D41434F, // MACO + Movtex = 0x4D4F5654, // MOVT + MovtexQuad = 0x4D4F5651, // MOVQ + PaintingData = 0x5041494E, // PAIN + Trajectory = 0x5452414A, // TRAJ // MK64 CourseVertex = 0x43565458, // CVTX diff --git a/src/factories/sm64/BehaviorScriptFactory.cpp b/src/factories/sm64/BehaviorScriptFactory.cpp new file mode 100644 index 0000000..6cbcd3e --- /dev/null +++ b/src/factories/sm64/BehaviorScriptFactory.cpp @@ -0,0 +1,489 @@ +#include "BehaviorScriptFactory.h" +#include "spdlog/spdlog.h" + +#include "Companion.h" +#include "utils/Decompressor.h" +#include "utils/TorchUtils.h" +#include <regex> + +ExportResult SM64::BehaviorScriptHeaderExporter::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 BehaviorScript " << symbol << "[];\n"; + return std::nullopt; +} + +ExportResult SM64::BehaviorScriptCodeExporter::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"); + const auto commands = std::static_pointer_cast<BehaviorScriptData>(raw)->mCommands; + uint32_t indentCount = 1; + + write << "static const BehaviorScript " << symbol << "[] = {\n"; + + for(auto& [opcode, arguments] : commands) { + bool commaFlag = false; + + for (uint32_t i = 0; i < indentCount; ++i) { + write << fourSpaceTab; + } + + if (opcode == BehaviorOpcode::BEGIN_LOOP || opcode == BehaviorOpcode::BEGIN_REPEAT) { + ++indentCount; + } else if (opcode == BehaviorOpcode::END_LOOP || opcode == BehaviorOpcode::END_REPEAT || opcode == BehaviorOpcode::END_REPEAT_CONTINUE) { + --indentCount; + } + + write << opcode << "("; + for(auto& args : arguments) { + if (commaFlag) { + write << ", "; + } else { + commaFlag = true; + } + + switch(static_cast<BehaviorArgumentType>(args.index())) { + case BehaviorArgumentType::U8: { + write << std::hex << "0x" << static_cast<uint32_t>(std::get<uint8_t>(args)); + break; + } + case BehaviorArgumentType::S8: { + write << std::hex << "0x" << static_cast<uint32_t>(std::get<int8_t>(args)); + break; + } + case BehaviorArgumentType::U16: { + write << std::hex << "0x" << std::get<uint16_t>(args); + break; + } + case BehaviorArgumentType::S16: { + write << std::dec << std::get<int16_t>(args); + break; + } + case BehaviorArgumentType::U32: { + write << std::hex << "0x" << std::get<uint32_t>(args); + break; + } + case BehaviorArgumentType::S32: { + write << std::dec << std::get<int32_t>(args); + break; + } + case BehaviorArgumentType::F32: { + write << std::dec << std::get<float>(args); + break; + } + case BehaviorArgumentType::PTR: { + auto ptr = std::get<uint64_t>(args); + auto dec = Companion::Instance->GetNodeByAddr(ptr); + std::string symbol = "NULL"; + + if (ptr == 0) { + write << symbol; + } else if (dec.has_value()) { + auto node = std::get<1>(dec.value()); + symbol = GetSafeNode<std::string>(node, "symbol"); + write << symbol; + } else { + SPDLOG_WARN("Cannot find node for ptr 0x{:X}", ptr); + write << std::hex << "0x" << ptr; + } + break; + } + default: { + throw std::runtime_error("Unknown Behavior Argument Type"); + } + } + } + write << "),\n"; + } + + write << "\n};\n"; + + size_t size = 0; + + return offset + size; +} + +ExportResult SM64::BehaviorScriptBinaryExporter::Export(std::ostream &write, std::shared_ptr<IParsedData> raw, std::string& entryName, YAML::Node &node, std::string* replacement ) { + auto writer = LUS::BinaryWriter(); + const auto commands = std::static_pointer_cast<BehaviorScriptData>(raw)->mCommands; + + WriteHeader(writer, LUS::ResourceType::BehaviorScript, 0); + + writer.Write((uint32_t)commands.size()); + + for(auto& [opcode, arguments] : commands) { + writer.Write(static_cast<uint8_t>(opcode)); + + for(auto& args : arguments) { + switch(static_cast<BehaviorArgumentType>(args.index())) { + case BehaviorArgumentType::U8: { + writer.Write(std::get<uint8_t>(args)); + break; + } + case BehaviorArgumentType::S8: { + writer.Write(std::get<int8_t>(args)); + break; + } + case BehaviorArgumentType::U16: { + writer.Write(std::get<uint16_t>(args)); + break; + } + case BehaviorArgumentType::S16: { + writer.Write(std::get<int16_t>(args)); + break; + } + case BehaviorArgumentType::U32: { + writer.Write(std::get<uint32_t>(args)); + break; + } + case BehaviorArgumentType::S32: { + writer.Write(std::get<int32_t>(args)); + break; + } + case BehaviorArgumentType::F32: { + writer.Write(std::get<float>(args)); + break; + } + case BehaviorArgumentType::PTR: { + auto ptr = static_cast<uint32_t>(std::get<uint64_t>(args)); + auto dec = Companion::Instance->GetNodeByAddr(ptr); + if (ptr == 0) { + writer.Write(ptr); + } else if (dec.has_value()) { + uint64_t hash = CRC64(std::get<0>(dec.value()).c_str()); + SPDLOG_INFO("Found Asset: 0x{:X} Hash: 0x{:X} Path: {}", ptr, hash, std::get<0>(dec.value())); + writer.Write(hash); + } else { + SPDLOG_WARN("Could not find Asset at 0x{:X}", ptr); + } + break; + } + default: { + throw std::runtime_error("Unknown Behavior Argument Type"); + } + } + } + } + + writer.Finish(write); + return std::nullopt; +} + +std::optional<std::shared_ptr<IParsedData>> SM64::BehaviorScriptFactory::parse(std::vector<uint8_t>& buffer, YAML::Node& node) { + auto [_, segment] = Decompressor::AutoDecode(node, buffer); + auto cmd = segment.data; + bool processing = true; + std::vector<BehaviorCommand> commands; + + while(processing) { + auto opcode = static_cast<BehaviorOpcode>(cmd[0x00]); + + SPDLOG_INFO("Processing Command {}", opcode); + + std::vector<BehaviorArgument> arguments; + + switch (opcode) { + case BehaviorOpcode::BEGIN: { + auto objList = cur_behavior_cmd_u8(0x01); + arguments.emplace_back(objList); + cmd += 0x4 << CMD_SIZE_SHIFT; + break; + } + case BehaviorOpcode::DELAY: { + auto num = cur_behavior_cmd_u8(0x01); + arguments.emplace_back(num); + cmd += 0x4 << CMD_SIZE_SHIFT; + break; + } + case BehaviorOpcode::CALL: { + uint64_t addr = cur_behavior_cmd_u32(0x04); + arguments.emplace_back(addr); + cmd += 0x8 << CMD_SIZE_SHIFT; + break; + } + case BehaviorOpcode::RETURN: { + processing = false; + cmd += 0x4 << CMD_SIZE_SHIFT; + break; + } + case BehaviorOpcode::GOTO: { + uint64_t addr = cur_behavior_cmd_u32(0x04); + arguments.emplace_back(addr); + cmd += 0x8 << CMD_SIZE_SHIFT; + break; + } + case BehaviorOpcode::BEGIN_REPEAT: { + auto count = cur_behavior_cmd_s16(0x02); + arguments.emplace_back(count); + cmd += 0x4 << CMD_SIZE_SHIFT; + break; + } + case BehaviorOpcode::END_REPEAT: + case BehaviorOpcode::END_REPEAT_CONTINUE: + case BehaviorOpcode::BEGIN_LOOP: { + cmd += 0x4 << CMD_SIZE_SHIFT; + break; + } + case BehaviorOpcode::END_LOOP: + case BehaviorOpcode::BREAK: + case BehaviorOpcode::BREAK_UNUSED: { + processing = false; + cmd += 0x4 << CMD_SIZE_SHIFT; + break; + } + case BehaviorOpcode::CALL_NATIVE: { + auto func = cur_behavior_cmd_u32(0x04); + arguments.emplace_back(func); + cmd += 0x8 << CMD_SIZE_SHIFT; + break; + } + case BehaviorOpcode::ADD_FLOAT: + case BehaviorOpcode::SET_FLOAT: + case BehaviorOpcode::ADD_INT: + case BehaviorOpcode::SET_INT: + case BehaviorOpcode::OR_INT: + case BehaviorOpcode::BIT_CLEAR: { + auto field = cur_behavior_cmd_u8(0x01); + auto value = cur_behavior_cmd_s16(0x02); + arguments.emplace_back(field); + arguments.emplace_back(value); + cmd += 0x4 << CMD_SIZE_SHIFT; + break; + } + case BehaviorOpcode::SET_INT_RAND_RSHIFT: + case BehaviorOpcode::SET_RANDOM_FLOAT: + case BehaviorOpcode::SET_RANDOM_INT: + case BehaviorOpcode::ADD_RANDOM_FLOAT: + case BehaviorOpcode::ADD_INT_RAND_RSHIFT: { + auto field = cur_behavior_cmd_u8(0x01); + auto min = cur_behavior_cmd_s16(0x02); + auto rangeRShift = cur_behavior_cmd_s16(0x04); + arguments.emplace_back(field); + arguments.emplace_back(min); + arguments.emplace_back(rangeRShift); + cmd += 0x8 << CMD_SIZE_SHIFT; + break; + } + case BehaviorOpcode::CMD_NOP_1: + case BehaviorOpcode::CMD_NOP_2: + case BehaviorOpcode::CMD_NOP_3: { + auto field = cur_behavior_cmd_u8(0x01); + arguments.emplace_back(field); + cmd += 0x4 << CMD_SIZE_SHIFT; + break; + } + case BehaviorOpcode::SET_MODEL: { + auto model = cur_behavior_cmd_s16(0x02); + arguments.emplace_back(model); + cmd += 0x4 << CMD_SIZE_SHIFT; + break; + } + case BehaviorOpcode::SPAWN_CHILD: { + auto modelId = cur_behavior_cmd_s32(0x04); + uint64_t behavior = cur_behavior_cmd_u32(0x08); + arguments.emplace_back(modelId); + arguments.emplace_back(behavior); + cmd += 0xC << CMD_SIZE_SHIFT; + break; + } + case BehaviorOpcode::DEACTIVATE: { + processing = false; + cmd += 0x4 << CMD_SIZE_SHIFT; + break; + } + case BehaviorOpcode::DROP_TO_FLOOR: { + cmd += 0x4 << CMD_SIZE_SHIFT; + break; + } + case BehaviorOpcode::SUM_FLOAT: + case BehaviorOpcode::SUM_INT: { + auto fieldDst = cur_behavior_cmd_u8(0x01); + auto fieldSrc1 = cur_behavior_cmd_u8(0x02); + auto fieldSrc2 = cur_behavior_cmd_u8(0x03); + arguments.emplace_back(fieldDst); + arguments.emplace_back(fieldSrc1); + arguments.emplace_back(fieldSrc2); + cmd += 0x4 << CMD_SIZE_SHIFT; + break; + } + case BehaviorOpcode::BILLBOARD: + case BehaviorOpcode::HIDE: { + cmd += 0x4 << CMD_SIZE_SHIFT; + break; + } + case BehaviorOpcode::SET_HITBOX: { + auto radius = cur_behavior_cmd_s16(0x04); + auto height = cur_behavior_cmd_s16(0x06); + arguments.emplace_back(radius); + arguments.emplace_back(height); + cmd += 0x8 << CMD_SIZE_SHIFT; + break; + } + case BehaviorOpcode::CMD_NOP_4: { + auto field = cur_behavior_cmd_u8(0x01); + auto value = cur_behavior_cmd_s16(0x02); + arguments.emplace_back(field); + arguments.emplace_back(value); + cmd += 0x4 << CMD_SIZE_SHIFT; + break; + } + case BehaviorOpcode::DELAY_VAR: { + auto field = cur_behavior_cmd_u8(0x01); + arguments.emplace_back(field); + cmd += 0x4 << CMD_SIZE_SHIFT; + break; + } + case BehaviorOpcode::BEGIN_REPEAT_UNUSED: { + auto count = cur_behavior_cmd_u8(0x01); + arguments.emplace_back(count); + cmd += 0x4 << CMD_SIZE_SHIFT; + break; + } + case BehaviorOpcode::LOAD_ANIMATIONS: { + auto field = cur_behavior_cmd_u8(0x01); + uint64_t anims = cur_behavior_cmd_u32(0x04); + arguments.emplace_back(field); + arguments.emplace_back(anims); + cmd += 0x8 << CMD_SIZE_SHIFT; + break; + } + case BehaviorOpcode::ANIMATE: { + auto animIndex = cur_behavior_cmd_u8(0x01); + arguments.emplace_back(animIndex); + cmd += 0x4 << CMD_SIZE_SHIFT; + break; + } + case BehaviorOpcode::SPAWN_CHILD_WITH_PARAM: { + auto bhvParam = cur_behavior_cmd_u8(0x01); + auto modelId = cur_behavior_cmd_s32(0x04); + uint64_t behavior = cur_behavior_cmd_u32(0x08); + arguments.emplace_back(bhvParam); + arguments.emplace_back(modelId); + arguments.emplace_back(behavior); + cmd += 0xC << CMD_SIZE_SHIFT; + break; + } + case BehaviorOpcode::LOAD_COLLISION_DATA: { + uint64_t collisionData = cur_behavior_cmd_u32(0x04); + arguments.emplace_back(collisionData); + cmd += 0x8 << CMD_SIZE_SHIFT; + break; + } + case BehaviorOpcode::SET_HITBOX_WITH_OFFSET: { + auto radius = cur_behavior_cmd_s16(0x04); + auto height = cur_behavior_cmd_s16(0x06); + auto downOffset = cur_behavior_cmd_s16(0x08); + arguments.emplace_back(radius); + arguments.emplace_back(height); + arguments.emplace_back(downOffset); + cmd += 0xC << CMD_SIZE_SHIFT; + break; + } + case BehaviorOpcode::SPAWN_OBJ: { + auto modelId = cur_behavior_cmd_s32(0x04); + uint64_t behavior = cur_behavior_cmd_u32(0x08); + arguments.emplace_back(modelId); + arguments.emplace_back(behavior); + cmd += 0xC << CMD_SIZE_SHIFT; + break; + } + case BehaviorOpcode::SET_HOME: { + cmd += 0x4 << CMD_SIZE_SHIFT; + break; + } + case BehaviorOpcode::SET_HURTBOX: { + auto radius = cur_behavior_cmd_s16(0x04); + auto height = cur_behavior_cmd_s16(0x06); + arguments.emplace_back(radius); + arguments.emplace_back(height); + cmd += 0x8 << CMD_SIZE_SHIFT; + break; + } + case BehaviorOpcode::SET_INTERACT_TYPE: { + auto type = cur_behavior_cmd_s32(0x04); + arguments.emplace_back(type); + cmd += 0x8 << CMD_SIZE_SHIFT; + break; + } + case BehaviorOpcode::SET_OBJ_PHYSICS: { + auto wallHitboxRadius = cur_behavior_cmd_s16(0x04); + auto gravity = cur_behavior_cmd_s16(0x06); + auto bounciness = cur_behavior_cmd_s16(0x08); + auto dragStrength = cur_behavior_cmd_s16(0x0A); + auto friction = cur_behavior_cmd_s16(0x0C); + auto buoyancy = cur_behavior_cmd_s16(0x0E); + auto unused1 = cur_behavior_cmd_s16(0x10); + auto unused2 = cur_behavior_cmd_s16(0x12); + arguments.emplace_back(wallHitboxRadius); + arguments.emplace_back(gravity); + arguments.emplace_back(bounciness); + arguments.emplace_back(dragStrength); + arguments.emplace_back(friction); + arguments.emplace_back(buoyancy); + arguments.emplace_back(unused1); + arguments.emplace_back(unused2); + cmd += 0x14 << CMD_SIZE_SHIFT; + break; + } + case BehaviorOpcode::SET_INTERACT_SUBTYPE: { + auto subType = cur_behavior_cmd_s32(0x04); + arguments.emplace_back(subType); + cmd += 0x8 << CMD_SIZE_SHIFT; + break; + } + case BehaviorOpcode::SCALE: { + auto unusedField = cur_behavior_cmd_u8(0x01); + auto percent = cur_behavior_cmd_s16(0x02); + arguments.emplace_back(unusedField); + arguments.emplace_back(percent); + cmd += 0x4 << CMD_SIZE_SHIFT; + break; + } + case BehaviorOpcode::PARENT_BIT_CLEAR: { + auto field = cur_behavior_cmd_u8(0x01); + auto flags = cur_behavior_cmd_s32(0x04); + arguments.emplace_back(field); + arguments.emplace_back(flags); + cmd += 0x8 << CMD_SIZE_SHIFT; + break; + } + case BehaviorOpcode::ANIMATE_TEXTURE: { + auto field = cur_behavior_cmd_u8(0x01); + auto rate = cur_behavior_cmd_s16(0x02); + arguments.emplace_back(field); + arguments.emplace_back(rate); + cmd += 0x4 << CMD_SIZE_SHIFT; + break; + } + case BehaviorOpcode::DISABLE_RENDERING: { + cmd += 0x4 << CMD_SIZE_SHIFT; + break; + } + case BehaviorOpcode::SET_INT_UNUSED: { + auto field = cur_behavior_cmd_u8(0x01); + auto value = cur_behavior_cmd_s16(0x06); + arguments.emplace_back(field); + arguments.emplace_back(value); + cmd += 0x8 << CMD_SIZE_SHIFT; + break; + } + case BehaviorOpcode::SPAWN_WATER_DROPLET: { + uint64_t dropletParams = cur_behavior_cmd_s32(0x04); + arguments.emplace_back(dropletParams); + cmd += 0x8 << CMD_SIZE_SHIFT; + break; + } + default: + throw std::runtime_error("Unknown Behavior Opcode"); + } + + commands.emplace_back(opcode, arguments); + } + + return std::make_shared<SM64::BehaviorScriptData>(commands); +} diff --git a/src/factories/sm64/BehaviorScriptFactory.h b/src/factories/sm64/BehaviorScriptFactory.h new file mode 100644 index 0000000..d1c451a --- /dev/null +++ b/src/factories/sm64/BehaviorScriptFactory.h @@ -0,0 +1,51 @@ +#pragma once + +#include "factories/BaseFactory.h" +#include "behavior/BehaviorCommand.h" + +typedef std::variant<uint8_t, int8_t, uint16_t, int16_t, uint32_t, int32_t, float, uint64_t> BehaviorArgument; + +enum class BehaviorArgumentType { + U8, S8, U16, S16, U32, S32, F32, PTR +}; + +namespace SM64 { + +struct BehaviorCommand { + BehaviorOpcode opcode; + std::vector<BehaviorArgument> arguments; + + BehaviorCommand(BehaviorOpcode opcode, std::vector<BehaviorArgument> arguments) : opcode(opcode), arguments(arguments) {} +}; + +class BehaviorScriptData : public IParsedData { +public: + std::vector<BehaviorCommand> mCommands; + + BehaviorScriptData(std::vector<BehaviorCommand> commands) : mCommands(std::move(commands)) {} +}; + +class BehaviorScriptHeaderExporter : public BaseExporter { + ExportResult Export(std::ostream& write, std::shared_ptr<IParsedData> data, std::string& entryName, YAML::Node& node, std::string* replacement) override; +}; + +class BehaviorScriptBinaryExporter : public BaseExporter { + ExportResult Export(std::ostream& write, std::shared_ptr<IParsedData> data, std::string& entryName, YAML::Node& node, std::string* replacement) override; +}; + +class BehaviorScriptCodeExporter : public BaseExporter { + ExportResult Export(std::ostream& write, std::shared_ptr<IParsedData> data, std::string& entryName, YAML::Node& node, std::string* replacement) override; +}; + +class BehaviorScriptFactory : 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, BehaviorScriptCodeExporter) + REGISTER(Header, BehaviorScriptHeaderExporter) + REGISTER(Binary, BehaviorScriptBinaryExporter) + }; + } +}; +} diff --git a/src/factories/sm64/behavior/BehaviorCommand.h b/src/factories/sm64/behavior/BehaviorCommand.h new file mode 100644 index 0000000..6effad3 --- /dev/null +++ b/src/factories/sm64/behavior/BehaviorCommand.h @@ -0,0 +1,261 @@ +#pragma once + +#include "endianness.h" +#include "n64/CommandMacros.h" +#include <string> +#include <spdlog/spdlog.h> +#include <spdlog/fmt/ostr.h> +#include <binarytools/BinaryWriter.h> +#include <types/Vec3D.h> + +enum class BehaviorOpcode { + BEGIN, + DELAY, + CALL, + RETURN, + GOTO, + BEGIN_REPEAT, + END_REPEAT, + END_REPEAT_CONTINUE, + BEGIN_LOOP, + END_LOOP, + BREAK, + BREAK_UNUSED, + CALL_NATIVE, + ADD_FLOAT, + SET_FLOAT, + ADD_INT, + SET_INT, + OR_INT, + BIT_CLEAR, + SET_INT_RAND_RSHIFT, + SET_RANDOM_FLOAT, + SET_RANDOM_INT, + ADD_RANDOM_FLOAT, + ADD_INT_RAND_RSHIFT, + CMD_NOP_1, + CMD_NOP_2, + CMD_NOP_3, + SET_MODEL, + SPAWN_CHILD, + DEACTIVATE, + DROP_TO_FLOOR, + SUM_FLOAT, + SUM_INT, + BILLBOARD, + HIDE, + SET_HITBOX, + CMD_NOP_4, + DELAY_VAR, + BEGIN_REPEAT_UNUSED, + LOAD_ANIMATIONS, + ANIMATE, + SPAWN_CHILD_WITH_PARAM, + LOAD_COLLISION_DATA, + SET_HITBOX_WITH_OFFSET, + SPAWN_OBJ, + SET_HOME, + SET_HURTBOX, + SET_INTERACT_TYPE, + SET_OBJ_PHYSICS, + SET_INTERACT_SUBTYPE, + SCALE, + PARENT_BIT_CLEAR, + ANIMATE_TEXTURE, + DISABLE_RENDERING, + SET_INT_UNUSED, + SPAWN_WATER_DROPLET, +}; + +inline std::ostream& operator<<(std::ostream& out, const BehaviorOpcode& opcode) { + std::string output; + switch (opcode) { + case BehaviorOpcode::BEGIN: + output = "BEGIN"; + break; + case BehaviorOpcode::DELAY: + output = "DELAY"; + break; + case BehaviorOpcode::CALL: + output = "CALL"; + break; + case BehaviorOpcode::RETURN: + output = "RETURN"; + break; + case BehaviorOpcode::GOTO: + output = "GOTO"; + break; + case BehaviorOpcode::BEGIN_REPEAT: + output = "BEGIN_REPEAT"; + break; + case BehaviorOpcode::END_REPEAT: + output = "END_REPEAT"; + break; + case BehaviorOpcode::END_REPEAT_CONTINUE: + output = "END_REPEAT_CONTINUE"; + break; + case BehaviorOpcode::BEGIN_LOOP: + output = "BEGIN_LOOP"; + break; + case BehaviorOpcode::END_LOOP: + output = "END_LOOP"; + break; + case BehaviorOpcode::BREAK: + output = "BREAK"; + break; + case BehaviorOpcode::BREAK_UNUSED: + output = "BREAK_UNUSED"; + break; + case BehaviorOpcode::CALL_NATIVE: + output = "CALL_NATIVE"; + break; + case BehaviorOpcode::ADD_FLOAT: + output = "ADD_FLOAT"; + break; + case BehaviorOpcode::SET_FLOAT: + output = "SET_FLOAT"; + break; + case BehaviorOpcode::ADD_INT: + output = "ADD_INT"; + break; + case BehaviorOpcode::SET_INT: + output = "SET_INT"; + break; + case BehaviorOpcode::OR_INT: + output = "OR_INT"; + break; + case BehaviorOpcode::BIT_CLEAR: + output = "BIT_CLEAR"; + break; + case BehaviorOpcode::SET_INT_RAND_RSHIFT: + output = "SET_INT_RAND_RSHIFT"; + break; + case BehaviorOpcode::SET_RANDOM_FLOAT: + output = "SET_RANDOM_FLOAT"; + break; + case BehaviorOpcode::SET_RANDOM_INT: + output = "SET_RANDOM_INT"; + break; + case BehaviorOpcode::ADD_RANDOM_FLOAT: + output = "ADD_RANDOM_FLOAT"; + break; + case BehaviorOpcode::ADD_INT_RAND_RSHIFT: + output = "ADD_INT_RAND_RSHIFT"; + break; + case BehaviorOpcode::CMD_NOP_1: + output = "CMD_NOP_1"; + break; + case BehaviorOpcode::CMD_NOP_2: + output = "CMD_NOP_2"; + break; + case BehaviorOpcode::CMD_NOP_3: + output = "CMD_NOP_3"; + break; + case BehaviorOpcode::SET_MODEL: + output = "SET_MODEL"; + break; + case BehaviorOpcode::SPAWN_CHILD: + output = "SPAWN_CHILD"; + break; + case BehaviorOpcode::DEACTIVATE: + output = "DEACTIVATE"; + break; + case BehaviorOpcode::DROP_TO_FLOOR: + output = "DROP_TO_FLOOR"; + break; + case BehaviorOpcode::SUM_FLOAT: + output = "SUM_FLOAT"; + break; + case BehaviorOpcode::SUM_INT: + output = "SUM_INT"; + break; + case BehaviorOpcode::BILLBOARD: + output = "BILLBOARD"; + break; + case BehaviorOpcode::HIDE: + output = "HIDE"; + break; + case BehaviorOpcode::SET_HITBOX: + output = "SET_HITBOX"; + break; + case BehaviorOpcode::CMD_NOP_4: + output = "CMD_NOP_4"; + break; + case BehaviorOpcode::DELAY_VAR: + output = "DELAY_VAR"; + break; + case BehaviorOpcode::BEGIN_REPEAT_UNUSED: + output = "BEGIN_REPEAT_UNUSED"; + break; + case BehaviorOpcode::LOAD_ANIMATIONS: + output = "LOAD_ANIMATIONS"; + break; + case BehaviorOpcode::ANIMATE: + output = "ANIMATE"; + break; + case BehaviorOpcode::SPAWN_CHILD_WITH_PARAM: + output = "SPAWN_CHILD_WITH_PARAM"; + break; + case BehaviorOpcode::LOAD_COLLISION_DATA: + output = "LOAD_COLLISION_DATA"; + break; + case BehaviorOpcode::SET_HITBOX_WITH_OFFSET: + output = "SET_HITBOX_WITH_OFFSET"; + break; + case BehaviorOpcode::SPAWN_OBJ: + output = "SPAWN_OBJ"; + break; + case BehaviorOpcode::SET_HOME: + output = "SET_HOME"; + break; + case BehaviorOpcode::SET_HURTBOX: + output = "SET_HURTBOX"; + break; + case BehaviorOpcode::SET_INTERACT_TYPE: + output = "SET_INTERACT_TYPE"; + break; + case BehaviorOpcode::SET_OBJ_PHYSICS: + output = "SET_OBJ_PHYSICS"; + break; + case BehaviorOpcode::SET_INTERACT_SUBTYPE: + output = "SET_INTERACT_SUBTYPE"; + break; + case BehaviorOpcode::SCALE: + output = "SCALE"; + break; + case BehaviorOpcode::PARENT_BIT_CLEAR: + output = "PARENT_BIT_CLEAR"; + break; + case BehaviorOpcode::ANIMATE_TEXTURE: + output = "ANIMATE_TEXTURE"; + break; + case BehaviorOpcode::DISABLE_RENDERING: + output = "DISABLE_RENDERING"; + break; + case BehaviorOpcode::SET_INT_UNUSED: + output = "SET_INT_UNUSED"; + break; + case BehaviorOpcode::SPAWN_WATER_DROPLET: + output = "SPAWN_WATER_DROPLET"; + break; + default: + throw std::runtime_error("Unknown Behavior Opcode"); + } + + return out << output; +} + +#define cur_behavior_cmd_u8(offset) \ + (cmd[CMD_PROCESS_OFFSET(offset)]) + +#define cur_behavior_cmd_s16(offset) \ + (int16_t)BSWAP16((*(int16_t *) &cmd[CMD_PROCESS_OFFSET(offset)])) + +#define cur_behavior_cmd_s32(offset) \ + (int32_t)BSWAP32((*(int32_t *) &cmd[CMD_PROCESS_OFFSET(offset)])) + +#define cur_behavior_cmd_u32(offset) \ + (uint32_t) BSWAP32((*(uint32_t *) &cmd[CMD_PROCESS_OFFSET(offset)])) + +#define cur_behavior_cmd_f32(offset) \ + (float) BSWAP32((*(float *) &cmd[CMD_PROCESS_OFFSET(offset)])) |
