mirror of
https://git.srhtnin.garden/sarah/srhtnin.github.io.git
synced 2026-10-13 18:38:11 +02:00
Added gardening minigame.
This commit is contained in:
1 parent
3efbb10fa5
commit
660d09272d
9 files changed
+986
No files matched your search
Binary file not shown.
|
After Width: | Height: | Size: 1.0 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 270 B |
Binary file not shown.
|
After Width: | Height: | Size: 238 B |
Binary file not shown.
|
After Width: | Height: | Size: 255 B |
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
$PageTitle = "Garden";
|
||||
|
||||
?>
|
||||
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html lang="en" data-palette="CatppuccinMocha">
|
||||
<?php require __DIR__ . "/Bits/Head.php"; ?>
|
||||
|
||||
<body>
|
||||
<?php require __DIR__ . "/Bits/Navbar.php"; ?>
|
||||
|
||||
<main class="MainContainer">
|
||||
<h1>Garden</h1>
|
||||
|
||||
<div class="GardenStatus">
|
||||
<strong>Dew:</strong>
|
||||
<span id="DewAmount">0</span>
|
||||
</div>
|
||||
|
||||
<div class="GardenLayout">
|
||||
<section>
|
||||
<h2>Plots</h2>
|
||||
|
||||
<div
|
||||
id="GardenGrid"
|
||||
class="GardenGrid"
|
||||
></div>
|
||||
</section>
|
||||
|
||||
<section class="SeedPanel">
|
||||
<h2>Seeds</h2>
|
||||
|
||||
<div
|
||||
id="SeedList"
|
||||
class="SeedList"
|
||||
></div>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<p id="GardenMessage">
|
||||
Select a seed, then choose an empty plot.
|
||||
</p>
|
||||
</main>
|
||||
|
||||
<script src="/Scripts/Garden/Plants.js"></script>
|
||||
<script src="/Scripts/Garden/Mutations.js"></script>
|
||||
<script src="/Scripts/Garden/Save.js"></script>
|
||||
<script src="/Scripts/Garden/Garden.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,558 @@
|
||||
let GameSave;
|
||||
let SelectedSeed = "Rose";
|
||||
|
||||
const GardenUpdateInterval = 1000;
|
||||
|
||||
|
||||
async function StartGame() {
|
||||
GameSave = await LoadGame();
|
||||
|
||||
NormalizeSave();
|
||||
|
||||
RenderGame();
|
||||
|
||||
setInterval(
|
||||
RenderGarden,
|
||||
GardenUpdateInterval
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
function NormalizeSave() {
|
||||
GameSave.Currency ??= {};
|
||||
GameSave.Currency.Dew ??= 0;
|
||||
|
||||
GameSave.Seeds ??= {};
|
||||
GameSave.Seeds.Unlocked ??= [
|
||||
"Rose"
|
||||
];
|
||||
|
||||
GameSave.Garden ??= {
|
||||
Width: 3,
|
||||
Height: 3,
|
||||
Plots: []
|
||||
};
|
||||
|
||||
const RequiredPlots =
|
||||
GameSave.Garden.Width *
|
||||
GameSave.Garden.Height;
|
||||
|
||||
while (
|
||||
GameSave.Garden.Plots.length <
|
||||
RequiredPlots
|
||||
) {
|
||||
GameSave.Garden.Plots.push(null);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function RenderGame() {
|
||||
RenderCurrency();
|
||||
RenderSeeds();
|
||||
RenderGarden();
|
||||
}
|
||||
|
||||
|
||||
function RenderCurrency() {
|
||||
const DewAmount =
|
||||
document.getElementById(
|
||||
"DewAmount"
|
||||
);
|
||||
|
||||
DewAmount.textContent =
|
||||
GameSave.Currency.Dew;
|
||||
}
|
||||
|
||||
|
||||
function RenderSeeds() {
|
||||
const SeedList =
|
||||
document.getElementById(
|
||||
"SeedList"
|
||||
);
|
||||
|
||||
SeedList.replaceChildren();
|
||||
|
||||
for (
|
||||
const PlantId
|
||||
of GameSave.Seeds.Unlocked
|
||||
) {
|
||||
const Plant =
|
||||
Plants[PlantId];
|
||||
|
||||
if (Plant === undefined) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const Button =
|
||||
document.createElement(
|
||||
"button"
|
||||
);
|
||||
|
||||
Button.className =
|
||||
"SeedButton";
|
||||
|
||||
Button.type = "button";
|
||||
|
||||
Button.textContent =
|
||||
Plant.Name;
|
||||
|
||||
if (
|
||||
PlantId ===
|
||||
SelectedSeed
|
||||
) {
|
||||
Button.setAttribute(
|
||||
"aria-current",
|
||||
"true"
|
||||
);
|
||||
}
|
||||
|
||||
Button.addEventListener(
|
||||
"click",
|
||||
() => {
|
||||
SelectedSeed =
|
||||
PlantId;
|
||||
|
||||
RenderSeeds();
|
||||
|
||||
SetGardenMessage(
|
||||
"Selected " +
|
||||
Plant.Name +
|
||||
"."
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
SeedList.appendChild(
|
||||
Button
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function RenderGarden() {
|
||||
const GardenGrid =
|
||||
document.getElementById(
|
||||
"GardenGrid"
|
||||
);
|
||||
|
||||
GardenGrid.style.setProperty(
|
||||
"--GardenWidth",
|
||||
GameSave.Garden.Width
|
||||
);
|
||||
|
||||
GardenGrid.replaceChildren();
|
||||
|
||||
GameSave.Garden.Plots.forEach(
|
||||
(Plot, PlotIndex) => {
|
||||
const PlotElement =
|
||||
CreatePlotElement(
|
||||
Plot,
|
||||
PlotIndex
|
||||
);
|
||||
|
||||
GardenGrid.appendChild(
|
||||
PlotElement
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
function CreatePlotElement(
|
||||
Plot,
|
||||
PlotIndex
|
||||
) {
|
||||
const Button =
|
||||
document.createElement(
|
||||
"button"
|
||||
);
|
||||
|
||||
Button.className =
|
||||
"GardenPlot";
|
||||
|
||||
Button.type = "button";
|
||||
|
||||
if (Plot === null) {
|
||||
Button.classList.add(
|
||||
"GardenPlotEmpty"
|
||||
);
|
||||
|
||||
Button.title =
|
||||
"Empty plot";
|
||||
|
||||
Button.addEventListener(
|
||||
"click",
|
||||
() => {
|
||||
PlantSeed(
|
||||
PlotIndex
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
return Button;
|
||||
}
|
||||
|
||||
|
||||
const Plant =
|
||||
Plants[Plot.Plant];
|
||||
|
||||
if (Plant === undefined) {
|
||||
Button.textContent = "?";
|
||||
|
||||
return Button;
|
||||
}
|
||||
|
||||
|
||||
const Stage =
|
||||
GetPlantStage(
|
||||
Plot,
|
||||
Plant
|
||||
);
|
||||
|
||||
const Image =
|
||||
document.createElement(
|
||||
"img"
|
||||
);
|
||||
|
||||
Image.className =
|
||||
"GardenPlant";
|
||||
|
||||
Image.alt =
|
||||
Plant.Name +
|
||||
" - " +
|
||||
Stage;
|
||||
|
||||
SetPlantImage(
|
||||
Image,
|
||||
Plot,
|
||||
Plant,
|
||||
Stage
|
||||
);
|
||||
|
||||
Button.appendChild(
|
||||
Image
|
||||
);
|
||||
|
||||
|
||||
if (Stage === "Mature") {
|
||||
Button.classList.add(
|
||||
"GardenPlotMature"
|
||||
);
|
||||
|
||||
Button.title =
|
||||
"Harvest " +
|
||||
Plant.Name;
|
||||
|
||||
Button.addEventListener(
|
||||
"click",
|
||||
() => {
|
||||
HarvestPlant(
|
||||
PlotIndex
|
||||
);
|
||||
}
|
||||
);
|
||||
} else {
|
||||
const Progress =
|
||||
GetPlantGrowthProgress(
|
||||
Plot,
|
||||
Plant
|
||||
);
|
||||
|
||||
Button.title =
|
||||
Plant.Name +
|
||||
" - " +
|
||||
Math.floor(
|
||||
Progress * 100
|
||||
) +
|
||||
"% grown";
|
||||
}
|
||||
|
||||
return Button;
|
||||
}
|
||||
|
||||
|
||||
async function PlantSeed(
|
||||
PlotIndex
|
||||
) {
|
||||
if (
|
||||
GameSave.Garden.Plots[
|
||||
PlotIndex
|
||||
] !== null
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
!GameSave.Seeds.Unlocked
|
||||
.includes(
|
||||
SelectedSeed
|
||||
)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
GameSave.Garden.Plots[
|
||||
PlotIndex
|
||||
] = {
|
||||
Plant: SelectedSeed,
|
||||
|
||||
AddedTags: [],
|
||||
|
||||
VisualVariant: null,
|
||||
|
||||
PlantedAt: Date.now()
|
||||
};
|
||||
|
||||
SetGardenMessage(
|
||||
"Planted " +
|
||||
Plants[SelectedSeed].Name +
|
||||
"."
|
||||
);
|
||||
|
||||
RenderGarden();
|
||||
|
||||
await SaveGame(
|
||||
GameSave
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
async function HarvestPlant(
|
||||
PlotIndex
|
||||
) {
|
||||
const Plot =
|
||||
GameSave.Garden.Plots[
|
||||
PlotIndex
|
||||
];
|
||||
|
||||
if (Plot === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
const Plant =
|
||||
Plants[Plot.Plant];
|
||||
|
||||
if (
|
||||
GetPlantStage(
|
||||
Plot,
|
||||
Plant
|
||||
) !== "Mature"
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
GiveReward(
|
||||
Plant.Reward
|
||||
);
|
||||
|
||||
GameSave.Garden.Plots[
|
||||
PlotIndex
|
||||
] = null;
|
||||
|
||||
SetGardenMessage(
|
||||
"Harvested " +
|
||||
Plant.Name +
|
||||
" for " +
|
||||
Plant.Reward.Amount +
|
||||
" " +
|
||||
Plant.Reward.Currency +
|
||||
"."
|
||||
);
|
||||
|
||||
RenderGame();
|
||||
|
||||
await SaveGame(
|
||||
GameSave
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
function GiveReward(
|
||||
Reward
|
||||
) {
|
||||
GameSave.Currency[
|
||||
Reward.Currency
|
||||
] ??= 0;
|
||||
|
||||
GameSave.Currency[
|
||||
Reward.Currency
|
||||
] += Reward.Amount;
|
||||
}
|
||||
|
||||
|
||||
function GetPlantGrowthProgress(
|
||||
Plot,
|
||||
Plant
|
||||
) {
|
||||
if (
|
||||
Plant.GrowthTime <= 0
|
||||
) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
const Age =
|
||||
Date.now() -
|
||||
Plot.PlantedAt;
|
||||
|
||||
return Math.min(
|
||||
Age /
|
||||
Plant.GrowthTime,
|
||||
1
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
function GetPlantStage(
|
||||
Plot,
|
||||
Plant
|
||||
) {
|
||||
const Progress =
|
||||
GetPlantGrowthProgress(
|
||||
Plot,
|
||||
Plant
|
||||
);
|
||||
|
||||
if (Progress < 1 / 3) {
|
||||
return "Seed";
|
||||
}
|
||||
|
||||
if (Progress < 2 / 3) {
|
||||
return "Sprout";
|
||||
}
|
||||
|
||||
return "Mature";
|
||||
}
|
||||
|
||||
|
||||
function GetPlantTags(
|
||||
Plot,
|
||||
Plant
|
||||
) {
|
||||
return [
|
||||
...Plant.Tags,
|
||||
...(Plot.AddedTags ?? [])
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
function GetPlantVariant(
|
||||
Plot,
|
||||
Plant
|
||||
) {
|
||||
if (
|
||||
Plot.VisualVariant !==
|
||||
null
|
||||
) {
|
||||
return Plot.VisualVariant;
|
||||
}
|
||||
|
||||
const Tags =
|
||||
GetPlantTags(
|
||||
Plot,
|
||||
Plant
|
||||
);
|
||||
|
||||
const Variants = [
|
||||
...Plant.Variants
|
||||
].sort(
|
||||
(A, B) =>
|
||||
B.Priority -
|
||||
A.Priority
|
||||
);
|
||||
|
||||
for (
|
||||
const Variant
|
||||
of Variants
|
||||
) {
|
||||
const Matches =
|
||||
Variant.Tags.every(
|
||||
Tag =>
|
||||
Tags.includes(
|
||||
Tag
|
||||
)
|
||||
);
|
||||
|
||||
if (Matches) {
|
||||
return Variant.Name;
|
||||
}
|
||||
}
|
||||
|
||||
return "Default";
|
||||
}
|
||||
|
||||
|
||||
function SetPlantImage(
|
||||
Image,
|
||||
Plot,
|
||||
Plant,
|
||||
Stage
|
||||
) {
|
||||
const Variant =
|
||||
GetPlantVariant(
|
||||
Plot,
|
||||
Plant
|
||||
);
|
||||
|
||||
const BasePath =
|
||||
"/Assets/Img/Garden/Plants/" +
|
||||
Plot.Plant +
|
||||
"/" +
|
||||
Variant +
|
||||
"/";
|
||||
|
||||
|
||||
/*
|
||||
* Try the requested stage first.
|
||||
*
|
||||
* If that image doesn't exist,
|
||||
* Mature.png becomes the fallback.
|
||||
*/
|
||||
|
||||
const Candidates = [
|
||||
BasePath + Stage + ".png",
|
||||
BasePath + "Mature.png"
|
||||
];
|
||||
|
||||
let CandidateIndex = 0;
|
||||
|
||||
Image.src =
|
||||
Candidates[
|
||||
CandidateIndex
|
||||
];
|
||||
|
||||
Image.addEventListener(
|
||||
"error",
|
||||
() => {
|
||||
CandidateIndex++;
|
||||
|
||||
if (
|
||||
CandidateIndex <
|
||||
Candidates.length
|
||||
) {
|
||||
Image.src =
|
||||
Candidates[
|
||||
CandidateIndex
|
||||
];
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
Image.remove();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
function SetGardenMessage(
|
||||
Message
|
||||
) {
|
||||
document.getElementById(
|
||||
"GardenMessage"
|
||||
).textContent = Message;
|
||||
}
|
||||
|
||||
|
||||
document.addEventListener(
|
||||
"DOMContentLoaded",
|
||||
StartGame
|
||||
);
|
||||
@@ -0,0 +1,40 @@
|
||||
const MutationSets = {
|
||||
DarkRose: {
|
||||
Name: "Dark Rose",
|
||||
|
||||
Chance: 0.1,
|
||||
Cooldown: 120000,
|
||||
|
||||
Pattern: [
|
||||
[
|
||||
{
|
||||
Tags: ["Rose"],
|
||||
Capture: "ParentA"
|
||||
},
|
||||
"Empty"
|
||||
],
|
||||
|
||||
[
|
||||
"Empty",
|
||||
{
|
||||
Tags: ["Rose"],
|
||||
Capture: "ParentB"
|
||||
}
|
||||
]
|
||||
],
|
||||
|
||||
Success: [
|
||||
[
|
||||
"Empty",
|
||||
"DarkRose"
|
||||
],
|
||||
|
||||
[
|
||||
"DarkRose",
|
||||
"Empty"
|
||||
]
|
||||
],
|
||||
|
||||
Failure: "Keep"
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,36 @@
|
||||
const Plants = {
|
||||
Rose: {
|
||||
Name: "Rose",
|
||||
|
||||
Tags: [
|
||||
"Rose",
|
||||
"Flower",
|
||||
"Red"
|
||||
],
|
||||
|
||||
GrowthTime: 60000,
|
||||
|
||||
Variants: [
|
||||
{
|
||||
Name: "Red",
|
||||
Tags: [
|
||||
"Red"
|
||||
],
|
||||
Priority: 10
|
||||
},
|
||||
|
||||
{
|
||||
Name: "Default",
|
||||
Tags: [],
|
||||
Priority: 0
|
||||
}
|
||||
],
|
||||
|
||||
Effects: [],
|
||||
|
||||
Reward: {
|
||||
Currency: "Dew",
|
||||
Amount: 5
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,299 @@
|
||||
const SaveKeyName = "SarahtoninGardenSaveKey";
|
||||
const LocalSaveName = "SarahtoninGarden";
|
||||
|
||||
const ApiUrl = "https://api.srhtnin.garden";
|
||||
|
||||
|
||||
function CreateNewSave() {
|
||||
return {
|
||||
Version: 1,
|
||||
Revision: 0,
|
||||
LastSavedAt: Date.now(),
|
||||
|
||||
Currency: {
|
||||
Dew: 0
|
||||
},
|
||||
|
||||
Seeds: {
|
||||
Unlocked: [
|
||||
"Rose"
|
||||
]
|
||||
},
|
||||
|
||||
Upgrades: {
|
||||
PlotSize: 0
|
||||
},
|
||||
|
||||
Garden: {
|
||||
Width: 3,
|
||||
Height: 3,
|
||||
Plots: Array(9).fill(null)
|
||||
},
|
||||
|
||||
Discoveries: {
|
||||
Plants: [
|
||||
"Rose"
|
||||
],
|
||||
|
||||
Mutations: []
|
||||
},
|
||||
|
||||
MutationCooldowns: {}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
function GetSaveKey() {
|
||||
let SaveKey = localStorage.getItem(
|
||||
SaveKeyName
|
||||
);
|
||||
|
||||
if (SaveKey !== null) {
|
||||
return SaveKey;
|
||||
}
|
||||
|
||||
const Bytes = new Uint8Array(32);
|
||||
|
||||
crypto.getRandomValues(Bytes);
|
||||
|
||||
SaveKey = Array.from(
|
||||
Bytes,
|
||||
Byte => Byte
|
||||
.toString(16)
|
||||
.padStart(2, "0")
|
||||
).join("");
|
||||
|
||||
localStorage.setItem(
|
||||
SaveKeyName,
|
||||
SaveKey
|
||||
);
|
||||
|
||||
return SaveKey;
|
||||
}
|
||||
|
||||
|
||||
function WriteLocalSave(SaveData) {
|
||||
localStorage.setItem(
|
||||
LocalSaveName,
|
||||
JSON.stringify(SaveData)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
function ReadLocalSave() {
|
||||
const RawSave = localStorage.getItem(
|
||||
LocalSaveName
|
||||
);
|
||||
|
||||
if (RawSave === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
return JSON.parse(RawSave);
|
||||
} catch (Error) {
|
||||
console.error(
|
||||
"Couldn't read local save:",
|
||||
Error
|
||||
);
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
async function WriteRemoteSave(SaveData) {
|
||||
const Response = await fetch(
|
||||
ApiUrl + "/Save.php",
|
||||
{
|
||||
method: "POST",
|
||||
|
||||
headers: {
|
||||
"Content-Type": "application/json"
|
||||
},
|
||||
|
||||
body: JSON.stringify({
|
||||
SaveKey: GetSaveKey(),
|
||||
SaveData: SaveData
|
||||
})
|
||||
}
|
||||
);
|
||||
|
||||
if (!Response.ok) {
|
||||
throw new Error(
|
||||
"Save API returned HTTP " +
|
||||
Response.status
|
||||
);
|
||||
}
|
||||
|
||||
const Result = await Response.json();
|
||||
|
||||
if (!Result.Success) {
|
||||
throw new Error(
|
||||
Result.Error ??
|
||||
"Remote save failed."
|
||||
);
|
||||
}
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
|
||||
async function ReadRemoteSave() {
|
||||
const Response = await fetch(
|
||||
ApiUrl + "/Load.php",
|
||||
{
|
||||
method: "POST",
|
||||
|
||||
headers: {
|
||||
"Content-Type": "application/json"
|
||||
},
|
||||
|
||||
body: JSON.stringify({
|
||||
SaveKey: GetSaveKey()
|
||||
})
|
||||
}
|
||||
);
|
||||
|
||||
if (!Response.ok) {
|
||||
throw new Error(
|
||||
"Load API returned HTTP " +
|
||||
Response.status
|
||||
);
|
||||
}
|
||||
|
||||
const Result = await Response.json();
|
||||
|
||||
if (!Result.Success) {
|
||||
throw new Error(
|
||||
Result.Error ??
|
||||
"Remote load failed."
|
||||
);
|
||||
}
|
||||
|
||||
if (!Result.Exists) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return Result.SaveData;
|
||||
}
|
||||
|
||||
|
||||
async function SaveGame(SaveData) {
|
||||
SaveData.Revision++;
|
||||
SaveData.LastSavedAt = Date.now();
|
||||
|
||||
WriteLocalSave(SaveData);
|
||||
|
||||
try {
|
||||
await WriteRemoteSave(SaveData);
|
||||
} catch (Error) {
|
||||
console.error(
|
||||
"Couldn't synchronize garden save:",
|
||||
Error
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
async function LoadGame() {
|
||||
const LocalSave = ReadLocalSave();
|
||||
|
||||
let RemoteSave = null;
|
||||
|
||||
try {
|
||||
RemoteSave = await ReadRemoteSave();
|
||||
} catch (Error) {
|
||||
console.error(
|
||||
"Couldn't retrieve remote save:",
|
||||
Error
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
if (
|
||||
LocalSave === null &&
|
||||
RemoteSave === null
|
||||
) {
|
||||
const NewSave = CreateNewSave();
|
||||
|
||||
WriteLocalSave(NewSave);
|
||||
|
||||
try {
|
||||
await WriteRemoteSave(NewSave);
|
||||
} catch (Error) {
|
||||
console.error(
|
||||
"Couldn't create remote save:",
|
||||
Error
|
||||
);
|
||||
}
|
||||
|
||||
return NewSave;
|
||||
}
|
||||
|
||||
|
||||
if (
|
||||
LocalSave !== null &&
|
||||
RemoteSave === null
|
||||
) {
|
||||
try {
|
||||
await WriteRemoteSave(LocalSave);
|
||||
} catch (Error) {
|
||||
console.error(
|
||||
"Couldn't upload local save:",
|
||||
Error
|
||||
);
|
||||
}
|
||||
|
||||
return LocalSave;
|
||||
}
|
||||
|
||||
|
||||
if (
|
||||
LocalSave === null &&
|
||||
RemoteSave !== null
|
||||
) {
|
||||
WriteLocalSave(RemoteSave);
|
||||
|
||||
return RemoteSave;
|
||||
}
|
||||
|
||||
|
||||
if (
|
||||
LocalSave.Revision >
|
||||
RemoteSave.Revision
|
||||
) {
|
||||
try {
|
||||
await WriteRemoteSave(LocalSave);
|
||||
} catch (Error) {
|
||||
console.error(
|
||||
"Couldn't update remote save:",
|
||||
Error
|
||||
);
|
||||
}
|
||||
|
||||
return LocalSave;
|
||||
}
|
||||
|
||||
|
||||
if (
|
||||
RemoteSave.Revision >
|
||||
LocalSave.Revision
|
||||
) {
|
||||
WriteLocalSave(RemoteSave);
|
||||
|
||||
return RemoteSave;
|
||||
}
|
||||
|
||||
|
||||
if (
|
||||
RemoteSave.LastSavedAt >
|
||||
LocalSave.LastSavedAt
|
||||
) {
|
||||
WriteLocalSave(RemoteSave);
|
||||
|
||||
return RemoteSave;
|
||||
}
|
||||
|
||||
return LocalSave;
|
||||
}
|
||||
Reference in new issue
Block a user