Created an initialization function for when the page loads, and/or we need to populate data after recovering from the API server being down. Removed console log error messages for when API server is down. Fixed Summary coloring for scenes with no entrances.

This commit is contained in:
Ada Werefox 2024-04-07 20:13:07 -05:00
parent 171c491497
commit f15f125630
7 changed files with 504 additions and 155 deletions

View File

@ -5,6 +5,10 @@
"entrances": 1312,
"hints": 0,
"codes": {
"empty": 0
"???": {
"Distance": 0,
"Global": false,
"InRange": false
}
}
}

View File

@ -11,20 +11,18 @@ var total_checks = 0;
var total_entrances = 0;
// Global state internal
var server_address = "";
var server_address = "localhost:51111";
var cross_codes = {};
var can_access_api_server = true;
window.onload = () => {
get_updated_server_address();
window.onload = async () => {
await get_updated_server_address();
fetch(`${document.URL}static/tracker/data/holy_cross_codes.json`)
.then((response) => response.json())
.then(
(data) => {
cross_codes = JSON.parse(JSON.stringify(data));
refresh_overview().then((overview) => {
perform_updates(true, true, true, true);
update_overview(overview, true);
});
initialize_elements();
refresh_elements();
},
(error) => {
@ -33,12 +31,324 @@ window.onload = () => {
);
};
async function refresh_elements() {
const overview = await refresh_overview().catch(() =>
console.log("Could not access the API server.")
);
// A function to call when the page loads to ensure that we have the correct data when we connect to the server.
async function initialize_elements() {
// Grab all updates from the backend.
let overview = await refresh_overview();
if (!overview.overview) {
return;
}
const checks = await refresh_checks();
const entrances = await refresh_entrances();
const hints = await refresh_hints();
overview = overview.overview;
if (overview) {
// Initialize overview data.
current_checks = checks.collected;
current_entrances = entrances.found;
total_checks = checks.total;
total_entrances = entrances.total;
update_overview(overview, true);
// Initialize breakdown list
let breakdown_list = document
.getElementById("breakdown-list")
.cloneNode(true);
let breakdown_list_item = breakdown_list.firstElementChild.cloneNode(true);
breakdown_list.innerHTML = "";
breakdown_list.appendChild(breakdown_list_item.cloneNode(true));
breakdown_list_item.classList.remove("hidden");
// Initialize summary list
let summary_list = document.getElementById("summary-list").cloneNode(true);
let summary_list_item =
summary_list.firstElementChild.firstElementChild.cloneNode(true);
summary_list.firstElementChild.innerHTML = "";
summary_list.firstElementChild.appendChild(summary_list_item.cloneNode(true));
summary_list_item.classList.remove("hidden");
// Initialize codes list
let codes_list = document.getElementById("codes-list").cloneNode(true);
let codes_list_item = codes_list.firstElementChild.cloneNode(true);
codes_list.innerHTML = "";
codes_list.appendChild(codes_list_item.cloneNode(true));
codes_list_item.classList.remove("hidden");
// Initialize hints list
let hints_list = document.getElementById("hints-list").cloneNode(true);
let hints_list_item = hints_list.firstElementChild.cloneNode(true);
hints_list.innerHTML = "";
hints_list.appendChild(hints_list_item.cloneNode(true));
hints_list_item.classList.remove("hidden");
// Populate the breakdown list
Object.keys(checks.scenes).forEach((scene) => {
// One-time update the title for each scene.
if (current_scene == scene) {
breakdown_list_item.dataset.current = "true";
breakdown_list_item.classList.remove("hidden", "order-last");
breakdown_list_item.classList.add("order-first");
} else {
breakdown_list_item.dataset.current = "false";
breakdown_list_item.classList.add("hidden", "order-last");
breakdown_list_item.classList.remove("order-first");
}
breakdown_list_item.dataset.breakdownScene = scene;
breakdown_list_item.querySelector(".breakdown-block-title").textContent =
scene;
// Populate checks data
breakdown_list_item.querySelector(
".breakdown-block-checks-title"
).textContent = `Checks: ${checks.scenes[scene].collected}/${checks.scenes[scene].total}/(${checks.scenes[scene].remaining} left)`;
breakdown_list_item.querySelector(
".breakdown-block-checks-title"
).dataset.checksCollected = checks.scenes[scene].collected;
breakdown_list_item.querySelector(
".breakdown-block-checks-title"
).dataset.checksRemaining = checks.scenes[scene].remaining;
breakdown_list_item.querySelector(
".breakdown-block-checks-title"
).dataset.checksTotal = checks.scenes[scene].total;
// Populate entrances data
breakdown_list_item.querySelector(
".breakdown-block-entrances-title"
).textContent = `Entrances: ${entrances.scenes[scene].found}/${entrances.scenes[scene].total}/(${entrances.scenes[scene].remaining} left)`;
breakdown_list_item.querySelector(
".breakdown-block-entrances-title"
).dataset.entrancesFound = entrances.scenes[scene].found;
breakdown_list_item.querySelector(
".breakdown-block-entrances-title"
).dataset.entrancesRemaining = entrances.scenes[scene].remaining;
breakdown_list_item.querySelector(
".breakdown-block-entrances-title"
).dataset.entrancesTotal = entrances.scenes[scene].total;
// Initialize checks list
let new_breakdown_block_checks_list = breakdown_list_item
.querySelector(".breakdown-block-checks-list")
.cloneNode(true);
let new_breakdown_block_checks_list_item =
new_breakdown_block_checks_list.firstElementChild.cloneNode(true);
new_breakdown_block_checks_list.innerHTML = "";
new_breakdown_block_checks_list.appendChild(
new_breakdown_block_checks_list_item.cloneNode(true)
);
new_breakdown_block_checks_list_item.classList.remove("hidden");
// Initialize entrances list
let new_breakdown_block_entrances_list = breakdown_list_item
.querySelector(".breakdown-block-entrances-list")
.cloneNode(true);
let new_breakdown_block_entrances_list_item =
new_breakdown_block_entrances_list.firstElementChild.cloneNode(true);
new_breakdown_block_entrances_list.innerHTML = "";
new_breakdown_block_entrances_list.appendChild(
new_breakdown_block_entrances_list_item.cloneNode(true)
);
new_breakdown_block_entrances_list_item.classList.remove("hidden");
// Initialize mapped list
let new_breakdown_block_mapped_list = breakdown_list_item
.querySelector(".breakdown-block-mapped-list")
.cloneNode(true);
let new_breakdown_block_mapped_list_item =
new_breakdown_block_mapped_list.firstElementChild.cloneNode(true);
new_breakdown_block_mapped_list.innerHTML = "";
new_breakdown_block_mapped_list.appendChild(
new_breakdown_block_mapped_list_item.cloneNode(true)
);
new_breakdown_block_mapped_list_item.classList.remove("hidden");
// Create checks list
Object.keys(checks.scenes[scene].checks).forEach((check) => {
new_breakdown_block_checks_list_item.textContent = `${check}`;
if (!checks.scenes[scene].checks[check].name) {
new_breakdown_block_checks_list.appendChild(
new_breakdown_block_checks_list_item.cloneNode(true)
);
}
});
// Create entrances list and mapped list
Object.keys(entrances.scenes[scene].doors).forEach((entrance) => {
if (!entrances.scenes[scene].doors[entrance].door) {
new_breakdown_block_entrances_list_item.textContent = `${entrance}`;
new_breakdown_block_entrances_list.appendChild(
new_breakdown_block_entrances_list_item.cloneNode(true)
);
} else {
new_breakdown_block_mapped_list_item.dataset.scene =
entrances.scenes[scene].doors[entrance].scene;
new_breakdown_block_mapped_list_item.textContent = `✔️ ${entrance} -> ${entrances.scenes[scene].doors[entrance].door}`;
new_breakdown_block_mapped_list.appendChild(
new_breakdown_block_mapped_list_item.cloneNode(true)
);
}
});
// Replace lists in breakdown
breakdown_list_item
.querySelector(".breakdown-block-checks-list")
.replaceWith(new_breakdown_block_checks_list.cloneNode(true));
breakdown_list_item
.querySelector(".breakdown-block-entrances-list")
.replaceWith(new_breakdown_block_entrances_list.cloneNode(true));
breakdown_list_item
.querySelector(".breakdown-block-mapped-list")
.replaceWith(new_breakdown_block_mapped_list.cloneNode(true));
// Add breakdown to list
breakdown_list.appendChild(breakdown_list_item.cloneNode(true));
});
// Populate the summary list
for (const scene of Object.keys(checks.scenes)) {
// One-time update data for scene
summary_list_item.dataset.scene = scene;
summary_list_item.querySelector(".summary-title").textContent = scene;
// Update checks and entrances
summary_list_item.dataset.checksCollected = checks.scenes[scene].collected;
summary_list_item.dataset.checksRemaining = checks.scenes[scene].remaining;
summary_list_item.dataset.checksTotal = checks.scenes[scene].total;
summary_list_item.querySelector(
".summary-checks"
).textContent = `Checks: ${checks.scenes[scene].collected}/${checks.scenes[scene].total} (${checks.scenes[scene].total})`;
summary_list_item.dataset.entrancesFound = entrances.scenes[scene].found;
summary_list_item.dataset.entrancesRemaining =
entrances.scenes[scene].remaining;
summary_list_item.dataset.entrancesTotal = entrances.scenes[scene].total;
summary_list_item.querySelector(
".summary-entrances"
).textContent = `Entrances: ${entrances.scenes[scene].found}/${entrances.scenes[scene].total} (${entrances.scenes[scene].total})`;
// Hide summaries for scenes with no entrances
if (entrances.scenes[scene].total <= 0) {
summary_list_item.classList.add("hidden");
} else {
summary_list_item.classList.remove("hidden");
}
// Apply color coding and add summary to list
summary_list_item.firstElementChild.replaceWith(
await apply_summary_colors({
element: summary_list_item.firstElementChild.cloneNode(true),
checks_collected: checks.scenes[scene].collected,
checks_total: checks.scenes[scene].total,
entrances_found: entrances.scenes[scene].found,
entrances_total: entrances.scenes[scene].total,
})
);
summary_list.firstElementChild.appendChild(
summary_list_item.cloneNode(true)
);
}
// Populate the codes list
Object.keys(overview.codes)
.sort((i, j) => {
return overview.codes[i].Distance - overview.codes[j].Distance;
})
.forEach((codename, index) => {
// One-time update data for code
codes_list_item.dataset.codename = codename;
codes_list_item.dataset.order = index;
codes_list_item.querySelector(".codes-list-item-title").textContent =
codename;
// Update code
if (overview.codes[codename].Global) {
codes_list_item.querySelector(".codes-list-item-code").textContent =
cross_codes["Global"][codename]
.replace(/U/g, "⬆️")
.replace(/R/g, "➡️")
.replace(/D/g, "⬇️")
.replace(/L/g, "⬅️");
} else {
codes_list_item.querySelector(".codes-list-item-code").textContent =
cross_codes[overview.scene][codename]
.replace(/U/g, "⬆️")
.replace(/R/g, "➡️")
.replace(/D/g, "⬇️")
.replace(/L/g, "⬅️");
}
// Add code to list
codes_list.appendChild(codes_list_item.cloneNode(true));
});
Object.keys(cross_codes.Default).forEach((codename) => {
// One-time update data for default code
codes_list_item.dataset.codename = codename;
codes_list_item.dataset.order = "last";
codes_list_item.querySelector(".codes-list-item-title").textContent =
codename;
// Update code
codes_list_item.querySelector(".codes-list-item-code").textContent =
cross_codes.Default[codename]
.replace(/U/g, "⬆️")
.replace(/R/g, "➡️")
.replace(/D/g, "⬇️")
.replace(/L/g, "⬅️");
// Add code to list
codes_list.appendChild(codes_list_item.cloneNode(true));
});
// Populate the hints list
Object.keys(hints).forEach((hint) => {
// Update hint
hints_list_item.firstElementChild.textContent = hints[hint];
// Add hint to list
hints_list.appendChild(hints_list_item.cloneNode(true));
});
// Replace breakdown list
document
.getElementById("breakdown-list")
.replaceWith(breakdown_list.cloneNode(true));
// Replace summary list
document
.getElementById("summary-list")
.replaceWith(summary_list.cloneNode(true));
// Replace codes list
document.getElementById("codes-list").replaceWith(codes_list.cloneNode(true));
// Replace hints list
document.getElementById("hints-list").replaceWith(hints_list.cloneNode(true));
// update_if_changes(overview);
// update_checks(checks);
// update_entrances(entrances);
// update_hints(hints);
return;
}
async function refresh_elements() {
const response = await refresh_overview();
if (response.overview) {
if (!can_access_api_server) {
console.log("I found the server!");
can_access_api_server = true;
await initialize_elements();
}
update_if_changes(response.overview);
} else {
if (can_access_api_server) {
console.log("Could not access the API server.");
}
can_access_api_server = false;
}
setTimeout(refresh_elements, 500);
}
async function update_if_changes(overview) {
document.getElementById("status-block").classList.add("hidden");
const changed_seed = overview.seed != current_seed;
@ -63,8 +373,6 @@ async function refresh_elements() {
update_overview(overview, changed_scene);
}
await update_codes(overview.codes);
}
setTimeout(refresh_elements, 500);
}
async function perform_updates(
@ -104,9 +412,9 @@ async function get_updated_server_address() {
(data) => {
const parsed_data = JSON.parse(JSON.stringify(data));
server_address = parsed_data["listen_address"];
if (parsed_data["backend_filepath_updated"]) {
get_updated_filepath();
}
// if (parsed_data["backend_filepath_updated"]) {
// get_updated_filepath();
// }
},
(error) => {
console.log(error);
@ -115,9 +423,18 @@ async function get_updated_server_address() {
}
async function refresh_overview() {
try {
const response = await fetch(`${server_address}overview`);
if (response.ok) {
const data = await response.json();
return data;
if (!("error" in data)) {
return { overview: data, error: null };
}
}
return { overview: null, error: null };
} catch (e) {
return { overview: null, error: e };
}
}
async function refresh_hints() {
@ -249,7 +566,6 @@ async function update_codes(codes) {
.getElementById("codes-list")
.querySelector(`[data-codename="${code}"]`).classList
).filter((classname) => classname.startsWith("order-"));
// console.log(classes);
if (classes.length > 0) {
document
.getElementById("codes-list")
@ -344,7 +660,15 @@ async function apply_summary_colors(summary) {
"text-highlight-both-text"
);
}
} else {
summary.element.classList.add(
"from-highlight-undiscovered-light",
"to-highlight-undiscovered-dark",
"text-highlight-undiscovered-text"
);
}
return summary.element;
}
async function update_summary(updates) {
@ -353,7 +677,7 @@ async function update_summary(updates) {
.getElementById("summary-list")
.querySelector(`[data-scene="${updates.scene}"]`)
.querySelector(".summary-checks");
summary_checks.textContent = `Checks: ${updates.checks.collected}/${summary_checks.dataset.checksTotal} (${updates.checks.remaining} left)`;
summary_checks.textContent = `Checks: ${updates.checks.collected}/${summary_checks.dataset.checksTotal} (${updates.checks.remaining})`;
summary_checks.dataset.checksUndiscovered = updates.checks.collected;
apply_summary_colors({
element: document
@ -414,8 +738,11 @@ async function update_checks(checks) {
document.getElementById("breakdown-list").children
);
breakdown_list.forEach((scene) => {
if (scene.querySelector(".breakdown-block-title").textContent) {
// Create variables for element pointers.
let scene_title = scene.querySelector(".breakdown-block-title").textContent;
let scene_title = scene.querySelector(
".breakdown-block-title"
).textContent;
if (scene_title) {
const scene_checks = parseInt(
scene.querySelector(".breakdown-block-checks-title").dataset.checks
@ -435,6 +762,9 @@ async function update_checks(checks) {
).textContent = `Checks: ${checks.scenes[scene_title].collected}/${checks.scenes[scene_title].total} (${checks.scenes[scene_title].remaining})`;
new_breakdown_block_checks_list.innerHTML = "";
new_breakdown_block_checks_list.appendChild(
breakdown_block_checks_list_item.cloneNode(true)
);
breakdown_block_checks_list_item.classList.remove("hidden");
Object.keys(checks.scenes[scene_title].checks).forEach((check) => {
if (checks.scenes[scene_title].checks[check].name == "") {
@ -455,6 +785,7 @@ async function update_checks(checks) {
.replaceWith(new_breakdown_block_checks_list.cloneNode(true));
}
}
}
});
// current_checks = checks.collected;
}
@ -483,16 +814,20 @@ async function update_entrances(entrances) {
document.getElementById("breakdown-list").children
);
breakdown_list.forEach((scene) => {
if (scene.querySelector(".breakdown-block-title").textContent) {
// Create variables for element pointers.
let scene_title = scene.querySelector(".breakdown-block-title").textContent;
let scene_title = scene.querySelector(
".breakdown-block-title"
).textContent;
if (scene_title) {
const scene_entrances = parseInt(
scene.querySelector(".breakdown-block-entrances-title").dataset
.entrances
);
if (scene_entrances != entrances.scenes[scene_title].found) {
scene.querySelector(".breakdown-block-checks-title").dataset.entrances =
scene_entrances;
scene.querySelector(
".breakdown-block-checks-title"
).dataset.entrances = scene_entrances;
update_summary({
scene: scene_title,
entrances: {
@ -505,11 +840,15 @@ async function update_entrances(entrances) {
).textContent = `Entrances: ${entrances.scenes[scene_title].found}/${entrances.scenes[scene_title].total} (${entrances.scenes[scene_title].remaining})`;
new_breakdown_block_entrances_list.innerHTML = "";
new_breakdown_block_entrances_list.appendChild(
breakdown_block_entrances_list_item.cloneNode(true)
);
breakdown_block_entrances_list_item.classList.remove("hidden");
new_breakdown_block_mapped_list.innerHTML = "";
breakdown_block_mapped_list_item.classList.remove("hidden");
Object.keys(entrances.scenes[scene_title].doors).forEach((entrance) => {
Object.keys(entrances.scenes[scene_title].doors).forEach(
(entrance) => {
if (entrances.scenes[scene_title].doors[entrance].door == "") {
breakdown_block_entrances_list_item.textContent = `${entrance}`;
new_breakdown_block_entrances_list.appendChild(
@ -524,7 +863,8 @@ async function update_entrances(entrances) {
breakdown_block_mapped_list_item.cloneNode(true)
);
}
});
}
);
document
.getElementById("breakdown-list")
.querySelector(`[data-breakdown-scene="${scene_title}"]`)
@ -545,6 +885,7 @@ async function update_entrances(entrances) {
.replaceWith(new_breakdown_block_mapped_list.cloneNode(true));
}
}
}
});
}
@ -552,6 +893,8 @@ async function update_hints(hints) {
let hints_list = document.getElementById("hints-list").cloneNode(true);
let hints_list_item = hints_list.firstElementChild.cloneNode(true);
hints_list.innerHTML = "";
hints_list.appendChild(hints_list_item.cloneNode(true));
hints_list_item.classList.remove("hidden");
Object.keys(hints).forEach((hint_index) => {
let hint = hints[hint_index].split(
/(\[[\w\s]+?\]|\"[\w \d\>\<#.\-\']+\"|\<[\w\d#]+\>)/gm
@ -599,9 +942,7 @@ async function update_hints(hints) {
async function update_scene(scene) {
Array.from(document.getElementById("breakdown-list").children).forEach(
(breakdown) => {
const breakdown_title = breakdown.querySelector(
".breakdown-block-title"
).textContent;
const breakdown_title = breakdown.dataset.breakdownScene;
if (breakdown_title == scene) {
document
.getElementById("breakdown-list")
@ -632,7 +973,7 @@ async function update_scene(scene) {
.classList.add("hidden");
document
.getElementById("breakdown-list")
.querySelector(`[data-breakdown-scene="${scene}"]`)
.querySelector(`[data-breakdown-scene="${breakdown_title}"]`)
.classList.add("order-last");
document
.getElementById("breakdown-list")
@ -648,12 +989,12 @@ async function update_scene(scene) {
if (summary_scene == scene) {
document
.getElementById("summary-list")
.firstElementChild.querySelector(`[data-scene="${scene}"]`)
.querySelector(`[data-scene="${scene}"]`)
.classList.add("hidden");
} else if (!(summary_scene == "")) {
document
.getElementById("summary-list")
.firstElementChild.querySelector(`[data-scene="${summary_scene}"]`)
.querySelector(`[data-scene="${summary_scene}"]`)
.classList.remove("hidden");
}
});

View File

@ -79,5 +79,8 @@
"Holy Cross Door": "DRULUR",
"Holy Cross (Blue Lines)": "URULURULURDRULDLURULURULU",
"Tree Holy Cross Chest": "LDRLUD"
},
"???": {
"???": "UDLR"
}
}

View File

@ -12,7 +12,7 @@
</div>
<hr class="border-2 border-bluelight-translucent-dark rounded-xl" />
</div>
<div class="flex flex-col pb-4 space-y-2 overflow-scroll max-h-64 scrollbar scrollbar-thumb-bluelight-dark scrollbar-track-bluelight breakdown-block-checks-list">
<div class="grid grid-flow-row pb-4 space-y-2 overflow-scroll max-h-64 scrollbar scrollbar-thumb-bluelight-dark scrollbar-track-bluelight breakdown-block-checks-list">
<ul class="py-0.5 min-w-max bg-bluelight-translucent rounded-md px-1 text-sm hidden">
</ul>
{% for check_name, check in scene_data.checks.checks.items %}
@ -25,14 +25,14 @@
</div>
</div>
<div class="flex flex-col overflow-hidden basis-1/2">
<div class="flex flex-col my-2 space-y-2">
<div class="grid grid-flow-row my-2 space-y-2">
<div class="text-md breakdown-block-entrances-title"
data-entrances="{{ scene_data.entrances.found }}">
Entrances: {{ scene_data.entrances.found }}/{{ scene_data.entrances.total }} ({{ scene_data.entrances.remaining }} left)
</div>
<hr class="border-2 border-bluelight-translucent-dark rounded-xl" />
</div>
<div class="flex flex-col pb-4 space-y-2 overflow-scroll max-h-64 scrollbar scrollbar-thumb-bluelight-dark scrollbar-track-bluelight breakdown-block-entrances-list">
<div class="grid grid-flow-row pb-4 space-y-2 overflow-scroll max-h-64 scrollbar scrollbar-thumb-bluelight-dark scrollbar-track-bluelight breakdown-block-entrances-list">
<ul class="py-0.5 min-w-max bg-bluelight-translucent rounded-md px-1 text-sm hidden">
</ul>
{% for entrance_origin, entrance_destination in scene_data.entrances.doors.items %}
@ -54,7 +54,6 @@
{% if entrance_destination.door %}
<button type="button"
class="py-0.5 text-start bg-gradient-to-br from-bluelight-translucent-dark to-trans-pride-cyan-translucent rounded-md px-1 text-sm shadow-sm shadow-[#242424]"
id="{{ entrance_origin }}-mapped"
onclick="open_breakdown(this)"
data-scene="{{ entrance_destination.scene }}">
✔️ {{ entrance_origin }} -> {{ entrance_destination.door }}

View File

@ -1,3 +1,3 @@
<div class="h-full min-w-full p-2 rounded-md bg-[rgb(36,36,36)] bg-opacity-35">
<div class="h-full min-w-full p-2 rounded-md bg-[rgb(36,36,36)] bg-opacity-35 {{ extra_classes }}">
<div class="inline align-top text-md {% comment "" %}inline-block{% endcomment %}">{{ value }}</div>
</div>

View File

@ -15,7 +15,7 @@
</span>
<div class="min-w-0 my-auto text-xl align-middle overflow-clip sm:text-3xl">Tunic Transition Tracker</div>
</div>
<div class="flex-row pb-2 space-y-1 text-lg sm:text-2xl max-w-fit font-trunic">
<div class="flex pb-2 text-lg sm:text-2xl max-w-fit font-trunic">
(
<div class="pt-1.5 text-sm sm:text-lg">&nbsp;tuniik' t'raan'ziishuun' t'raakx&nbsp;</div>
)
@ -79,7 +79,7 @@
<hr class="border-2 border-bluelight-translucent-dark rounded-xl" />
<div class="flex-col py-2 space-y-1 *:text-wrap *:break-words"
id="hints-list">
{% include "tracker/hints/index.html" with value="" %}
{% include "tracker/hints/index.html" with value="" extra_classes="hidden" %}
{% for name, value in hints.items %}
{% include "tracker/hints/index.html" %}
{% endfor %}

View File

@ -48,17 +48,19 @@ def index(request):
f"{listen_address}hints", timeout=5, verify=True
).text
tracker_overview_data = loads(request_overview_data)
if "error" in tracker_overview_data.keys():
raise ValueError
tracker_items_data = loads(request_items_data)
tracker_doors_data = loads(request_doors_data)
tracker_hints_data = loads(request_hints_data)
except:
with open("less_fun_overview.json", "r") as t:
with open("empty_overview.json", "r") as t:
tracker_overview_data = loads(t.read())
with open("less_fun_items.json", "r") as t:
with open("empty_items.json", "r") as t:
tracker_items_data = loads(t.read())
with open("less_fun_doors.json", "r") as t:
with open("empty_doors.json", "r") as t:
tracker_doors_data = loads(t.read())
with open("less_fun_hints.json", "r") as t:
with open("empty_hints.json", "r") as t:
tracker_hints_data = loads(t.read())
with open("tracker/static/tracker/data/holy_cross_codes.json", "r") as t:
try: