This commit is contained in:
33333-33333 2026-07-18 13:06:02 +09:00
commit f657b6a4a4
94 changed files with 3970 additions and 1241 deletions

View file

@ -167,7 +167,12 @@
function compactWorld(worldRef) {
const config = typeof CONFIG !== "undefined" ? CONFIG : (global.CONFIG || {});
const dayLength = Math.max(1, Number(config.dayLength || 120));
const worldTick10 = q((Math.max(1, worldRef?.day || 1) - 1) * dayLength + (Number(worldRef?.time) || 0), 10);
const rawTime = Math.max(0, Number(worldRef?.time) || 0);
const elapsedDays = Number.isFinite(Number(worldRef?.elapsedDays))
? Math.max(0, Math.floor(Number(worldRef.elapsedDays) || 0))
: Math.max(0, Math.floor(rawTime / dayLength));
const timeOfDay = ((rawTime % dayLength) + dayLength) % dayLength;
const worldTick10 = q(elapsedDays * dayLength + timeOfDay, 10);
return [
enumIndex(FIELD_IDS, worldRef?.fieldType || "garden"),
enumIndex(GROUND_IDS, worldRef?.groundType || "soil"),
@ -187,26 +192,42 @@
q(worldRef?.achievementLastInterventionAt, 10, 0),
q(worldRef?.achievementNoDeathStartAt, 10, -10),
q(worldRef?.achievementDirectFeedCount, 1, 0),
elapsedDays,
q(worldRef?.achievementManualTarinaiAddedCount, 1, 0),
];
}
function applyCompactWorld(worldRef, arr = []) {
function applyCompactWorld(worldRef, arr = [], meta = []) {
const config = typeof CONFIG !== "undefined" ? CONFIG : (global.CONFIG || {});
const dayLength = Math.max(1, Number(config.dayLength || 120));
const totalTime = u(arr[3], 10, 0);
const encodedTotalTime = Math.max(0, u(arr[3], 10, 0));
const hasEncodedElapsedDays = arr[18] !== null && arr[18] !== undefined && Number.isFinite(Number(arr[18]));
const hasMetaElapsedDays = meta[3] !== null && meta[3] !== undefined && Number.isFinite(Number(meta[3]));
const hasMetaDay = meta[0] !== null && meta[0] !== undefined && Number.isFinite(Number(meta[0]));
const encodedElapsedDays = hasEncodedElapsedDays
? Math.max(0, Math.floor(Number(arr[18]) || 0))
: (hasMetaElapsedDays
? Math.max(0, Math.floor(Number(meta[3]) || 0))
: (hasMetaDay
? Math.max(0, Math.floor((Number(meta[0]) || 1) - 1))
: Math.max(0, Math.floor(encodedTotalTime / dayLength / 2))));
const timeOfDay = ((encodedTotalTime % dayLength) + dayLength) % dayLength;
const totalTime = encodedElapsedDays * dayLength + timeOfDay;
worldRef.fieldType = enumValue(FIELD_IDS, arr[0], "garden");
worldRef.weather = enumValue(WEATHER_IDS, arr[4], "sunny");
worldRef.worldSeed = String(arr[8] || "") || global.TarinaiSeedFactory.createWorldSeed() || `w${Date.now().toString(36)}`;
worldRef.birthSerial = Math.max(0, u(arr[9], 1, 0));
worldRef.tarinaiPopulationLimit = Math.max(0, u(arr[10], 1, 0));
worldRef.objectLimit = Math.max(0, u(arr[11], 1, 0));
worldRef.tarinaiPopulationLimit = worldRef.normalizeColonyLimit?.(u(arr[10], 1, 0)) ?? Math.min(300, Math.max(0, u(arr[10], 1, 0)));
worldRef.objectLimit = worldRef.normalizeColonyLimit?.(u(arr[11], 1, 0)) ?? Math.min(300, Math.max(0, u(arr[11], 1, 0)));
worldRef.achievementNaturalSlaveGenerations = Array.isArray(arr[12]) ? [...new Set(arr[12].map(value => Math.max(1, Math.floor(Number(value) || 1))))].sort((a, b) => a - b) : [];
worldRef.achievementNaturalKingGenerations = Array.isArray(arr[13]) ? [...new Set(arr[13].map(value => Math.max(1, Math.floor(Number(value) || 1))))].sort((a, b) => a - b) : [];
worldRef.achievementPlayerPlacementCount = Math.max(0, u(arr[14], 1, 0));
worldRef.achievementLastInterventionAt = Math.max(0, u(arr[15], 10, totalTime));
worldRef.achievementNoDeathStartAt = u(arr[16], 10, -1);
worldRef.achievementDirectFeedCount = Math.max(0, u(arr[17], 1, 0));
worldRef.day = Math.max(1, Math.floor(totalTime / dayLength) + 1);
worldRef.time = totalTime - (worldRef.day - 1) * dayLength;
worldRef.achievementManualTarinaiAddedCount = Math.min(100, Math.max(0, u(arr[19], 1, 0)));
worldRef.time = Math.max(0, totalTime);
worldRef.elapsedDays = encodedElapsedDays;
worldRef.day = worldRef.elapsedDays + 1;
worldRef.nextWeatherChange = rand(CONFIG.weatherChangeMin, CONFIG.weatherChangeMax);
worldRef.deadCount = u(arr[7], 1, 0);
worldRef.liveIdNext = 1;
@ -235,6 +256,8 @@
const needOverprotective = !isUnlocked("overprotective");
const needSauna = !isUnlocked("sauna_cold_plunge");
const needQuickDelete = !isUnlocked("unplanned_city_30");
const needMinimalist = !isUnlocked("minimalist_happy");
const needPlayerPlacedMetadata = needQuickDelete || needMinimalist;
const metadata = {
w: [
needSlaveGenerations ? [...new Set((worldRef?.achievementNaturalSlaveGenerations || []).map(value => Math.max(1, Math.floor(Number(value) || 1))))].sort((a, b) => a - b) : [],
@ -256,7 +279,7 @@
needSauna ? finiteOrNull(t?._achievementSaunaHotAt) : null,
]),
i: itemRecords.map(rec => [
needQuickDelete && rec?.item?._achievementPlayerPlaced ? 1 : 0,
needPlayerPlacedMetadata && rec?.item?._achievementPlayerPlaced ? 1 : 0,
needQuickDelete ? finiteOrNull(rec?.item?._achievementPlacedAt) : null,
]),
};
@ -587,7 +610,7 @@
return {
v: SNAPSHOT_VERSION,
a: "tj1",
m: [worldRef.day || 1, tarinaiLive.length, worldRef.fieldType || "garden"],
m: [worldRef.day || 1, tarinaiLive.length, worldRef.fieldType || "garden", Math.max(0, Math.floor(Number(worldRef.elapsedDays ?? ((Number(worldRef.day || 1) || 1) - 1)) || 0))],
w: compactWorld(worldRef),
t: tarinaiLive.map((t, i) => compactTarinai(t, i, familyIndex, tarinaiIndex, itemIndex)),
i: itemRows,
@ -608,7 +631,7 @@
worldRef.selected = null;
worldRef.events = global.TarinaiEvents || null;
worldRef.liveTarinai = new Map();
applyCompactWorld(worldRef, snapshot.w || []);
applyCompactWorld(worldRef, snapshot.w || [], snapshot.m || []);
const tarRows = Array.isArray(snapshot.t) ? snapshot.t : [];
for (let idx = 0; idx < tarRows.length; idx++) {
@ -681,6 +704,23 @@
if (typeof updateNeedsRuntime === "function") {
for (const t of worldRef.tarinai) updateNeedsRuntime(t, worldRef, 0);
}
// Velocity is not serialized. Start restored bodies from a neutral physical
// state, but do not grant a timed collision/damage immunity period.
delete worldRef._restoreSettleUntil;
for (const t of worldRef.tarinai) {
if (!t || t.dead) continue;
t.vx = 0;
t.vy = 0;
t.impulseVx = 0;
t.impulseVy = 0;
t.prevX = t.x;
t.prevY = t.y;
t._lastPhysicalVelocityX = 0;
t._lastPhysicalVelocityY = 0;
t.lastVelocityShockDamageAt = -999;
t.lastPhysicalCollisionDamageAt = -999;
}
worldRef.liveIdNext = Math.max(1, worldRef.tarinai.length + 1);
worldRef.liveIdSerial = Math.max(1, worldRef.tarinai.length + 1);
worldRef.birthSerial = Math.max(Number(worldRef.birthSerial) || 0, ...worldRef.tarinai.map(t => Number(t.birthSerial) || 0));
@ -694,11 +734,13 @@
worldRef.relationNotices = {};
worldRef.resolvedFightIds = {};
worldRef.eventCounters = {};
worldRef.rebuildTarinaiCountCache?.("restore");
worldRef.updateItemCounts?.();
worldRef.enforceGrassLimit?.("load-grass-limit");
worldRef.compactItems?.();
worldRef.updateItemCounts?.();
worldRef.updateEffectCounts?.();
global.TarinaiAchievements?.evaluateEvent?.(worldRef, "restore", { source: "snapshot" });
worldRef.rebuildSpatial?.(true);
worldRef.markTerrainDirty?.("load");
worldRef.clampCamera?.();