Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 0 additions & 12 deletions src/factories/bk64/AnimFactory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,6 @@

namespace BK64 {

ExportResult AnimHeaderExporter::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 ALIGN_ASSET(2) char " << symbol << "[] = \"__OTR__" << (*replacement) << "\";\n\n";
return std::nullopt;
}

return std::nullopt;
}

ExportResult AnimCodeExporter::Export(std::ostream& write, std::shared_ptr<IParsedData> raw, std::string& entryName,
YAML::Node& node, std::string* replacement) {
auto offset = GetSafeNode<uint32_t>(node, "offset");
Expand Down
8 changes: 2 additions & 6 deletions src/factories/bk64/AnimFactory.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#pragma once

#include <factories/BaseFactory.h>
#include "factories/bk64/BKHeaderExporter.h"

namespace BK64 {

Expand Down Expand Up @@ -36,11 +37,6 @@ class AnimData : public IParsedData {
}
};

class AnimHeaderExporter : public BaseExporter {
ExportResult Export(std::ostream& write, std::shared_ptr<IParsedData> data, std::string& entryName,
YAML::Node& node, std::string* replacement) override;
};

class AnimBinaryExporter : public BaseExporter {
ExportResult Export(std::ostream& write, std::shared_ptr<IParsedData> data, std::string& entryName,
YAML::Node& node, std::string* replacement) override;
Expand All @@ -61,7 +57,7 @@ class AnimFactory : public BaseFactory {
std::optional<std::shared_ptr<IParsedData>> parse(std::vector<uint8_t>& buffer, YAML::Node& data) override;
std::optional<std::shared_ptr<IParsedData>> parse_modding(std::vector<uint8_t>& buffer, YAML::Node& data) override;
inline std::unordered_map<ExportType, std::shared_ptr<BaseExporter>> GetExporters() override {
return { REGISTER(Code, AnimCodeExporter) REGISTER(Header, AnimHeaderExporter)
return { REGISTER(Code, AnimCodeExporter) REGISTER(Header, BKHeaderExporter)
REGISTER(Binary, AnimBinaryExporter) REGISTER(Modding, AnimModdingExporter) };
}
bool SupportModdedAssets() override {
Expand Down
77 changes: 35 additions & 42 deletions src/factories/bk64/BKAssetFactory.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include "BKAssetFactory.h"
#include "Companion.h"
#include "ConfigFactory.h"
#include "BKAssetTable.h"
#include "spdlog/spdlog.h"
#include "utils/Decompressor.h"
#include "TinySHA1.hpp"
Expand All @@ -14,6 +15,27 @@

namespace BK64 {

// Font masks + text-bearing models / signs / overlays a language pack
// may relocalize.
static const std::unordered_set<uint32_t> kLangAssets = {
0x6EB, // SPRITE_DIALOG_FONT_ALPHAMASK
0x6EC, // SPRITE_BOLD_FONT_LETTERS_ALPHAMASK
0x2EE, // ON_VACATIOIN_SIGN
0x46C, // JIGSAW_PUZZLE
0x486, // XMAS_TREE_SWITCH
0x48B, // JIGGY_PODIUM
0x4EA, // RACE_BANNER_FINISH
0x4EB, // RACE_BANNER_START
0x50A, // SHARKFOOD_ISLAND (model with sign)
0x54C, // GAME OVER
0x54D, // BANJO_KAZOOIE_SIGN
0x54E, // COPYRIGHT_OVERLAY
0x55C, // PRESS_START_OVERLAY
0x55D, // NO_CONTROLLER_OVERLAY
0x563, // LEVEL_ENTRY_SIGNS
0x56C, // THE_END_SIGN
};

static const std::unordered_map<BKAssetType, std::string> sAssetSymbolPrefixes = {
{ BKAssetType::Animation, "ANIM" },
{ BKAssetType::Binary, "BIN" },
Expand Down Expand Up @@ -306,33 +328,20 @@ std::optional<std::shared_ptr<IParsedData>> BKAssetFactory::parse(std::vector<ui

int count = 0;

// Slot size = gap to the next-higher table offset.
std::vector<uint32_t> sortedOffsets;
sortedOffsets.reserve(assetTableInfo.size());
std::vector<uint32_t> offsets;
offsets.reserve(assetTableInfo.size());
for (const auto& ai : assetTableInfo) {
sortedOffsets.push_back(ai.offset);
offsets.push_back(ai.offset);
}
std::sort(sortedOffsets.begin(), sortedOffsets.end());
sortedOffsets.erase(std::unique(sortedOffsets.begin(), sortedOffsets.end()), sortedOffsets.end());
auto slotSize = [&](uint32_t off) -> uint32_t {
auto it = std::upper_bound(sortedOffsets.begin(), sortedOffsets.end(), off);
if (it != sortedOffsets.end()) {
return *it - off;
}
uint64_t start = static_cast<uint64_t>(dataStartRomOffset) + off;
return start < buffer.size() ? static_cast<uint32_t>(buffer.size() - start) : 0;
};
const SlotSizer slotSize(offsets, dataStartRomOffset, buffer.size());

size_t outOfOrder = 0;
for (uint32_t i = 0; i + 1 < assetCount; i++) {
if (assetTableInfo.at(i + 1).offset < assetTableInfo.at(i).offset) {
outOfOrder++;
if (slotSize.StrayCount() > 0) {
for (uint32_t i = 0; i < assetCount; i++) {
if (slotSize.IsStray(i)) {
SPDLOG_WARN(" stray table entry {} at offset 0x{:X}", i, assetTableInfo.at(i).offset);
}
}
}
if (outOfOrder > 0) {
SPDLOG_WARN("Asset table is not monotonic ({} out-of-order entries); sizing slots by next-higher offset",
outOfOrder);
}

// Warm the decompressor cache up front, in parallel. The serial parse
// pass below then mostly hits already-decoded data.
Expand Down Expand Up @@ -393,6 +402,10 @@ std::optional<std::shared_ptr<IParsedData>> BKAssetFactory::parse(std::vector<ui
continue;
}

if (assetSize == 0) {
continue;
}

if (static_cast<uint64_t>(assetOffset) + assetSize > buffer.size()) {
SPDLOG_ERROR("Asset {} offset 0x{:X} + size 0x{:X} = 0x{:X} exceeds ROM "
"buffer 0x{:X}",
Expand Down Expand Up @@ -499,26 +512,6 @@ std::optional<std::shared_ptr<IParsedData>> BKAssetFactory::parse(std::vector<ui
if (Companion::Instance->GetConfig().dialogPack) {
const bool isText = assetType == BKAssetType::Dialog || assetType == BKAssetType::GruntyQuestion ||
assetType == BKAssetType::QuizQuestion;
// Font masks + text-bearing models / signs / overlays a language pack
// may relocalize.
static const std::unordered_set<uint32_t> kLangAssets = {
0x6EB, // SPRITE_DIALOG_FONT_ALPHAMASK (dialog/quiz/grunty text)
0x6EC, // SPRITE_BOLD_FONT_LETTERS_ALPHAMASK (world names, headers)
0x2EE, // ON_VACATIOIN_SIGN
0x46C, // JIGSAW_PUZZLE
0x486, // XMAS_TREE_SWITCH
0x48B, // JIGGY_PODIUM
0x4EA, // RACE_BANNER_FINISH
0x4EB, // RACE_BANNER_START
0x50A, // SHARKFOOD_ISLAND (model with sign)
0x54C, // GAME OVER
0x54D, // BANJO_KAZOOIE_SIGN
0x54E, // COPYRIGHT_OVERLAY
0x55C, // PRESS_START_OVERLAY
0x55D, // NO_CONTROLLER_OVERLAY
0x563, // LEVEL_ENTRY_SIGNS
0x56C, // THE_END_SIGN
};
const uint32_t idx = assetInfo.index;
bool isLangAsset = kLangAssets.count(idx) != 0;
// The JP cart additionally carries the kana dialog font and the
Expand Down
67 changes: 67 additions & 0 deletions src/factories/bk64/BKAssetTable.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
#pragma once

#include <algorithm>
#include <cstddef>
#include <cstdint>
#include <vector>

namespace BK64 {

class SlotSizer {
public:
SlotSizer(const std::vector<uint32_t>& offsets, uint32_t dataStart, size_t romSize)
: mStray(offsets.size(), false), mDataStart(dataStart), mRomSize(romSize) {
mBoundaries.reserve(offsets.size());
uint32_t high = 0;
for (size_t i = 0; i < offsets.size(); i++) {
if (offsets[i] < high) {
mStray[i] = true;
mStrayCount++;
continue;
}
high = offsets[i];
mBoundaries.push_back(offsets[i]);
}
std::sort(mBoundaries.begin(), mBoundaries.end());
mBoundaries.erase(std::unique(mBoundaries.begin(), mBoundaries.end()), mBoundaries.end());
mRegionEnd = mBoundaries.empty() ? 0 : mBoundaries.back();
}

uint32_t operator()(uint32_t off) const {
if (off >= mRegionEnd) {
return 0;
}
const auto next = std::upper_bound(mBoundaries.begin(), mBoundaries.end(), off);
const uint32_t end = std::min(next != mBoundaries.end() ? *next : mRegionEnd, mRegionEnd);
if (end <= off) {
return 0;
}
const uint64_t start = static_cast<uint64_t>(mDataStart) + off;
if (start >= mRomSize) {
return 0;
}
return static_cast<uint32_t>(std::min<uint64_t>(end - off, mRomSize - start));
}

bool IsStray(size_t index) const {
return index < mStray.size() && mStray[index];
}

size_t StrayCount() const {
return mStrayCount;
}

uint32_t RegionEnd() const {
return mRegionEnd;
}

private:
std::vector<uint32_t> mBoundaries;
std::vector<bool> mStray;
size_t mStrayCount = 0;
uint32_t mRegionEnd = 0;
uint32_t mDataStart;
size_t mRomSize;
};

} // namespace BK64
24 changes: 24 additions & 0 deletions src/factories/bk64/BKByteUtils.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#pragma once

#include <cstdint>

namespace BK64 {

// Big-endian scalar reads from raw ROM/overlay bytes.
inline uint16_t ReadU16BE(const uint8_t* p) {
return static_cast<uint16_t>((p[0] << 8) | p[1]);
}

inline int16_t ReadS16BE(const uint8_t* p) {
return static_cast<int16_t>(ReadU16BE(p));
}

inline uint32_t ReadU32BE(const uint8_t* p) {
return ((uint32_t)p[0] << 24) | ((uint32_t)p[1] << 16) | ((uint32_t)p[2] << 8) | (uint32_t)p[3];
}

inline int32_t ReadS32BE(const uint8_t* p) {
return static_cast<int32_t>(ReadU32BE(p));
}

} // namespace BK64
Loading
Loading