y
This commit is contained in:
parent
61718e2981
commit
f657b6a4a4
94 changed files with 3970 additions and 1241 deletions
|
|
@ -602,7 +602,8 @@
|
|||
|
||||
function writeWorld(writer, w = []) {
|
||||
writeBitFields(writer, [w[0] || 0, w[1] || 0, w[2] || 0, w[4] || 0], [2, 3, 4, 3]);
|
||||
writer.u(w[3] || 0); // worldTick10
|
||||
writer.u(w[3] || 0); // total elapsed worldTick10
|
||||
writer.u(Math.max(0, Number(w[18] ?? 0) || 0)); // explicit elapsed completed days
|
||||
let mask = 0;
|
||||
if (valuesDiffer(w[5], -9990)) mask |= 1;
|
||||
if (valuesDiffer(w[6], 1)) mask |= 2;
|
||||
|
|
@ -610,7 +611,8 @@
|
|||
if (valuesDiffer(w[9], 0)) mask |= 8;
|
||||
if (valuesDiffer(w[10], 0)) mask |= 16;
|
||||
if (valuesDiffer(w[11], 0)) mask |= 32;
|
||||
writeBitFields(writer, [mask], [6]);
|
||||
if (valuesDiffer(w[19], 0)) mask |= 64;
|
||||
writeBitFields(writer, [mask], [7]);
|
||||
if (mask & 1) writer.s(w[5] || 0); // lastBirthAt10 can be negative
|
||||
if (mask & 2) writer.u(w[6] || 1); // generation
|
||||
if (mask & 4) writer.u(w[7] || 0); // dead count
|
||||
|
|
@ -620,11 +622,13 @@
|
|||
if (mask & 8) writer.u(w[9] || 0); // birthSerial
|
||||
if (mask & 16) writer.u(w[10] || 0); // tarinai population limit
|
||||
if (mask & 32) writer.u(w[11] || 0); // object limit
|
||||
if (mask & 64) writer.u(w[19] || 0); // manual Tarinai additions
|
||||
}
|
||||
function readWorld(reader) {
|
||||
const [field, ground, mood, weather] = readBitFields(reader, [2, 3, 4, 3]);
|
||||
const tick = reader.u();
|
||||
const [mask] = readBitFields(reader, [6]);
|
||||
const elapsedDays = reader.u();
|
||||
const [mask] = readBitFields(reader, [7]);
|
||||
const lastBirthAt = (mask & 1) ? reader.s() : -9990;
|
||||
const generation = (mask & 2) ? reader.u() : 1;
|
||||
const deadCount = (mask & 4) ? reader.u() : 0;
|
||||
|
|
@ -632,7 +636,12 @@
|
|||
const birthSerial = (mask & 8) ? reader.u() : 0;
|
||||
const tarinaiPopulationLimit = (mask & 16) ? reader.u() : 0;
|
||||
const objectLimit = (mask & 32) ? reader.u() : 0;
|
||||
return [field, ground, mood, tick, weather, lastBirthAt, generation, deadCount, seed, birthSerial, tarinaiPopulationLimit, objectLimit];
|
||||
const manualTarinaiAddedCount = (mask & 64) ? reader.u() : 0;
|
||||
const row = [field, ground, mood, tick, weather, lastBirthAt, generation, deadCount, seed, birthSerial, tarinaiPopulationLimit, objectLimit];
|
||||
row[18] = elapsedDays;
|
||||
row[19] = manualTarinaiAddedCount;
|
||||
row[20] = BINARY_SCHEMA_VERSION;
|
||||
return row;
|
||||
}
|
||||
|
||||
const birthHash32 = global.TarinaiCoreHelpers?.birthHash32 || (seed => {
|
||||
|
|
@ -1465,10 +1474,10 @@
|
|||
}
|
||||
|
||||
const ACHIEVEMENT_METADATA_BINARY_VERSION = 1;
|
||||
const ACHIEVEMENT_SPELL_BINARY_VERSION = 5;
|
||||
const ACHIEVEMENT_MASK_BYTES = 8;
|
||||
const ACHIEVEMENT_PROGRESS_BITS = Object.freeze([7, 4, 7, 12, 5, 5, 5, 11, 6, 10, 9, 10, 3, 17]);
|
||||
const ACHIEVEMENT_PROGRESS_MAX = Object.freeze([100, 15, 100, 3333, 30, 20, 20, 2047, 50, 666, 333, 721, 7, 131071]);
|
||||
const ACHIEVEMENT_SPELL_BINARY_VERSION = 8;
|
||||
const ACHIEVEMENT_MASK_BYTES = 10;
|
||||
const ACHIEVEMENT_PROGRESS_BITS = Object.freeze([7, 4, 7, 12, 5, 5, 5, 11, 6, 10, 9, 10, 3, 17, 5, 14, 7]);
|
||||
const ACHIEVEMENT_PROGRESS_MAX = Object.freeze([100, 15, 100, 3333, 30, 20, 20, 2047, 50, 666, 333, 721, 7, 131071, 30, 10000, 100]);
|
||||
|
||||
function finiteNumberOrNull(value) {
|
||||
const n = Number(value);
|
||||
|
|
@ -1493,14 +1502,18 @@
|
|||
function achievementMaskBytesFromSpell(spell = null) {
|
||||
const bytes = new Uint8Array(ACHIEVEMENT_MASK_BYTES);
|
||||
if (!Array.isArray(spell)) return { bytes, baseMinute: 0, deltas: [], progress: [] };
|
||||
if (Number(spell[0]) !== ACHIEVEMENT_SPELL_BINARY_VERSION) throw new Error("unsupported achievement spell version");
|
||||
const version = Number(spell[0]);
|
||||
if (version !== ACHIEVEMENT_SPELL_BINARY_VERSION) throw new Error("unsupported achievement spell version");
|
||||
const low = Math.max(0, Math.min(0xffffffff, Math.floor(Number(spell[1]) || 0)));
|
||||
const high = Math.max(0, Math.min(0xffffffff, Math.floor(Number(spell[2]) || 0)));
|
||||
const extra = Math.max(0, Math.min(0xffff, Math.floor(Number(spell[3]) || 0)));
|
||||
for (let i = 0; i < 4; i++) bytes[i] = Math.floor(low / (2 ** (i * 8))) & 255;
|
||||
for (let i = 0; i < 4; i++) bytes[i + 4] = Math.floor(high / (2 ** (i * 8))) & 255;
|
||||
const baseMinute = toSafeUInt(spell[3]);
|
||||
const deltas = Array.isArray(spell[4]) ? spell[4].map(toSafeUInt) : [];
|
||||
const progress = Array.isArray(spell[5]) ? spell[5] : [];
|
||||
bytes[8] = extra & 255;
|
||||
bytes[9] = (extra >>> 8) & 255;
|
||||
const baseMinute = toSafeUInt(spell[4]);
|
||||
const deltas = Array.isArray(spell[5]) ? spell[5].map(toSafeUInt) : [];
|
||||
const progress = Array.isArray(spell[6]) ? spell[6] : [];
|
||||
let unlockedCount = 0;
|
||||
for (const byte of bytes) {
|
||||
let value = byte;
|
||||
|
|
@ -1515,7 +1528,7 @@
|
|||
let high = 0;
|
||||
for (let i = 0; i < 4; i++) low += (Number(bytes[i]) || 0) * (2 ** (i * 8));
|
||||
for (let i = 0; i < 4; i++) high += (Number(bytes[i + 4]) || 0) * (2 ** (i * 8));
|
||||
return [ACHIEVEMENT_SPELL_BINARY_VERSION, low >>> 0, high >>> 0, toSafeUInt(baseMinute), deltas.map(toSafeUInt), progress];
|
||||
return [ACHIEVEMENT_SPELL_BINARY_VERSION, low >>> 0, high >>> 0, (Number(bytes[8]) || 0) + (Number(bytes[9]) || 0) * 256, toSafeUInt(baseMinute), deltas.map(toSafeUInt), progress];
|
||||
}
|
||||
function writeAchievementProgress(writer, values = [], bits = ACHIEVEMENT_PROGRESS_BITS, maxima = ACHIEVEMENT_PROGRESS_MAX) {
|
||||
const normalized = maxima.map((max, index) => Math.max(0, Math.min(max, toSafeUInt(values?.[index]))));
|
||||
|
|
@ -1559,7 +1572,7 @@
|
|||
const baseMinute = reader.u();
|
||||
const deltas = [];
|
||||
for (let i = 0; i < unlockedCount; i++) deltas.push(reader.u());
|
||||
const progress = readAchievementProgress(reader);
|
||||
const progress = readAchievementProgress(reader, ACHIEVEMENT_PROGRESS_BITS, ACHIEVEMENT_PROGRESS_MAX);
|
||||
return spellFromAchievementMaskBytes(bytes, baseMinute, deltas, progress);
|
||||
}
|
||||
function writeAchievementMetadata(writer, metadata = null, tarinaiCount = 0, itemCount = 0) {
|
||||
|
|
@ -1630,7 +1643,7 @@
|
|||
|
||||
if (Array.isArray(value.s)) writeAchievementSpell(writer, value.s);
|
||||
}
|
||||
function readAchievementMetadata(reader, tarinaiCount = 0, itemCount = 0, schema = BINARY_SCHEMA_VERSION) {
|
||||
function readAchievementMetadata(reader, tarinaiCount = 0, itemCount = 0) {
|
||||
const version = reader.b();
|
||||
if (version !== ACHIEVEMENT_METADATA_BINARY_VERSION) throw new Error("unsupported achievement metadata schema");
|
||||
const [flags] = readBitFields(reader, [1]);
|
||||
|
|
@ -1678,7 +1691,7 @@
|
|||
i[index] = [placed, placedAt];
|
||||
});
|
||||
const metadata = { w, t, i };
|
||||
if (flags & 1) metadata.s = readAchievementSpell(reader, schema);
|
||||
if (flags & 1) metadata.s = readAchievementSpell(reader);
|
||||
return metadata;
|
||||
}
|
||||
|
||||
|
|
@ -1686,9 +1699,12 @@
|
|||
function summaryFromPayload(w = [], tarinaiCount = 0) {
|
||||
const config = typeof CONFIG !== "undefined" ? CONFIG : (global.CONFIG || {});
|
||||
const dayLength = Math.max(1, Number(config.dayLength || 120));
|
||||
const totalTime = (Number(w[3]) || 0) / 10;
|
||||
const day = Math.max(1, Math.floor(totalTime / dayLength) + 1);
|
||||
return [day, tarinaiCount, fieldValue(w[0])];
|
||||
const totalTime = Math.max(0, (Number(w[3]) || 0) / 10);
|
||||
const explicitDays = Number(w[18]);
|
||||
const elapsedDays = Number.isFinite(explicitDays)
|
||||
? Math.max(0, Math.floor(explicitDays))
|
||||
: Math.max(0, Math.floor(totalTime / dayLength));
|
||||
return [elapsedDays + 1, tarinaiCount, fieldValue(w[0]), elapsedDays];
|
||||
}
|
||||
|
||||
function encodeBinarySnapshot(snapshot, stats = null) {
|
||||
|
|
@ -1738,7 +1754,7 @@
|
|||
const items = readItemBlocks(reader);
|
||||
let g = null;
|
||||
try {
|
||||
g = readAchievementMetadata(reader, tCount, items.length, schema);
|
||||
g = readAchievementMetadata(reader, tCount, items.length);
|
||||
} catch (_) {
|
||||
throw new Error("invalid achievement metadata in binary save");
|
||||
}
|
||||
|
|
@ -1826,6 +1842,8 @@
|
|||
global.TarinaiSaveCodec = {
|
||||
encodeSnapshot,
|
||||
decodeSnapshot,
|
||||
encodeBinarySnapshot,
|
||||
decodeBinarySnapshot,
|
||||
getLastEncodeStats,
|
||||
getLastDecodeStats,
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue