Files
srhtnin.github.io/Scripts/Garden/Save.js
T
2026-08-30 15:36:16 +02:00

300 lines
5.1 KiB
JavaScript

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;
}