asdfg
This commit is contained in:
parent
f6d7412744
commit
091afc2b5c
77 changed files with 4405 additions and 8223 deletions
158
js/save_codec.js
158
js/save_codec.js
|
|
@ -24,6 +24,7 @@
|
|||
"normalItems",
|
||||
"physicsItems",
|
||||
"achievementMetadata",
|
||||
"extendedState",
|
||||
]);
|
||||
let lastEncodeStats = null;
|
||||
let lastDecodeStats = null;
|
||||
|
|
@ -477,12 +478,6 @@
|
|||
return readBitFields(reader, Array.from({ length: count }, () => bits)).map(v => v * Math.max(1, step));
|
||||
}
|
||||
|
||||
function writeFixedPacked(writer, arr = [], count = 0, bits = 8, step = 1) {
|
||||
writeQuantizedBitFields(writer, arr, count, bits, step);
|
||||
}
|
||||
function readFixedPacked(reader, count = 0, bits = 8, step = 1) {
|
||||
return readQuantizedBitFields(reader, count, bits, step);
|
||||
}
|
||||
function writeFixedDiffPacked(writer, base = [], current = [], count = 0, bits = 8) {
|
||||
let mask = 0;
|
||||
const values = [];
|
||||
|
|
@ -526,14 +521,14 @@
|
|||
return false;
|
||||
}
|
||||
function writeTimers(writer, timers = []) {
|
||||
const defaults = [0, 0, 0, 0, 0, 0, 0, 0, 100];
|
||||
const defaults = [0, 0, 0, 0, 0, 0, 0, 0, 100, 0];
|
||||
let mask = 0;
|
||||
for (let i = 0; i < defaults.length; i++) if (valuesDiffer(timers?.[i], defaults[i])) mask |= (1 << i);
|
||||
writeBitFields(writer, [mask], [defaults.length]);
|
||||
for (let i = 0; i < defaults.length; i++) if (mask & (1 << i)) writer.s(timers[i] || 0);
|
||||
}
|
||||
function readTimers(reader) {
|
||||
const defaults = [0, 0, 0, 0, 0, 0, 0, 0, 100];
|
||||
const defaults = [0, 0, 0, 0, 0, 0, 0, 0, 100, 0];
|
||||
const out = defaults.slice();
|
||||
const [mask] = readBitFields(reader, [defaults.length]);
|
||||
for (let i = 0; i < defaults.length; i++) if (mask & (1 << i)) out[i] = reader.s();
|
||||
|
|
@ -696,19 +691,6 @@
|
|||
Math.round((Number(genetics.temperatureOffset) || 0) * 10),
|
||||
];
|
||||
}
|
||||
function writeSignedDiffList(writer, base = [], current = [], count = 0) {
|
||||
let mask = 0;
|
||||
for (let i = 0; i < count; i++) if (valuesDiffer(current?.[i], base?.[i])) mask |= (1 << i);
|
||||
writeBitFields(writer, [mask], [count]);
|
||||
for (let i = 0; i < count; i++) if (mask & (1 << i)) writer.s((current?.[i] || 0) - (base?.[i] || 0));
|
||||
}
|
||||
function readSignedDiffList(reader, base = [], count = 0) {
|
||||
const [mask] = readBitFields(reader, [count]);
|
||||
const out = Array.from({ length: count }, (_, i) => base?.[i] || 0);
|
||||
for (let i = 0; i < count; i++) if (mask & (1 << i)) out[i] = (base?.[i] || 0) + reader.s();
|
||||
return out;
|
||||
}
|
||||
|
||||
class CompactBitWriter {
|
||||
constructor() { this.bytes = []; this.buffer = 0; this.bits = 0; }
|
||||
write(value = 0, width = 0) {
|
||||
|
|
@ -765,7 +747,7 @@
|
|||
const flags = row[0] || 0;
|
||||
const birth = birthSeedFromDescriptor(row[1], worldSeed, rowIndex + 1);
|
||||
const defaultPersonality = seedPersonalityArray(birth.seed, flags);
|
||||
const defaultTimers = [0, 0, 0, 0, 0, 0, 0, 0, 100];
|
||||
const defaultTimers = [0, 0, 0, 0, 0, 0, 0, 0, 100, 0];
|
||||
const genetics = Array.isArray(row[18]) ? row[18] : [];
|
||||
const fightStats = Array.isArray(row[19]) ? row[19] : [];
|
||||
let bodyMask = 0;
|
||||
|
|
@ -776,7 +758,7 @@
|
|||
if (arrayHasValues(row[14], [0, 0, 0])) bodyMask |= 16;
|
||||
const pinIdx = row[15] ?? -1;
|
||||
const nestIdx = row[16] ?? -1;
|
||||
const stateId = row[17]?.[0] ? 1 : 0;
|
||||
const stateId = Math.max(0, Math.min(15, Number(row[17]?.[0]) || 0));
|
||||
const stateTarget = row[17]?.[1] ?? -1;
|
||||
const geneticsBase = seedGeneticsArray(birth.seed, flags);
|
||||
let linkMask = 0;
|
||||
|
|
@ -786,7 +768,7 @@
|
|||
flags, birth, bodyMask, linkMask, pinIdx, nestIdx, stateId, stateTarget, genetics, fightStats,
|
||||
geneticsBase, geneticsMask: diffMask(geneticsBase, genetics, 5), fightMask: diffMask([0, 0, 0], fightStats, 3),
|
||||
hunger: Math.max(0, Math.min(100, Math.round(Number(row[6]) || 0))),
|
||||
energy: Math.max(0, Math.min(100, Math.round(Number(row[7]) || 0))),
|
||||
energy: Math.max(0, Math.min(240, Math.round(Number(row[7]) || 0))),
|
||||
sleepPressure: Math.max(0, Math.min(100, Math.round(Number(row[8]) || 0))),
|
||||
};
|
||||
}
|
||||
|
|
@ -794,11 +776,11 @@
|
|||
const TARINAI_COLUMN_LAYOUT = Object.freeze([
|
||||
["flags", 10],
|
||||
["hunger", 7],
|
||||
["energy", 7],
|
||||
["energy", 8],
|
||||
["sleepPressure", 7],
|
||||
["bodyMask", 5],
|
||||
["linkMask", 2],
|
||||
["stateId", 1],
|
||||
["stateId", 4],
|
||||
["geneticsMask", 5],
|
||||
["fightMask", 3],
|
||||
]);
|
||||
|
|
@ -899,7 +881,7 @@
|
|||
const current = (bodyMask & 1) ? readFixedDiffPacked(reader, defaultPersonality, 4, 8) : defaultPersonality;
|
||||
const parents = (bodyMask & 2) ? readIndexList(reader) : [];
|
||||
const relationships = (bodyMask & 4) ? readRelationships(reader) : [];
|
||||
const timers = (bodyMask & 8) ? readTimers(reader) : [0, 0, 0, 0, 0, 0, 0, 0, 100];
|
||||
const timers = (bodyMask & 8) ? readTimers(reader) : [0, 0, 0, 0, 0, 0, 0, 0, 100, 0];
|
||||
const modes = (bodyMask & 16) ? readModes(reader) : [0, 0, 0];
|
||||
const pinIdx = (linkMask & 1) ? reader.u() : -1;
|
||||
const nestIdx = (linkMask & 2) ? reader.u() : -1;
|
||||
|
|
@ -1473,13 +1455,16 @@
|
|||
return items;
|
||||
}
|
||||
|
||||
const ACHIEVEMENT_METADATA_BINARY_VERSION = 1;
|
||||
const ACHIEVEMENT_SPELL_BINARY_VERSION = 8;
|
||||
const ACHIEVEMENT_METADATA_BINARY_VERSION = 3;
|
||||
const ACHIEVEMENT_SPELL_BINARY_VERSION = 11;
|
||||
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]);
|
||||
const ACHIEVEMENT_PROGRESS_BITS_V9 = Object.freeze([7, 4, 7, 12, 5, 5, 5, 11, 6, 10, 9, 10, 3, 17, 5, 14, 7]);
|
||||
const ACHIEVEMENT_PROGRESS_MAX_V9 = Object.freeze([100, 15, 100, 3333, 30, 20, 20, 2047, 50, 666, 333, 721, 7, 131071, 30, 10000, 100]);
|
||||
const ACHIEVEMENT_PROGRESS_BITS = Object.freeze([...ACHIEVEMENT_PROGRESS_BITS_V9, 4, 6, 8]);
|
||||
const ACHIEVEMENT_PROGRESS_MAX = Object.freeze([...ACHIEVEMENT_PROGRESS_MAX_V9, 10, 33, 200]);
|
||||
|
||||
function finiteNumberOrNull(value) {
|
||||
if (value === null || value === undefined) return null;
|
||||
const n = Number(value);
|
||||
return Number.isFinite(n) ? n : null;
|
||||
}
|
||||
|
|
@ -1501,9 +1486,9 @@
|
|||
}
|
||||
function achievementMaskBytesFromSpell(spell = null) {
|
||||
const bytes = new Uint8Array(ACHIEVEMENT_MASK_BYTES);
|
||||
if (!Array.isArray(spell)) return { bytes, baseMinute: 0, deltas: [], progress: [] };
|
||||
if (!Array.isArray(spell)) return { bytes, baseMinute: 0, deltas: [], progress: [], mysteryDrugIds: [] };
|
||||
const version = Number(spell[0]);
|
||||
if (version !== ACHIEVEMENT_SPELL_BINARY_VERSION) throw new Error("unsupported achievement spell version");
|
||||
if (![9, 10, ACHIEVEMENT_SPELL_BINARY_VERSION].includes(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)));
|
||||
|
|
@ -1514,21 +1499,26 @@
|
|||
const baseMinute = toSafeUInt(spell[4]);
|
||||
const deltas = Array.isArray(spell[5]) ? spell[5].map(toSafeUInt) : [];
|
||||
const progress = Array.isArray(spell[6]) ? spell[6] : [];
|
||||
const mysteryDrugIds = version >= 10 && Array.isArray(spell[7])
|
||||
? [...new Set(spell[7].map(value => String(value || "")).filter(Boolean))].slice(0, 10)
|
||||
: [];
|
||||
let unlockedCount = 0;
|
||||
for (const byte of bytes) {
|
||||
let value = byte;
|
||||
while (value) { unlockedCount += value & 1; value >>>= 1; }
|
||||
}
|
||||
if (deltas.length !== unlockedCount) throw new Error("invalid achievement spell timestamps");
|
||||
return { bytes, baseMinute, deltas, progress };
|
||||
return { bytes, baseMinute, deltas, progress, mysteryDrugIds };
|
||||
}
|
||||
|
||||
function spellFromAchievementMaskBytes(bytes = [], baseMinute = 0, deltas = [], progress = []) {
|
||||
function spellFromAchievementMaskBytes(bytes = [], baseMinute = 0, deltas = [], progress = [], version = ACHIEVEMENT_SPELL_BINARY_VERSION, mysteryDrugIds = []) {
|
||||
let low = 0;
|
||||
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, (Number(bytes[8]) || 0) + (Number(bytes[9]) || 0) * 256, toSafeUInt(baseMinute), deltas.map(toSafeUInt), progress];
|
||||
const spell = [version, low >>> 0, high >>> 0, (Number(bytes[8]) || 0) + (Number(bytes[9]) || 0) * 256, toSafeUInt(baseMinute), deltas.map(toSafeUInt), progress];
|
||||
if (version >= 10) spell.push([...new Set((mysteryDrugIds || []).map(value => String(value || "")).filter(Boolean))].slice(0, 10));
|
||||
return spell;
|
||||
}
|
||||
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]))));
|
||||
|
|
@ -1560,9 +1550,11 @@
|
|||
writer.raw(normalized.bytes);
|
||||
writer.u(normalized.baseMinute);
|
||||
for (const delta of normalized.deltas) writer.u(delta);
|
||||
writeAchievementProgress(writer, normalized.progress);
|
||||
writeAchievementProgress(writer, normalized.progress, ACHIEVEMENT_PROGRESS_BITS, ACHIEVEMENT_PROGRESS_MAX);
|
||||
writer.u(normalized.mysteryDrugIds.length);
|
||||
for (const id of normalized.mysteryDrugIds) writer.str(id);
|
||||
}
|
||||
function readAchievementSpell(reader) {
|
||||
function readAchievementSpell(reader, metadataVersion = ACHIEVEMENT_METADATA_BINARY_VERSION) {
|
||||
const bytes = reader.raw(ACHIEVEMENT_MASK_BYTES);
|
||||
let unlockedCount = 0;
|
||||
for (const byte of bytes) {
|
||||
|
|
@ -1572,8 +1564,21 @@
|
|||
const baseMinute = reader.u();
|
||||
const deltas = [];
|
||||
for (let i = 0; i < unlockedCount; i++) deltas.push(reader.u());
|
||||
const progress = readAchievementProgress(reader, ACHIEVEMENT_PROGRESS_BITS, ACHIEVEMENT_PROGRESS_MAX);
|
||||
return spellFromAchievementMaskBytes(bytes, baseMinute, deltas, progress);
|
||||
const current = metadataVersion >= 3;
|
||||
const progress = readAchievementProgress(
|
||||
reader,
|
||||
current ? ACHIEVEMENT_PROGRESS_BITS : ACHIEVEMENT_PROGRESS_BITS_V9,
|
||||
current ? ACHIEVEMENT_PROGRESS_MAX : ACHIEVEMENT_PROGRESS_MAX_V9,
|
||||
);
|
||||
const mysteryDrugIds = [];
|
||||
if (current) {
|
||||
const count = Math.min(10, reader.u());
|
||||
for (let i = 0; i < count; i++) {
|
||||
const id = String(reader.str() || "");
|
||||
if (id && !mysteryDrugIds.includes(id)) mysteryDrugIds.push(id);
|
||||
}
|
||||
}
|
||||
return spellFromAchievementMaskBytes(bytes, baseMinute, deltas, progress, current ? ACHIEVEMENT_SPELL_BINARY_VERSION : 9, mysteryDrugIds);
|
||||
}
|
||||
function writeAchievementMetadata(writer, metadata = null, tarinaiCount = 0, itemCount = 0) {
|
||||
const value = metadata && typeof metadata === "object" ? metadata : {};
|
||||
|
|
@ -1588,19 +1593,27 @@
|
|||
Math.min(10, toSafeUInt(w[4])),
|
||||
], [6, 8, 4]);
|
||||
|
||||
const timeDefaults = [null, -1, null, 0, -1, -1];
|
||||
const timeValues = [w[5], w[6], w[7], w[8], w[9], w[10]];
|
||||
let timeMask = 0;
|
||||
const timeDefaults = [null, -1, null, 0, -1, -1, -1];
|
||||
const timeValues = [w[5], w[6], w[7], w[8], w[9], w[10], w[11]];
|
||||
// Two-bit state per value: 0 = schema default, 1 = explicit null,
|
||||
// 2 = explicit finite number. This preserves null separately from 0/-1.
|
||||
const timeStates = [];
|
||||
const encodedTimes = [];
|
||||
timeValues.forEach((raw, index) => {
|
||||
const finite = finiteNumberOrNull(raw);
|
||||
const defaultValue = timeDefaults[index];
|
||||
const sameAsDefault = finite == null ? defaultValue == null : finite === defaultValue;
|
||||
if (sameAsDefault) return;
|
||||
timeMask |= 1 << index;
|
||||
encodedTimes.push(quantizedTenths(finite == null ? defaultValue || 0 : finite));
|
||||
if (finite == null) {
|
||||
timeStates.push(defaultValue == null ? 0 : 1);
|
||||
return;
|
||||
}
|
||||
if (finite === defaultValue) {
|
||||
timeStates.push(0);
|
||||
return;
|
||||
}
|
||||
timeStates.push(2);
|
||||
encodedTimes.push(quantizedTenths(finite));
|
||||
});
|
||||
writeBitFields(writer, [timeMask], [timeDefaults.length]);
|
||||
writeBitFields(writer, timeStates, timeStates.map(() => 2));
|
||||
encodedTimes.forEach(value => writer.s(value));
|
||||
|
||||
const tarRows = Array.isArray(value.t) ? value.t : [];
|
||||
|
|
@ -1611,12 +1624,21 @@
|
|||
const treatment = toSafeUInt(row[1]);
|
||||
const fightAt = finiteNumberOrNull(row[2]);
|
||||
const saunaAt = finiteNumberOrNull(row[3]);
|
||||
if (feed || treatment || fightAt != null || saunaAt != null) activeTarRows.push({ index, feed, treatment, fightAt, saunaAt });
|
||||
const slaveDepth = toSafeUInt(row[4]);
|
||||
const kingDepth = toSafeUInt(row[5]);
|
||||
if (feed || treatment || fightAt != null || saunaAt != null || slaveDepth || kingDepth) {
|
||||
activeTarRows.push({ index, feed, treatment, fightAt, saunaAt, slaveDepth, kingDepth });
|
||||
}
|
||||
}
|
||||
writer.u(activeTarRows.length);
|
||||
let previousTarIndex = -1;
|
||||
for (const row of activeTarRows) { writer.u(row.index - previousTarIndex - 1); previousTarIndex = row.index; }
|
||||
for (const row of activeTarRows) { writer.u(row.feed); writer.u(row.treatment); }
|
||||
for (const row of activeTarRows) {
|
||||
writer.u(row.feed);
|
||||
writer.u(row.treatment);
|
||||
writer.u(row.slaveDepth);
|
||||
writer.u(row.kingDepth);
|
||||
}
|
||||
const tarFlags = [];
|
||||
for (const row of activeTarRows) tarFlags.push(row.fightAt != null ? 1 : 0, row.saunaAt != null ? 1 : 0);
|
||||
if (tarFlags.length) writeBitFields(writer, tarFlags, tarFlags.map(() => 1));
|
||||
|
|
@ -1645,18 +1667,22 @@
|
|||
}
|
||||
function readAchievementMetadata(reader, tarinaiCount = 0, itemCount = 0) {
|
||||
const version = reader.b();
|
||||
if (version !== ACHIEVEMENT_METADATA_BINARY_VERSION) throw new Error("unsupported achievement metadata schema");
|
||||
if (![2, ACHIEVEMENT_METADATA_BINARY_VERSION].includes(version)) throw new Error("unsupported achievement metadata schema");
|
||||
const [flags] = readBitFields(reader, [1]);
|
||||
const w = [readPositiveDeltaList(reader), readPositiveDeltaList(reader)];
|
||||
const [directFeed, robotClean, enemyAntKills] = readBitFields(reader, [6, 8, 4]);
|
||||
w.push(directFeed, robotClean, enemyAntKills);
|
||||
const timeDefaults = [null, -1, null, 0, -1, -1];
|
||||
const [timeMask] = readBitFields(reader, [timeDefaults.length]);
|
||||
const timeDefaults = version >= 3 ? [null, -1, null, 0, -1, -1, -1] : [null, -1, null, 0, -1, -1];
|
||||
const timeStates = readBitFields(reader, timeDefaults.map(() => 2));
|
||||
for (let index = 0; index < timeDefaults.length; index++) {
|
||||
w.push(timeMask & (1 << index) ? unquantizedTenths(reader.s()) : timeDefaults[index]);
|
||||
const state = timeStates[index];
|
||||
if (state === 0) w.push(timeDefaults[index]);
|
||||
else if (state === 1) w.push(null);
|
||||
else if (state === 2) w.push(unquantizedTenths(reader.s()));
|
||||
else throw new Error("invalid achievement metadata time state");
|
||||
}
|
||||
|
||||
const t = Array.from({ length: tarinaiCount }, () => [0, 0, null, null]);
|
||||
const t = Array.from({ length: tarinaiCount }, () => [0, 0, null, null, 0, 0]);
|
||||
const tarCount = reader.u();
|
||||
const tarIndexes = [];
|
||||
let previousTarIndex = -1;
|
||||
|
|
@ -1665,13 +1691,22 @@
|
|||
if (previousTarIndex >= tarinaiCount) throw new Error("invalid achievement tarinai metadata index");
|
||||
tarIndexes.push(previousTarIndex);
|
||||
}
|
||||
const tarCounters = tarIndexes.map(() => [reader.u(), reader.u()]);
|
||||
const tarCounters = tarIndexes.map(() => version >= 3
|
||||
? [reader.u(), reader.u(), reader.u(), reader.u()]
|
||||
: [reader.u(), reader.u(), 0, 0]);
|
||||
const tarFlagWidths = Array.from({ length: tarCount * 2 }, () => 1);
|
||||
const tarFlags = tarFlagWidths.length ? readBitFields(reader, tarFlagWidths) : [];
|
||||
tarIndexes.forEach((index, rowIndex) => {
|
||||
const fightAt = tarFlags[rowIndex * 2] ? unquantizedTenths(reader.s()) : null;
|
||||
const saunaAt = tarFlags[rowIndex * 2 + 1] ? unquantizedTenths(reader.s()) : null;
|
||||
t[index] = [tarCounters[rowIndex][0], tarCounters[rowIndex][1], fightAt, saunaAt];
|
||||
t[index] = [
|
||||
tarCounters[rowIndex][0],
|
||||
tarCounters[rowIndex][1],
|
||||
fightAt,
|
||||
saunaAt,
|
||||
tarCounters[rowIndex][2],
|
||||
tarCounters[rowIndex][3],
|
||||
];
|
||||
});
|
||||
|
||||
const i = Array.from({ length: itemCount }, () => [0, null]);
|
||||
|
|
@ -1691,7 +1726,7 @@
|
|||
i[index] = [placed, placedAt];
|
||||
});
|
||||
const metadata = { w, t, i };
|
||||
if (flags & 1) metadata.s = readAchievementSpell(reader);
|
||||
if (flags & 1) metadata.s = readAchievementSpell(reader, version);
|
||||
return metadata;
|
||||
}
|
||||
|
||||
|
|
@ -1730,6 +1765,7 @@
|
|||
const itemRows = Array.isArray(snapshot.i) ? snapshot.i : [];
|
||||
writeItemBlocks(writer, itemRows);
|
||||
writer.category("achievementMetadata", () => writeAchievementMetadata(writer, snapshot.g || null, tarinaiRows.length, itemRows.length));
|
||||
writer.category("extendedState", () => writer.str(JSON.stringify(snapshot.x || {})));
|
||||
return writer.out();
|
||||
} finally {
|
||||
activeStringWriteMap = null;
|
||||
|
|
@ -1743,7 +1779,7 @@
|
|||
const formatHeader = reader.b();
|
||||
const schema = formatHeader & 0x7f;
|
||||
const hasStringTable = Boolean(formatHeader & 0x80);
|
||||
if (schema !== BINARY_SCHEMA_VERSION) throw new Error("unsupported binary save schema");
|
||||
if (![54, BINARY_SCHEMA_VERSION].includes(schema)) throw new Error("unsupported binary save schema");
|
||||
readStringTable(reader, hasStringTable);
|
||||
const w = readWorld(reader);
|
||||
const tCount = reader.u();
|
||||
|
|
@ -1758,8 +1794,10 @@
|
|||
} catch (_) {
|
||||
throw new Error("invalid achievement metadata in binary save");
|
||||
}
|
||||
let x = {};
|
||||
try { x = JSON.parse(reader.str() || "{}"); } catch (_) { throw new Error("invalid extended state in binary save"); }
|
||||
if (reader.pos !== reader.bytes.length) throw new Error("trailing bytes in binary save");
|
||||
return { v: Snapshot.version, a: "tj1", m: summaryFromPayload(w, t.length), w, t, i: items, g };
|
||||
return { v: Snapshot.version, a: "tj1", m: summaryFromPayload(w, t.length), w, t, i: items, r: [], g, x };
|
||||
} finally {
|
||||
activeStringReadList = null;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue