Skip to content
Open
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
166 changes: 93 additions & 73 deletions soh/soh/Enhancements/randomizer/3drando/spoiler_log.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,10 @@

#include <ship/Context.h>
#include <soh/OTRGlobals.h>
#include <soh/util.h>

#include <libultraship/bridge/consolevariablebridge.h>
#include <spdlog/spdlog.h>

using json = nlohmann::ordered_json;
using namespace Rando;
Expand All @@ -40,6 +42,10 @@ namespace {
std::string placementtxt;
} // namespace

static std::string SafeJsonString(std::string value) {
return SohUtils::SanitizeUtf8(std::move(value));
}

void GenerateHash() {
auto ctx = Rando::Context::GetInstance();
std::string hash = ctx->GetHash();
Expand Down Expand Up @@ -73,13 +79,16 @@ static void WriteLocation(std::string sphere, const RandomizerCheck locationKey,
switch (gSaveContext.language) {
case LANGUAGE_ENG:
default:
jsonData["playthrough"][sphere][location->GetName()] = itemLocation->GetPlacedItemName().GetEnglish();
jsonData["playthrough"][sphere][location->GetName()] =
SafeJsonString(itemLocation->GetPlacedItemName().GetEnglish());
break;
case LANGUAGE_GER:
jsonData["playthrough"][sphere][location->GetName()] = itemLocation->GetPlacedItemName().GetGerman();
jsonData["playthrough"][sphere][location->GetName()] =
SafeJsonString(itemLocation->GetPlacedItemName().GetGerman());
break;
case LANGUAGE_FRA:
jsonData["playthrough"][sphere][location->GetName()] = itemLocation->GetPlacedItemName().GetFrench();
jsonData["playthrough"][sphere][location->GetName()] =
SafeJsonString(itemLocation->GetPlacedItemName().GetFrench());
break;
}
}
Expand Down Expand Up @@ -130,7 +139,7 @@ static void WriteShuffledEntrance(std::string sphereString, Entrance* entrance)
case LANGUAGE_GER:
case LANGUAGE_FRA:
default:
jsonData["entrancesMap"][sphereString][name] = text;
jsonData["entrancesMap"][sphereString][name] = SafeJsonString(text);
break;
}
}
Expand All @@ -141,7 +150,8 @@ static void WriteSettings() {
std::array<Rando::Option, RSK_MAX> options = Rando::Settings::GetInstance()->GetAllOptions();
for (const Rando::Option& option : options) {
if (option.GetName() != "") {
jsonData["settings"][option.GetName()] = option.GetOptionText(ctx->GetOption(option.GetKey()).Get());
jsonData["settings"][option.GetName()] =
SafeJsonString(option.GetOptionText(ctx->GetOption(option.GetKey()).Get()));
}
}
}
Expand All @@ -162,7 +172,7 @@ static void WriteExcludedLocations() {
continue;
}

jsonData["excludedLocations"].push_back(RemoveLineBreaks(location->GetName()));
jsonData["excludedLocations"].push_back(SafeJsonString(RemoveLineBreaks(location->GetName())));
}
}
}
Expand All @@ -174,7 +184,8 @@ static void WriteStartingInventory() {
for (const Rando::OptionGroup* subGroup : optionGroup.GetSubGroups()) {
if (subGroup->GetContainsType() == Rando::OptionGroupType::DEFAULT) {
for (Rando::Option* option : subGroup->GetOptions()) {
jsonData["settings"][option->GetName()] = option->GetOptionText(ctx->GetOption(option->GetKey()).Get());
jsonData["settings"][option->GetName()] =
SafeJsonString(option->GetOptionText(ctx->GetOption(option->GetKey()).Get()));
}
}
}
Expand All @@ -188,7 +199,7 @@ static void WriteEnabledTricks() {
if (ctx->GetTrickOption(static_cast<RandomizerTrick>(setting->GetKey())).IsNot(RO_GENERIC_ON)) {
continue;
}
jsonData["enabledTricks"].push_back(RemoveLineBreaks(setting->GetName()).c_str());
jsonData["enabledTricks"].push_back(SafeJsonString(RemoveLineBreaks(setting->GetName())));
}
}

Expand All @@ -200,7 +211,7 @@ static void WriteMasterQuestDungeons() {
if (dungeon->IsVanilla()) {
continue;
}
jsonData["masterQuestDungeons"].push_back(dungeon->GetName());
jsonData["masterQuestDungeons"].push_back(SafeJsonString(dungeon->GetName()));
}
}

