const { DataApi } = require("@unity-services/cloud-save-1.4");
module.exports = async ({ params, context, logger }) => {
const { projectId } = context;
const totalLevels = Number(params.totalLevels);
if (!Number.isInteger(totalLevels) || totalLevels < 1) {
throw new Error("Parameter 'totalLevels' must be a positive integer.");
}
const cloudSave = new DataApi(context);
const COLLECTION = "level-stats";
const KEY = "level-completion";
const MAX_RETRIES = 5;
const BASE_DELAY = 50;
for (let attempt = 1; attempt <= MAX_RETRIES; attempt++) {
try {
const read = await cloudSave.getPrivateCustomItems(projectId, COLLECTION, [KEY]);
const record = read.data.results[0] ?? { value: {}, metadata: {} };
const statsObj = record.value;
const etag = record.metadata?.etag;
let created = 0;
for (let lvl = 0; lvl <= totalLevels - 1; lvl++) {
if (!statsObj[lvl]) {
statsObj[lvl] = { NumCompletions: 0 };
created++;
}
}
if (created === 0) {
return { Initialized: 0, AlreadyPresent: totalLevels };
}
await cloudSave.setPrivateCustomItemBatch(projectId, COLLECTION, {
data: [{ key: KEY, value: statsObj, writeLock: etag }]
});
return { Initialized: created, AlreadyPresent: totalLevels - created };
} catch (err) {
if (err.response?.status === 412 && attempt < MAX_RETRIES) {
const backoff = BASE_DELAY * 2 ** (attempt - 1) + Math.random() * BASE_DELAY;
logger.warn(`ETag conflict, retry ${attempt}/${MAX_RETRIES} in ${Math.round(backoff)} ms`);
await new Promise(r => setTimeout(r, backoff));
continue;
}
logger.error("InitAllLevelStats failed", { message: err.message });
throw err;
}
}
throw new Error(`Failed after ${MAX_RETRIES} retries`);
};