1#ifndef YAZE_APP_EDITOR_MESSAGE_MESSAGE_DATA_H
2#define YAZE_APP_EDITOR_MESSAGE_MESSAGE_DATA_H
87#include <unordered_map>
91#include <nlohmann/json.hpp>
92#include "absl/status/status.h"
93#include "absl/status/statusor.h"
94#include "absl/strings/match.h"
95#include "absl/strings/str_format.h"
96#include "absl/strings/str_replace.h"
111static const std::unordered_map<uint8_t, wchar_t> CharEncoder = {
112 {0x00,
'A'}, {0x01,
'B'}, {0x02,
'C'}, {0x03,
'D'}, {0x04,
'E'},
113 {0x05,
'F'}, {0x06,
'G'}, {0x07,
'H'}, {0x08,
'I'}, {0x09,
'J'},
114 {0x0A,
'K'}, {0x0B,
'L'}, {0x0C,
'M'}, {0x0D,
'N'}, {0x0E,
'O'},
115 {0x0F,
'P'}, {0x10,
'Q'}, {0x11,
'R'}, {0x12,
'S'}, {0x13,
'T'},
116 {0x14,
'U'}, {0x15,
'V'}, {0x16,
'W'}, {0x17,
'X'}, {0x18,
'Y'},
117 {0x19,
'Z'}, {0x1A,
'a'}, {0x1B,
'b'}, {0x1C,
'c'}, {0x1D,
'd'},
118 {0x1E,
'e'}, {0x1F,
'f'}, {0x20,
'g'}, {0x21,
'h'}, {0x22,
'i'},
119 {0x23,
'j'}, {0x24,
'k'}, {0x25,
'l'}, {0x26,
'm'}, {0x27,
'n'},
120 {0x28,
'o'}, {0x29,
'p'}, {0x2A,
'q'}, {0x2B,
'r'}, {0x2C,
's'},
121 {0x2D,
't'}, {0x2E,
'u'}, {0x2F,
'v'}, {0x30,
'w'}, {0x31,
'x'},
122 {0x32,
'y'}, {0x33,
'z'}, {0x34,
'0'}, {0x35,
'1'}, {0x36,
'2'},
123 {0x37,
'3'}, {0x38,
'4'}, {0x39,
'5'}, {0x3A,
'6'}, {0x3B,
'7'},
124 {0x3C,
'8'}, {0x3D,
'9'}, {0x3E,
'!'}, {0x3F,
'?'}, {0x40,
'-'},
125 {0x41,
'.'}, {0x42,
','}, {0x44,
'>'}, {0x45,
'('}, {0x46,
')'},
126 {0x4C,
'"'}, {0x51,
'\''}, {0x59,
' '}, {0x5A,
'<'}, {0x5F, L
'¡'},
127 {0x60, L
'¡'}, {0x61, L
'¡'}, {0x62, L
' '}, {0x63, L
' '}, {0x64, L
' '},
128 {0x65,
' '}, {0x66,
'_'},
186 return absl::StrContains(std::string(s),
Contents);
192 auto replaced_string = std::string(s);
193 size_t pos = replaced_string.find(
Contents);
194 while (pos != std::string::npos) {
198 return replaced_string;
217 std::string str,
const std::vector<DictionaryEntry>& dictionary);
222 std::string_view query,
size_t start_pos,
223 bool case_sensitive,
bool match_whole_word);
229 std::string_view replacement,
size_t start_pos,
230 bool replace_all,
bool case_sensitive,
231 bool match_whole_word,
232 size_t* first_replaced_pos =
nullptr);
236 uint8_t value,
const std::vector<DictionaryEntry>& dictionary);
257 const std::vector<uint8_t>& rawData,
258 const std::string& parsedString,
259 const std::vector<uint8_t>& parsedData)
282 std::string_view message_string,
283 const std::vector<DictionaryEntry>& dictionary) {
284 std::stringstream protons;
285 bool command =
false;
287 for (
const auto& c : message_string) {
290 }
else if (c ==
']') {
300 std::string protons_string = protons.str();
301 std::string replaced_string =
303 std::string final_string =
304 absl::StrReplaceAll(replaced_string, {{
CHEESE,
""}});
312 const std::vector<DictionaryEntry>& dictionary) {
343 const std::string& description) {
355 "\\[%s(:[0-9A-F]{1,2})\\]",
356 absl::StrReplaceAll(
Token, {{
"[",
"\\["}, {
"]",
"\\]"}}));
359 "\\[%s\\]", absl::StrReplaceAll(
Token, {{
"[",
"\\["}, {
"]",
"\\]"}}));
366 return absl::StrFormat(
"[%s:%02X]",
Token, value);
368 return absl::StrFormat(
"[%s]",
Token);
372 std::smatch
MatchMe(
const std::string& dfrag)
const {
375 std::regex_match(dfrag, match, pattern);
385const static std::string kWindowBorder =
"Window border";
386const static std::string kWindowPosition =
"Window position";
387const static std::string kScrollSpeed =
"Scroll speed";
388const static std::string kTextDrawSpeed =
"Text draw speed";
389const static std::string kTextColor =
"Text color";
390const static std::string kPlayerName =
"Player name";
391const static std::string kLine1Str =
"Line 1";
392const static std::string kLine2Str =
"Line 2";
393const static std::string kLine3Str =
"Line 3";
394const static std::string kWaitForKey =
"Wait for key";
395const static std::string kScrollText =
"Scroll text";
396const static std::string kDelayX =
"Delay X";
397const static std::string kBCDNumber =
"BCD number";
398const static std::string kSoundEffect =
"Sound effect";
399const static std::string kChoose3 =
"Choose 3";
400const static std::string kChoose2High =
"Choose 2 high";
401const static std::string kChoose2Low =
"Choose 2 low";
402const static std::string kChoose2Indented =
"Choose 2 indented";
403const static std::string kChooseItem =
"Choose item";
404const static std::string kNextAttractImage =
"Next attract image";
405const static std::string kBankMarker =
"Bank marker (automatic)";
406const static std::string kCrash =
"Crash";
408static const std::vector<TextElement> TextCommands = {
409 TextElement(0x6B,
"W",
true, kWindowBorder),
410 TextElement(0x6D,
"P",
true, kWindowPosition),
411 TextElement(0x6E,
"SPD",
true, kScrollSpeed),
412 TextElement(0x7A,
"S",
true, kTextDrawSpeed),
413 TextElement(0x77,
"C",
true, kTextColor),
414 TextElement(0x6A,
"L",
false, kPlayerName),
415 TextElement(0x74,
"1",
false, kLine1Str),
416 TextElement(0x75,
"2",
false, kLine2Str),
417 TextElement(0x76,
"3",
false, kLine3Str),
418 TextElement(0x7E,
"K",
false, kWaitForKey),
419 TextElement(0x73,
"V",
false, kScrollText),
420 TextElement(0x78,
"WT",
true, kDelayX),
421 TextElement(0x6C,
"N",
true, kBCDNumber),
422 TextElement(0x79,
"SFX",
true, kSoundEffect),
423 TextElement(0x71,
"CH3",
false, kChoose3),
424 TextElement(0x72,
"CH2",
false, kChoose2High),
425 TextElement(0x6F,
"CH2L",
false, kChoose2Low),
426 TextElement(0x68,
"CH2I",
false, kChoose2Indented),
427 TextElement(0x69,
"CHI",
false, kChooseItem),
428 TextElement(0x67,
"IMG",
false, kNextAttractImage),
429 TextElement(0x80,
kBankToken,
false, kBankMarker),
430 TextElement(0x70,
"NONO",
false, kCrash),
439static const std::vector<TextElement> SpecialChars = {
440 TextElement(0x43,
"...",
false,
"Ellipsis …"),
441 TextElement(0x4D,
"UP",
false,
"Arrow ↑"),
442 TextElement(0x4E,
"DOWN",
false,
"Arrow ↓"),
443 TextElement(0x4F,
"LEFT",
false,
"Arrow ←"),
444 TextElement(0x50,
"RIGHT",
false,
"Arrow →"),
445 TextElement(0x5B,
"A",
false,
"Button Ⓐ"),
446 TextElement(0x5C,
"B",
false,
"Button Ⓑ"),
447 TextElement(0x5D,
"X",
false,
"Button ⓧ"),
448 TextElement(0x5E,
"Y",
false,
"Button ⓨ"),
449 TextElement(0x52,
"HP1L",
false,
"1 HP left"),
450 TextElement(0x53,
"HP1R",
false,
"1 HP right"),
451 TextElement(0x54,
"HP2L",
false,
"2 HP left"),
452 TextElement(0x55,
"HP3L",
false,
"3 HP left"),
453 TextElement(0x56,
"HP3R",
false,
"3 HP right"),
454 TextElement(0x57,
"HP4L",
false,
"4 HP left"),
455 TextElement(0x58,
"HP4R",
false,
"4 HP right"),
456 TextElement(0x47,
"HY0",
false,
"Hieroglyph ☥"),
457 TextElement(0x48,
"HY1",
false,
"Hieroglyph 𓈗"),
458 TextElement(0x49,
"HY2",
false,
"Hieroglyph Ƨ"),
459 TextElement(0x4A,
"LFL",
false,
"Link face left"),
460 TextElement(0x4B,
"LFR",
false,
"Link face right"),
491 const std::vector<uint8_t>& rom_data,
int* current_pos);
497 std::vector<MessageData>& message_data,
498 const std::vector<DictionaryEntry>& dictionary_entries);
535 std::vector<std::pair<uint32_t, uint32_t>>
write_ranges()
const;
541 const std::vector<MessageData>& messages,
542 std::optional<size_t> expected_message_count);
560 bool allow_bank_switch =
true);
564 std::vector<std::string>& parsed_messages,
565 std::vector<MessageData>& expanded_messages,
566 std::vector<DictionaryEntry>& dictionary);
570 const std::vector<MessageData>& messages);
574 const std::vector<MessageData>& messages);
578 const std::vector<MessageData>& expanded);
582 const std::string& path,
const std::vector<MessageData>& vanilla,
583 const std::vector<MessageData>& expanded);
587 const nlohmann::json& json);
591 const std::string& path);
612 const std::string& line);
617 const std::string& content);
623 const std::vector<std::pair<int, std::string>>& messages,
624 const std::vector<std::string>& labels);
656 const std::vector<std::string>& messages);
661 const std::vector<std::string>& messages);
666 const std::vector<MessageData>& messages,
667 std::optional<size_t> expected_message_count = std::nullopt);
678 const std::vector<MessageData>& messages);
The Rom class is used to load, save, and modify Rom data. This is a generic SNES ROM container and do...
const std::vector< VanillaMessageWrite > & writes() const
size_t message_count() const
bool operator==(const VanillaMessageSavePlan &) const =default
std::vector< std::pair< uint32_t, uint32_t > > write_ranges() const
size_t bank_switch_count() const
VanillaMessageSavePlan(const VanillaMessageSavePlan &)=default
size_t bank_switch_count_
VanillaMessageSavePlan(std::vector< VanillaMessageWrite > writes, size_t message_count, size_t bank_switch_count)
std::vector< VanillaMessageWrite > writes_
friend absl::StatusOr< VanillaMessageSavePlan > BuildVanillaMessageSavePlan(const std::vector< MessageData > &messages, std::optional< size_t > expected_message_count)
VanillaMessageSavePlan & operator=(VanillaMessageSavePlan &&)=default
VanillaMessageSavePlan(VanillaMessageSavePlan &&)=default
VanillaMessageSavePlan & operator=(const VanillaMessageSavePlan &)=default
const std::vector< uint8_t > & bytes() const
std::vector< uint8_t > bytes_
bool operator==(const VanillaMessageWrite &) const =default
VanillaMessageWrite(uint32_t start, std::vector< uint8_t > bytes)
uint8_t FindMatchingCharacter(char value)
const std::string kBankToken
nlohmann::json SerializeMessagesToJson(const std::vector< MessageData > &messages)
absl::StatusOr< MessageBank > MessageBankFromString(std::string_view value)
DictionaryEntry FindRealDictionaryEntry(uint8_t value, const std::vector< DictionaryEntry > &dictionary)
constexpr int kMaxLineWidth
int GetExpandedTextDataStart()
constexpr int kMessageBundleVersion
const std::string DICTIONARYTOKEN
constexpr uint8_t kScrollVertical
std::string ParseTextDataByte(uint8_t value)
absl::Status WriteAllTextData(Rom *rom, const std::vector< MessageData > &messages)
absl::Status LoadExpandedMessages(std::string &expanded_message_path, std::vector< std::string > &parsed_messages, std::vector< MessageData > &expanded_messages, std::vector< DictionaryEntry > &dictionary)
std::optional< std::pair< int, std::string > > ParseOrgHeader(const std::string &line)
std::string MessageBankToString(MessageBank bank)
constexpr int kExpandedTextDataEndDefault
std::string ReplaceAllDictionaryWords(std::string str, const std::vector< DictionaryEntry > &dictionary)
absl::Status WriteExpandedTextData(Rom *rom, int start, int end, const std::vector< std::string > &messages)
nlohmann::json SerializeMessageBundle(const std::vector< MessageData > &vanilla, const std::vector< MessageData > &expanded)
constexpr int kPointersDictionaries
absl::StatusOr< std::vector< MessageBundleEntry > > LoadMessageBundleFromJson(const std::string &path)
constexpr int kNumDictionaryEntries
absl::StatusOr< MessageData > ParseSingleMessage(const std::vector< uint8_t > &rom_data, int *current_pos)
absl::StatusOr< std::vector< MessageBundleEntry > > ParseMessageBundleJson(const nlohmann::json &json)
std::vector< MessageData > ReadAllTextData(uint8_t *rom, int pos, int max_pos, bool allow_bank_switch)
std::vector< std::string > ParseMessageData(std::vector< MessageData > &message_data, const std::vector< DictionaryEntry > &dictionary_entries)
std::optional< TextElement > FindMatchingSpecial(uint8_t value)
constexpr uint8_t kMessageTerminator
constexpr int kTextData2End
std::vector< DictionaryEntry > BuildDictionaryEntries(Rom *rom)
constexpr uint8_t kBankSwitchCommand
int ReplaceTextMatches(std::string *text, std::string_view query, std::string_view replacement, size_t start_pos, bool replace_all, bool case_sensitive, bool match_whole_word, size_t *first_replaced_pos)
std::optional< size_t > FindTextMatch(std::string_view text, std::string_view query, size_t start_pos, bool case_sensitive, bool match_whole_word)
std::vector< uint8_t > ParseMessageToData(std::string str)
absl::Status ExportMessagesToJson(const std::string &path, const std::vector< MessageData > &messages)
constexpr uint8_t kWidthArraySize
absl::Status ExportMessageBundleToJson(const std::string &path, const std::vector< MessageData > &vanilla, const std::vector< MessageData > &expanded)
constexpr uint8_t DICTOFF
std::string ExportToOrgFormat(const std::vector< std::pair< int, std::string > > &messages, const std::vector< std::string > &labels)
absl::StatusOr< VanillaMessageSavePlan > BuildVanillaMessageSavePlan(const std::vector< MessageData > &messages, std::optional< size_t > expected_message_count)
std::vector< MessageData > ReadExpandedTextData(uint8_t *rom, int pos)
std::optional< TextElement > FindMatchingCommand(uint8_t b)
MessageParseResult ParseMessageToDataWithDiagnostics(std::string_view str)
int GetExpandedTextDataEnd()
ParsedElement FindMatchingElement(const std::string &str)
std::vector< std::string > ValidateMessageLineWidths(const std::string &message)
std::vector< std::pair< int, std::string > > ParseOrgContent(const std::string &content)
constexpr int kExpandedTextDataDefault
int8_t FindDictionaryEntry(uint8_t value)
absl::Status ApplyVanillaMessageSavePlan(Rom *rom, const VanillaMessageSavePlan &plan)
constexpr int kTextDataEnd
bool ContainedInString(std::string_view s) const
std::string ReplaceInstancesOfIn(std::string_view s) const
DictionaryEntry(uint8_t i, std::string_view s)
std::vector< uint8_t > Data
DictionaryEntry()=default
MessageData(const MessageData &other)
std::vector< uint8_t > Data
std::vector< uint8_t > DataParsed
std::string ContentsParsed
std::string OptimizeMessageForDictionary(std::string_view message_string, const std::vector< DictionaryEntry > &dictionary)
void SetMessage(const std::string &message, const std::vector< DictionaryEntry > &dictionary)
MessageData(int id, int address, const std::string &rawString, const std::vector< uint8_t > &rawData, const std::string &parsedString, const std::vector< uint8_t > &parsedData)
std::vector< uint8_t > bytes
std::vector< std::string > errors
std::vector< std::string > warnings
ParsedElement(const TextElement &textElement, uint8_t value)
std::smatch MatchMe(const std::string &dfrag) const
std::string StrictPattern
TextElement(uint8_t id, const std::string &token, bool arg, const std::string &description)
bool operator==(const TextElement &other) const
std::string GetParamToken(uint8_t value=0) const