Tag prefetched copies with the controller's run token

If the controller crashes after sending generation N but before saving it, the destination keeps that prefetch while the controller restarts at N-1, and another instance can then upload different data as generation N. The controller now picks a random token per run, sends it with every prefetch and acquire reply, and the scenario applies a held copy only when its generation and token both match, and lets a new run's copy replace one with another token.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
ILLISISandClaude Opus 5.5 committed 2026-10-20 12:24:24 +11:00
1 parent ca7caedfbe
commit 5e4dcada50
6 files changed
+84 -18

No files matched your search

+8 -4
View File
@@ -29,6 +29,7 @@ type IpcAcquireResponse = {
has_data?: boolean,
message?: string,
epoch?: number,
token?: string,
}
/**
@@ -139,6 +140,7 @@ export default async function(context: InstancePluginContext) {
has_data: acquireResponse.hasData,
message: acquireResponse.message,
epoch: acquireResponse.epoch,
token: acquireResponse.token,
};
} catch (err: any) {
if (!(err instanceof lib.SessionLost)) {
@@ -282,13 +284,15 @@ export default async function(context: InstancePluginContext) {
// A copy of a player's stored data, sent ahead while they switch to this instance (player_sync.prefetch_inventory)
async function handlePrefetch(event: PrefetchEvent) {
const { playerData } = event;
const { playerData, token } = event;
const { name, generation } = playerData;
logger.verbose(`Prefetching ${name}`);
// This side doesn't know the save's cleared recipe list, so the whole stored list goes as a full delta
await sendPlayerData(playerData, undefined, (chunk, number, total, extra) => (
`/sc player_sync.prefetch_inventory('${name}',${generation},'${chunk}',${number},${total}${extra})`
), true);
await sendPlayerData(playerData, undefined, (chunk, number, total, extra) => {
const tokenArg = number === 1 ? `,'${token}'` : "";
const args = `'${name}',${generation},'${chunk}',${number},${total}${extra}${tokenArg}`;
return `/sc player_sync.prefetch_inventory(${args})`;
}, true);
}
instance.handle(PrefetchEvent, handlePrefetch);