Rewrite Logic Tracker to consolidate Check and Region. Initial multiple drill down levels.

This commit is contained in:
Anthony Stewart 2025-07-10 22:03:14 -05:00 committed by xxAtrain223
commit 23f8520205

View file

@ -32,24 +32,8 @@ struct ExpressionTable {
bool CombineAdult = false; bool CombineAdult = false;
}; };
struct LogicTrackerCheck { struct LogicTrackerNode {
struct Region { struct Connection {
std::string RegionName;
RandomizerRegion RandomizerRegion;
ExpressionTable ExpressionTable;
bool ChildDayAccess = false;
bool ChildNightAccess = false;
bool AdultDayAccess = false;
bool AdultNightAccess = false;
};
std::string CheckName;
std::vector<Region> Regions;
};
struct LogicTrackerRegion {
struct Entrance {
std::string ParentName; std::string ParentName;
RandomizerRegion ParentRandomizerRegion; RandomizerRegion ParentRandomizerRegion;
ExpressionTable ExpressionTable; ExpressionTable ExpressionTable;
@ -60,10 +44,15 @@ struct LogicTrackerRegion {
bool AdultNightAccess = false; bool AdultNightAccess = false;
}; };
std::string RegionName; std::string NodeName;
std::vector<Entrance> Entrances; std::vector<Connection> Connections;
int NodeId;
}; };
bool expandingNode = false;
int expandNodeId = -1;
std::vector<LogicTrackerNode> nodes;
static ExpressionTable::ExpressionRow CreateExpressionRows(const std::shared_ptr<LogicExpression>& expression) { static ExpressionTable::ExpressionRow CreateExpressionRows(const std::shared_ptr<LogicExpression>& expression) {
ExpressionTable::ExpressionRow row; ExpressionTable::ExpressionRow row;
row.Expression = expression; row.Expression = expression;
@ -85,7 +74,6 @@ enum class AgeTime {
AdultNight AdultNight
}; };
static void PopulateExpressionValues(ExpressionTable::ExpressionRow& row, const ExpressionEvaluation& eval, static void PopulateExpressionValues(ExpressionTable::ExpressionRow& row, const ExpressionEvaluation& eval,
AgeTime ageTime) { AgeTime ageTime) {
if (ageTime == AgeTime::ChildDay) { if (ageTime == AgeTime::ChildDay) {
@ -121,161 +109,162 @@ static std::tuple<bool, bool, bool> CalculateCombines(const ExpressionTable::Exp
return {combineAll, combineChild, combineAdult}; return {combineAll, combineChild, combineAdult};
} }
bool expandCheck = false;
std::unique_ptr<LogicTrackerCheck> logicTrackerCheck;
void LogicTrackerWindow::ShowRandomizerCheck(RandomizerCheck randomizerCheck) { void LogicTrackerWindow::ShowRandomizerCheck(RandomizerCheck randomizerCheck) {
const auto& location = Rando::StaticData::GetLocation(randomizerCheck); const auto& location = Rando::StaticData::GetLocation(randomizerCheck);
logicTrackerCheck = std::make_unique<LogicTrackerCheck>();
logicTrackerCheck->CheckName = location->GetName();
//for (const auto& region : areaTable) { nodes.clear();
LogicTrackerNode node;
node.NodeName = location->GetName();
node.NodeId = nodes.size();
for (int randomizerRegion = RR_NONE; randomizerRegion < RR_MAX; ++randomizerRegion) { for (int randomizerRegion = RR_NONE; randomizerRegion < RR_MAX; ++randomizerRegion) {
const auto& region = areaTable[randomizerRegion]; const auto& region = areaTable[randomizerRegion];
for (const auto& locationAccess : region.locations) { for (const auto& locationAccess : region.locations) {
if (locationAccess.GetLocation() == randomizerCheck) { if (locationAccess.GetLocation() == randomizerCheck) {
LogicTrackerCheck::Region regionAgeTime; LogicTrackerNode::Connection connection;
regionAgeTime.RegionName = region.regionName; connection.ParentName = region.regionName;
regionAgeTime.RandomizerRegion = RandomizerRegion(randomizerRegion); connection.ParentRandomizerRegion = RandomizerRegion(randomizerRegion);
regionAgeTime.ExpressionTable.Root = CreateExpressionRows(LogicExpression::Parse(locationAccess.GetConditionStr())); connection.ExpressionTable.Root = CreateExpressionRows(LogicExpression::Parse(locationAccess.GetConditionStr()));
regionAgeTime.ChildDayAccess = region.childDay; connection.ChildDayAccess = region.childDay;
regionAgeTime.ChildNightAccess = region.childNight; connection.ChildNightAccess = region.childNight;
regionAgeTime.AdultDayAccess = region.adultDay; connection.AdultDayAccess = region.adultDay;
regionAgeTime.AdultNightAccess = region.adultNight; connection.AdultNightAccess = region.adultNight;
if (regionAgeTime.ChildDayAccess) { if (connection.ChildDayAccess) {
logic->IsChild = true; logic->IsChild = true;
logic->AtDay = true; logic->AtDay = true;
const auto& eval = EvaluateExpression(regionAgeTime.ExpressionTable.Root.Expression); const auto& eval = EvaluateExpression(connection.ExpressionTable.Root.Expression);
PopulateExpressionValues(regionAgeTime.ExpressionTable.Root, eval, AgeTime::ChildDay); PopulateExpressionValues(connection.ExpressionTable.Root, eval, AgeTime::ChildDay);
logic->IsChild = false; logic->IsChild = false;
logic->AtDay = false; logic->AtDay = false;
} }
if (regionAgeTime.ChildNightAccess) { if (connection.ChildNightAccess) {
logic->IsChild = true; logic->IsChild = true;
logic->AtNight = true; logic->AtNight = true;
const auto& eval = EvaluateExpression(regionAgeTime.ExpressionTable.Root.Expression); const auto& eval = EvaluateExpression(connection.ExpressionTable.Root.Expression);
PopulateExpressionValues(regionAgeTime.ExpressionTable.Root, eval, AgeTime::ChildNight); PopulateExpressionValues(connection.ExpressionTable.Root, eval, AgeTime::ChildNight);
logic->IsChild = false; logic->IsChild = false;
logic->AtNight = false; logic->AtNight = false;
} }
if (regionAgeTime.AdultDayAccess) { if (connection.AdultDayAccess) {
logic->IsAdult = true; logic->IsAdult = true;
logic->AtDay = true; logic->AtDay = true;
const auto& eval = EvaluateExpression(regionAgeTime.ExpressionTable.Root.Expression); const auto& eval = EvaluateExpression(connection.ExpressionTable.Root.Expression);
PopulateExpressionValues(regionAgeTime.ExpressionTable.Root, eval, AgeTime::AdultDay); PopulateExpressionValues(connection.ExpressionTable.Root, eval, AgeTime::AdultDay);
logic->IsAdult = false; logic->IsAdult = false;
logic->AtDay = false; logic->AtDay = false;
} }
if (regionAgeTime.AdultNightAccess) { if (connection.AdultNightAccess) {
logic->IsAdult = true; logic->IsAdult = true;
logic->AtNight = true; logic->AtNight = true;
const auto& eval = EvaluateExpression(regionAgeTime.ExpressionTable.Root.Expression); const auto& eval = EvaluateExpression(connection.ExpressionTable.Root.Expression);
PopulateExpressionValues(regionAgeTime.ExpressionTable.Root, eval, AgeTime::AdultNight); PopulateExpressionValues(connection.ExpressionTable.Root, eval, AgeTime::AdultNight);
logic->IsAdult = false; logic->IsAdult = false;
logic->AtNight = false; logic->AtNight = false;
} }
auto [combineAll, combineChild, combineAdult] = CalculateCombines(regionAgeTime.ExpressionTable.Root); auto [combineAll, combineChild, combineAdult] = CalculateCombines(connection.ExpressionTable.Root);
regionAgeTime.ExpressionTable.CombineAll = combineAll; connection.ExpressionTable.CombineAll = combineAll;
regionAgeTime.ExpressionTable.CombineChild = combineChild; connection.ExpressionTable.CombineChild = combineChild;
regionAgeTime.ExpressionTable.CombineAdult = combineAdult; connection.ExpressionTable.CombineAdult = combineAdult;
logicTrackerCheck->Regions.emplace_back(std::move(regionAgeTime)); node.Connections.emplace_back(std::move(connection));
} }
} }
} }
nodes.emplace_back(std::move(node));
auto window = Ship::Context::GetInstance()->GetWindow()->GetGui()->GetGuiWindow("Logic Tracker"); auto window = Ship::Context::GetInstance()->GetWindow()->GetGui()->GetGuiWindow("Logic Tracker");
window->Show(); window->Show();
ImGui::SetWindowFocus(window->GetName().c_str()); ImGui::SetWindowFocus(window->GetName().c_str());
expandCheck = true; expandNodeId = node.NodeId;
} }
bool expandRegion = false;
std::unique_ptr<LogicTrackerRegion> logicTrackerRegion;
void LogicTrackerWindow::ShowRandomizerRegion(RandomizerRegion randomizerRegion) { void LogicTrackerWindow::ShowRandomizerRegion(RandomizerRegion randomizerRegion) {
const auto& region = RegionTable(randomizerRegion); const auto& region = RegionTable(randomizerRegion);
logicTrackerRegion = std::make_unique<LogicTrackerRegion>(); LogicTrackerNode node;
logicTrackerRegion->RegionName = region->regionName; node.NodeName = region->regionName;
node.NodeId = nodes.size();
for (const auto& entrance : region->entrances) { for (const auto& entrance : region->entrances) {
const auto& parentRegion = entrance->GetParentRegion(); const auto& parentRegion = entrance->GetParentRegion();
LogicTrackerRegion::Entrance entranceAgeTime; LogicTrackerNode::Connection connection;
entranceAgeTime.ParentName = parentRegion->regionName; connection.ParentName = parentRegion->regionName;
entranceAgeTime.ParentRandomizerRegion = entrance->GetParentRegionKey(); connection.ParentRandomizerRegion = entrance->GetParentRegionKey();
entranceAgeTime.ExpressionTable.Root = connection.ExpressionTable.Root =
CreateExpressionRows(LogicExpression::Parse(entrance->GetConditionStr())); CreateExpressionRows(LogicExpression::Parse(entrance->GetConditionStr()));
entranceAgeTime.ChildDayAccess = parentRegion->childDay; connection.ChildDayAccess = parentRegion->childDay;
entranceAgeTime.ChildNightAccess = parentRegion->childNight; connection.ChildNightAccess = parentRegion->childNight;
entranceAgeTime.AdultDayAccess = parentRegion->adultDay; connection.AdultDayAccess = parentRegion->adultDay;
entranceAgeTime.AdultNightAccess = parentRegion->adultNight; connection.AdultNightAccess = parentRegion->adultNight;
if (entranceAgeTime.ChildDayAccess) { if (connection.ChildDayAccess) {
logic->IsChild = true; logic->IsChild = true;
logic->AtDay = true; logic->AtDay = true;
const auto& eval = EvaluateExpression(entranceAgeTime.ExpressionTable.Root.Expression); const auto& eval = EvaluateExpression(connection.ExpressionTable.Root.Expression);
PopulateExpressionValues(entranceAgeTime.ExpressionTable.Root, eval, AgeTime::ChildDay); PopulateExpressionValues(connection.ExpressionTable.Root, eval, AgeTime::ChildDay);
logic->IsChild = false; logic->IsChild = false;
logic->AtDay = false; logic->AtDay = false;
} }
if (entranceAgeTime.ChildNightAccess) { if (connection.ChildNightAccess) {
logic->IsChild = true; logic->IsChild = true;
logic->AtNight = true; logic->AtNight = true;
const auto& eval = EvaluateExpression(entranceAgeTime.ExpressionTable.Root.Expression); const auto& eval = EvaluateExpression(connection.ExpressionTable.Root.Expression);
PopulateExpressionValues(entranceAgeTime.ExpressionTable.Root, eval, AgeTime::ChildNight); PopulateExpressionValues(connection.ExpressionTable.Root, eval, AgeTime::ChildNight);
logic->IsChild = false; logic->IsChild = false;
logic->AtNight = false; logic->AtNight = false;
} }
if (entranceAgeTime.AdultDayAccess) { if (connection.AdultDayAccess) {
logic->IsAdult = true; logic->IsAdult = true;
logic->AtDay = true; logic->AtDay = true;
const auto& eval = EvaluateExpression(entranceAgeTime.ExpressionTable.Root.Expression); const auto& eval = EvaluateExpression(connection.ExpressionTable.Root.Expression);
PopulateExpressionValues(entranceAgeTime.ExpressionTable.Root, eval, AgeTime::AdultDay); PopulateExpressionValues(connection.ExpressionTable.Root, eval, AgeTime::AdultDay);
logic->IsAdult = false; logic->IsAdult = false;
logic->AtDay = false; logic->AtDay = false;
} }
if (entranceAgeTime.AdultNightAccess) { if (connection.AdultNightAccess) {
logic->IsAdult = true; logic->IsAdult = true;
logic->AtNight = true; logic->AtNight = true;
const auto& eval = EvaluateExpression(entranceAgeTime.ExpressionTable.Root.Expression); const auto& eval = EvaluateExpression(connection.ExpressionTable.Root.Expression);
PopulateExpressionValues(entranceAgeTime.ExpressionTable.Root, eval, AgeTime::AdultNight); PopulateExpressionValues(connection.ExpressionTable.Root, eval, AgeTime::AdultNight);
logic->IsAdult = false; logic->IsAdult = false;
logic->AtNight = false; logic->AtNight = false;
} }
auto [combineAll, combineChild, combineAdult] = CalculateCombines(entranceAgeTime.ExpressionTable.Root); auto [combineAll, combineChild, combineAdult] = CalculateCombines(connection.ExpressionTable.Root);
entranceAgeTime.ExpressionTable.CombineAll = combineAll; connection.ExpressionTable.CombineAll = combineAll;
entranceAgeTime.ExpressionTable.CombineChild = combineChild; connection.ExpressionTable.CombineChild = combineChild;
entranceAgeTime.ExpressionTable.CombineAdult = combineAdult; connection.ExpressionTable.CombineAdult = combineAdult;
logicTrackerRegion->Entrances.emplace_back(std::move(entranceAgeTime)); node.Connections.emplace_back(std::move(connection));
} }
nodes.emplace_back(std::move(node));
auto window = Ship::Context::GetInstance()->GetWindow()->GetGui()->GetGuiWindow("Logic Tracker"); auto window = Ship::Context::GetInstance()->GetWindow()->GetGui()->GetGuiWindow("Logic Tracker");
window->Show(); window->Show();
ImGui::SetWindowFocus(window->GetName().c_str()); ImGui::SetWindowFocus(window->GetName().c_str());
expandRegion = true; expandNodeId = node.NodeId;
} }
static std::string ToString(const std::optional<LogicExpression::ValueVariant>& value) { static std::string ToString(const std::optional<LogicExpression::ValueVariant>& value) {
@ -459,12 +448,9 @@ static void DrawExpressionTable(ExpressionTable& table) {
ImGui::EndTable(); ImGui::EndTable();
} }
static void DrawCheckRegion(LogicTrackerCheck::Region& region) { static void DrawNodeConnection(LogicTrackerNode& node, LogicTrackerNode::Connection& connection) {
ImGui::SeparatorText(("Region: " + region.RegionName).c_str()); ImGui::TextUnformatted("Parent Access:");
if (ImGui::BeginTable(("##" + connection.ParentName).c_str(), 4,
ImGui::TextUnformatted("Region Access:");
if (ImGui::BeginTable(("Region Access: " + region.RegionName).c_str(), 4,
ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg | ImGuiTableFlags_NoHostExtendX)) { ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg | ImGuiTableFlags_NoHostExtendX)) {
ImGui::TableSetupColumn("Child Day", ImGuiTableColumnFlags_WidthFixed); ImGui::TableSetupColumn("Child Day", ImGuiTableColumnFlags_WidthFixed);
ImGui::TableSetupColumn("Child Night", ImGuiTableColumnFlags_WidthFixed); ImGui::TableSetupColumn("Child Night", ImGuiTableColumnFlags_WidthFixed);
@ -473,111 +459,72 @@ static void DrawCheckRegion(LogicTrackerCheck::Region& region) {
ImGui::TableHeadersRow(); ImGui::TableHeadersRow();
ImGui::TableNextRow(); ImGui::TableNextRow();
ImGui::PushFont(OTRGlobals::Instance->fontMono); ImGui::PushFont(OTRGlobals::Instance->fontMono);
ImGui::TableNextColumn();
ImGui::TextUnformatted(region.ChildDayAccess ? "true" : "false");
ImGui::TableNextColumn(); ImGui::TableNextColumn();
ImGui::TextUnformatted(region.ChildNightAccess ? "true" : "false"); ImGui::TextUnformatted(connection.ChildDayAccess ? "true" : "false");
ImGui::TableNextColumn(); ImGui::TableNextColumn();
ImGui::TextUnformatted(region.AdultDayAccess ? "true" : "false"); ImGui::TextUnformatted(connection.ChildNightAccess ? "true" : "false");
ImGui::TableNextColumn(); ImGui::TableNextColumn();
ImGui::TextUnformatted(region.AdultNightAccess ? "true" : "false"); ImGui::TextUnformatted(connection.AdultDayAccess ? "true" : "false");
ImGui::TableNextColumn();
ImGui::TextUnformatted(connection.AdultNightAccess ? "true" : "false");
ImGui::PopFont(); ImGui::PopFont();
ImGui::EndTable(); ImGui::EndTable();
} }
ImGui::SameLine(); if (connection.ParentRandomizerRegion != RR_NONE) {
if (ImGui::Button(("Show Entrance Logic##" + region.RegionName).c_str())) { ImGui::SameLine();
LogicTrackerWindow::ShowRandomizerRegion(region.RandomizerRegion); if (ImGui::Button(("Show Region Logic##" + connection.ParentName).c_str())) {
while (nodes.back().NodeId > node.NodeId) {
nodes.pop_back();
}
LogicTrackerWindow::ShowRandomizerRegion(connection.ParentRandomizerRegion);
}
} }
ImGui::Dummy(ImVec2(0.0f, 10.0f)); ImGui::TextUnformatted("Node Access:");
DrawExpressionTable(connection.ExpressionTable);
ImGui::TextUnformatted("Check Access:");
DrawExpressionTable(region.ExpressionTable);
} }
static void DrawCheck() { static void DrawNode(LogicTrackerNode& node) {
if (expandCheck) { if (expandingNode) {
expandCheck = false; ImGui::SetNextItemOpen(expandNodeId == node.NodeId, ImGuiCond_Always);
ImGui::SetNextItemOpen(true, ImGuiCond_Always);
} }
if (ImGui::CollapsingHeader(("Check: " + (logicTrackerCheck != nullptr ? logicTrackerCheck->CheckName : "")).c_str(), ImGuiTreeNodeFlags_AllowOverlap | ImGuiTreeNodeFlags_SpanFullWidth)) {
if (logicTrackerCheck->Regions.empty()) { if (ImGui::CollapsingHeader(node.NodeName.c_str(),
ImGui::Text("No regions found for this check."); ImGuiTreeNodeFlags_AllowOverlap | ImGuiTreeNodeFlags_SpanFullWidth)) {
return; ImGui::Indent(25.0f);
} for (int i = 0; i < node.Connections.size(); i++) {
for (auto& region : logicTrackerCheck->Regions) { if (ImGui::CollapsingHeader(node.Connections[i].ParentName.c_str(), ImGuiTreeNodeFlags_AllowOverlap |
DrawCheckRegion(region); ImGuiTreeNodeFlags_SpanAvailWidth)) {
ImGui::Dummy(ImVec2(0.0f, 20.0f)); DrawNodeConnection(node, node.Connections[i]);
} }
}
}
static void DrawRegionEntrance(LogicTrackerRegion::Entrance& entrance) {
ImGui::SeparatorText(("Entrance: " + entrance.ParentName).c_str());
ImGui::TextUnformatted("Entrance Access:");
if (ImGui::BeginTable(("Entrance Access: " + entrance.ParentName).c_str(), 4,
ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg | ImGuiTableFlags_NoHostExtendX)) {
ImGui::TableSetupColumn("Child Day", ImGuiTableColumnFlags_WidthFixed);
ImGui::TableSetupColumn("Child Night", ImGuiTableColumnFlags_WidthFixed);
ImGui::TableSetupColumn("Adult Day", ImGuiTableColumnFlags_WidthFixed);
ImGui::TableSetupColumn("Adult Night", ImGuiTableColumnFlags_WidthFixed);
ImGui::TableHeadersRow();
ImGui::TableNextRow();
ImGui::PushFont(OTRGlobals::Instance->fontMono);
ImGui::TableNextColumn();
ImGui::TextUnformatted(entrance.ChildDayAccess ? "true" : "false");
ImGui::TableNextColumn();
ImGui::TextUnformatted(entrance.ChildNightAccess ? "true" : "false");
ImGui::TableNextColumn();
ImGui::TextUnformatted(entrance.AdultDayAccess ? "true" : "false");
ImGui::TableNextColumn();
ImGui::TextUnformatted(entrance.AdultNightAccess ? "true" : "false");
ImGui::PopFont();
ImGui::EndTable();
}
ImGui::SameLine();
if (ImGui::Button(("Show Region Logic##" + entrance.ParentName).c_str())) {
LogicTrackerWindow::ShowRandomizerRegion(entrance.ParentRandomizerRegion);
}
ImGui::Dummy(ImVec2(0.0f, 10.0f));
DrawExpressionTable(entrance.ExpressionTable);
}
static void DrawRegion() {
if (expandRegion) {
expandRegion = false;
ImGui::SetNextItemOpen(true, ImGuiCond_Always);
}
if (ImGui::CollapsingHeader(("Region: " + (logicTrackerRegion != nullptr ? logicTrackerRegion->RegionName : "")).c_str(), ImGuiTreeNodeFlags_AllowOverlap | ImGuiTreeNodeFlags_SpanFullWidth)) {
if (logicTrackerRegion->Entrances.empty()) {
ImGui::Text("No entrances found for this region.");
return;
}
for (auto& entrance : logicTrackerRegion->Entrances) {
DrawRegionEntrance(entrance);
ImGui::Dummy(ImVec2(0.0f, 20.0f));
} }
ImGui::Unindent(25.0f);
} }
} }
void LogicTrackerWindow::DrawElement() { void LogicTrackerWindow::DrawElement() {
DrawCheck(); if (expandNodeId != -1) {
DrawRegion(); expandingNode = true;
}
for (LogicTrackerNode& node : nodes) {
DrawNode(node);
}
if (expandingNode) {
expandNodeId = -1;
expandingNode = false;
}
} }
void LogicTrackerWindow::InitElement() { void LogicTrackerWindow::InitElement() {