Expand All @@ -210,7 +221,7 @@ static void WriteChosenOptions() {
for (const auto& trial : ctx->GetTrials()->GetTrialList()) {
if (trial->IsRequired()) {
std::string trialName = trial->GetName().GetForCurrentLanguage(MF_CLEAN);
jsonData["requiredTrials"].push_back(RemoveLineBreaks(trialName));
jsonData["requiredTrials"].push_back(SafeJsonString(RemoveLineBreaks(trialName)));
}
}
if (ctx->GetOption(RSK_SELECTED_STARTING_AGE).Is(RO_AGE_ADULT)) {
Expand Down Expand Up @@ -276,13 +287,13 @@ static void WriteAllLocations() {
if (!location->HasCustomPrice() && location->GetPlacedRandomizerGet() != RG_ICE_TRAP) {

jsonData["locations"][Rando::StaticData::GetLocation(location->GetRandomizerCheck())->GetName()] =
placedItemName;
SafeJsonString(placedItemName);
continue;
}

// We're dealing with a complex item, build out the json object for it
jsonData["locations"][Rando::StaticData::GetLocation(location->GetRandomizerCheck())->GetName()]["item"] =
placedItemName;
SafeJsonString(placedItemName);

if (location->HasCustomPrice()) {
jsonData["locations"][Rando::StaticData::GetLocation(location->GetRandomizerCheck())->GetName()]["price"] =
Expand All @@ -297,30 +308,33 @@ static void WriteAllLocations() {
case 0:
default:
jsonData["locations"][Rando::StaticData::GetLocation(location->GetRandomizerCheck())->GetName()]
["model"] = Rando::StaticData::RetrieveItem(
ctx->overrides[location->GetRandomizerCheck()].LooksLike())
.GetName()
.GetEnglish();
["model"] = SafeJsonString(Rando::StaticData::RetrieveItem(
ctx->overrides[location->GetRandomizerCheck()].LooksLike())
.GetName()
.GetEnglish());
jsonData["locations"][Rando::StaticData::GetLocation(location->GetRandomizerCheck())->GetName()]
["trickName"] = ctx->overrides[location->GetRandomizerCheck()].GetTrickName().GetEnglish();
["trickName"] = SafeJsonString(
ctx->overrides[location->GetRandomizerCheck()].GetTrickName().GetEnglish());
break;
case 1:
jsonData["locations"][Rando::StaticData::GetLocation(location->GetRandomizerCheck())->GetName()]
["model"] = Rando::StaticData::RetrieveItem(
ctx->overrides[location->GetRandomizerCheck()].LooksLike())
.GetName()
.GetGerman();
["model"] = SafeJsonString(Rando::StaticData::RetrieveItem(
ctx->overrides[location->GetRandomizerCheck()].LooksLike())
.GetName()
.GetGerman());
jsonData["locations"][Rando::StaticData::GetLocation(location->GetRandomizerCheck())->GetName()]
["trickName"] = ctx->overrides[location->GetRandomizerCheck()].GetTrickName().GetGerman();
["trickName"] = SafeJsonString(
ctx->overrides[location->GetRandomizerCheck()].GetTrickName().GetGerman());
break;
case 2:
jsonData["locations"][Rando::StaticData::GetLocation(location->GetRandomizerCheck())->GetName()]
["model"] = Rando::StaticData::RetrieveItem(
ctx->overrides[location->GetRandomizerCheck()].LooksLike())
.GetName()
.GetFrench();
["model"] = SafeJsonString(Rando::StaticData::RetrieveItem(
ctx->overrides[location->GetRandomizerCheck()].LooksLike())
.GetName()
.GetFrench());
jsonData["locations"][Rando::StaticData::GetLocation(location->GetRandomizerCheck())->GetName()]
["trickName"] = ctx->overrides[location->GetRandomizerCheck()].GetTrickName().GetFrench();
["trickName"] = SafeJsonString(
ctx->overrides[location->GetRandomizerCheck()].GetTrickName().GetFrench());
break;
}
}
Expand All @@ -330,59 +344,65 @@ static void WriteAllLocations() {
void SpoilerLog_Write() {
auto ctx = Rando::Context::GetInstance();

jsonData.clear();

jsonData["version"] = (char*)gBuildVersion;
jsonData["fileType"] = FILE_TYPE_SPOILER;
jsonData["git_branch"] = (char*)gGitBranch;
jsonData["git_commit"] = (char*)gGitCommitHash;
jsonData["seed"] = ctx->GetSeedString();
jsonData["finalSeed"] = ctx->GetSeed();

// Write Hash
int index = 0;
for (uint8_t seed_value : ctx->hashIconIndexes) {
jsonData["file_hash"][index] = seed_value;
index++;
}

WriteSettings();
WriteExcludedLocations();
WriteStartingInventory();
WriteEnabledTricks();
WriteMasterQuestDungeons();
WriteChosenOptions();
WritePlaythrough();
try {
jsonData.clear();
hintedLocations.clear();

jsonData["version"] = (char*)gBuildVersion;
jsonData["fileType"] = FILE_TYPE_SPOILER;
jsonData["git_branch"] = (char*)gGitBranch;
jsonData["git_commit"] = (char*)gGitCommitHash;
jsonData["seed"] = SafeJsonString(ctx->GetSeedString());
jsonData["finalSeed"] = ctx->GetSeed();

// Write Hash
int index = 0;
for (uint8_t seed_value : ctx->hashIconIndexes) {
jsonData["file_hash"][index] = seed_value;
index++;
}

ctx->playthroughLocations.clear();
ctx->playthroughBeatable = false;
WriteSettings();
WriteExcludedLocations();
WriteStartingInventory();
WriteEnabledTricks();
WriteMasterQuestDungeons();
WriteChosenOptions();
WritePlaythrough();

ctx->WriteHintJson(jsonData);
WriteShuffledEntrances();
WriteAllLocations();
ctx->playthroughLocations.clear();
ctx->playthroughBeatable = false;

if (!std::filesystem::exists(Ship::Context::GetPathRelativeToAppDirectory("Randomizer"))) {
std::filesystem::create_directory(Ship::Context::GetPathRelativeToAppDirectory("Randomizer"));
}
ctx->WriteHintJson(jsonData);
WriteShuffledEntrances();
WriteAllLocations();

std::string jsonString = jsonData.dump(4);
std::ostringstream fileNameStream;
for (uint8_t i = 0; i < ctx->hashIconIndexes.size(); i++) {
if (i) {
fileNameStream << '-';
if (!std::filesystem::exists(Ship::Context::GetPathRelativeToAppDirectory("Randomizer"))) {
std::filesystem::create_directory(Ship::Context::GetPathRelativeToAppDirectory("Randomizer"));
}
if (ctx->hashIconIndexes[i] < 10) {
fileNameStream << '0';

std::string jsonString = jsonData.dump(4);
std::ostringstream fileNameStream;
for (uint8_t i = 0; i < ctx->hashIconIndexes.size(); i++) {
if (i) {
fileNameStream << '-';
}
if (ctx->hashIconIndexes[i] < 10) {
fileNameStream << '0';
}
fileNameStream << std::to_string(ctx->hashIconIndexes[i]);
}
fileNameStream << std::to_string(ctx->hashIconIndexes[i]);
std::string fileName = fileNameStream.str();
std::ofstream jsonFile(Ship::Context::GetPathRelativeToAppDirectory(
(std::string("Randomizer/") + fileName + std::string(".json")).c_str()));
jsonFile << std::setw(4) << jsonString << std::endl;
jsonFile.close();

CVarSetString(CVAR_GENERAL("SpoilerLog"),
(std::string("./Randomizer/") + fileName + std::string(".json")).c_str());
} catch (const std::exception& e) {
SPDLOG_ERROR("SpoilerLog_Write failed: {}", e.what());
}
std::string fileName = fileNameStream.str();
std::ofstream jsonFile(Ship::Context::GetPathRelativeToAppDirectory(
(std::string("Randomizer/") + fileName + std::string(".json")).c_str()));
jsonFile << std::setw(4) << jsonString << std::endl;
jsonFile.close();

CVarSetString(CVAR_GENERAL("SpoilerLog"), (std::string("./Randomizer/") + fileName + std::string(".json")).c_str());
}

void PlacementLog_Msg(std::string_view msg) {
Expand Down
43 changes: 22 additions & 21 deletions soh/soh/Enhancements/randomizer/hint.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#include "map"
#include "string"
#include "SeedContext.h"
#include "soh/util.h"
#include <spdlog/spdlog.h>
#include "static_data.h"
#include "3drando/random.hpp"
Expand Down Expand Up @@ -375,31 +376,34 @@ oJson Hint::toJSON() {
auto ctx = Rando::Context::GetInstance();
nlohmann::ordered_json log = {};
if (enabled) {
log["type"] = StaticData::hintTypeNames[hintType].GetForCurrentLanguage(MF_CLEAN);
log["type"] = SohUtils::SanitizeUtf8(StaticData::hintTypeNames[hintType].GetForCurrentLanguage(MF_CLEAN));

std::vector<std::string> hintMessages = GetAllMessageStrings(MF_CLEAN);
if (hintMessages.size() == 1) {
log["message"] = hintMessages[0];
log["message"] = SohUtils::SanitizeUtf8(hintMessages[0]);
} else if (hintMessages.size() > 1) {
log["messages"] = hintMessages;
std::vector<std::string> sanitizedMessages;
sanitizedMessages.reserve(hintMessages.size());
for (const std::string& message : hintMessages) {
sanitizedMessages.push_back(SohUtils::SanitizeUtf8(message));
}
log["messages"] = sanitizedMessages;
}

if (distribution != "") {
log["distribution"] = distribution;
log["distribution"] = SohUtils::SanitizeUtf8(distribution);
}

if (hintType != HINT_TYPE_FOOLISH) {
if (!(StaticData::staticHintInfoMap.contains(ownKey) &&
StaticData::staticHintInfoMap[ownKey].targetChecks.size() > 0)) {
if (locations.size() == 1) {
log["location"] = StaticData::GetLocation(locations[0])
->GetName(); // RANDOTODO change to CustomMessage when VB is done;
log["location"] = SohUtils::SanitizeUtf8(StaticData::GetLocation(locations[0])->GetName());
} else if (locations.size() > 1) {
// If we have defaults, no need to write more
std::vector<std::string> locStrings = {};
for (size_t c = 0; c < locations.size(); c++) {
locStrings.push_back(StaticData::GetLocation(locations[c])
->GetName()); // RANDOTODO change to CustomMessage when VB is done
locStrings.push_back(SohUtils::SanitizeUtf8(StaticData::GetLocation(locations[c])->GetName()));
}
log["locations"] = locStrings;
}
Expand All @@ -408,15 +412,11 @@ oJson Hint::toJSON() {
if (!(StaticData::staticHintInfoMap.contains(ownKey) &&
StaticData::staticHintInfoMap[ownKey].targetItems.size() > 0)) {
if (items.size() == 1) {
log["item"] = StaticData::GetItemTable()[items[0]]
.GetName()
.GetEnglish(); // RANDOTODO change to CustomMessage;
log["item"] = SohUtils::SanitizeUtf8(StaticData::GetItemTable()[items[0]].GetName().GetEnglish());
} else if (items.size() > 1) {
std::vector<std::string> itemStrings = {};
for (size_t c = 0; c < items.size(); c++) {
itemStrings.push_back(StaticData::GetItemTable()[items[c]]
.GetName()
.GetEnglish()); // RANDOTODO change to CustomMessage
itemStrings.push_back(SohUtils::SanitizeUtf8(StaticData::GetItemTable()[items[c]].GetName().GetEnglish()));
}
log["items"] = itemStrings;
}
Expand All @@ -433,16 +433,16 @@ oJson Hint::toJSON() {
}
}
if (areas.size() == 1) {
log["area"] =
StaticData::hintTextTable[StaticData::areaNames[areas[0]]].GetClear().GetForCurrentLanguage(MF_CLEAN);
log["area"] = SohUtils::SanitizeUtf8(
StaticData::hintTextTable[StaticData::areaNames[areas[0]]].GetClear().GetForCurrentLanguage(MF_CLEAN));
} else if (areas.size() > 0 && !(StaticData::staticHintInfoMap.contains(ownKey) &&
StaticData::staticHintInfoMap[ownKey].targetChecks.size() > 0)) {
// If we got locations from defaults, areas are derived from them and don't need logging
std::vector<std::string> areaStrings = {};
for (size_t c = 0; c < areas.size(); c++) {
areaStrings.push_back(
areaStrings.push_back(SohUtils::SanitizeUtf8(
StaticData::hintTextTable[StaticData::areaNames[areas[c]]].GetClear().GetForCurrentLanguage(
MF_CLEAN));
MF_CLEAN)));
}
log["areas"] = areaStrings;
}
Expand All @@ -458,11 +458,12 @@ oJson Hint::toJSON() {
}

if (trials.size() == 1) {
log["trial"] = ctx->GetTrial(trials[0])->GetName().GetForCurrentLanguage(MF_CLEAN);
log["trial"] = SohUtils::SanitizeUtf8(ctx->GetTrial(trials[0])->GetName().GetForCurrentLanguage(MF_CLEAN));
} else if (trials.size() > 0) {
std::vector<std::string> trialStrings = {};
for (size_t c = 0; c < trials.size(); c++) {
trialStrings.push_back(ctx->GetTrial(trials[c])->GetName().GetForCurrentLanguage(MF_CLEAN));
trialStrings.push_back(
SohUtils::SanitizeUtf8(ctx->GetTrial(trials[c])->GetName().GetForCurrentLanguage(MF_CLEAN)));
}
log["trials"] = trialStrings;
}
Expand Down Expand Up @@ -505,7 +506,7 @@ void Hint::logHint(oJson& jsonData) {
if (enabled &&
(!(staticHint && (hintType == HINT_TYPE_ITEM) && ctx->GetOption(RSK_HINT_CLARITY).Is(RO_HINT_CLARITY_CLEAR)))) {
// skip if not enabled or if a static hint with no possible variance
jsonData[logMap][Rando::StaticData::hintNames[ownKey].GetForCurrentLanguage(MF_CLEAN)] = toJSON();
jsonData[logMap][SohUtils::SanitizeUtf8(Rando::StaticData::hintNames[ownKey].GetForCurrentLanguage(MF_CLEAN))] = toJSON();
}
}

Expand Down
Loading
Loading