mirror of
https://github.com/izzy2lost/Torch.git
synced 2026-07-06 00:18:35 -07:00
Behavior Script Factory
This commit is contained in:
@@ -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>());
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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)
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -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)]))
|
||||
Reference in New Issue
Block a user