mirror of
https://github.com/bryanthaboi/gen1recomp
synced 2026-10-03 16:16:38 -04:00
sync save deletion
This commit is contained in:
+123
-1
@@ -117,8 +117,58 @@ local function slotForPlaythrough(options, version, playthroughId)
|
||||
return bestKey, bestSlot
|
||||
end
|
||||
|
||||
local function slotKey(scopeKey, slotId)
|
||||
local SaveData = saveApi()
|
||||
local cart = cartOfScope(scopeKey)
|
||||
local source
|
||||
if cart then
|
||||
source = SaveData.readCartSlotSource(cart, slotId)
|
||||
else
|
||||
source = SaveData.readSlotSource(scopeKey, slotId)
|
||||
end
|
||||
local save = source and SaveData.decode(source)
|
||||
if type(save) ~= "table" then return nil end
|
||||
local id
|
||||
local scope = { key = scopeKey, cart = cart, version = scopeKey }
|
||||
if cart then
|
||||
id = SaveData.cartSlotPlaythroughId(cart, slotId, save)
|
||||
local okOpts, options = pcall(SaveData.loadOptions)
|
||||
local reg = (okOpts and type(options) == "table"
|
||||
and type(options.carts) == "table") and options.carts[cart] or nil
|
||||
scope.version = type(reg) == "table" and reg.base or nil
|
||||
else
|
||||
id = SaveData.slotPlaythroughId(scopeKey, slotId, save)
|
||||
end
|
||||
if not id then return nil end
|
||||
return SyncState.key(wireVersion(save, scope), id)
|
||||
end
|
||||
|
||||
function SyncEngine.defaultSaves()
|
||||
return {
|
||||
keyForSlot = slotKey,
|
||||
|
||||
remove = function(version, playthroughId)
|
||||
local SaveData = saveApi()
|
||||
local options = SaveData.loadOptions()
|
||||
local scopeKey, slotId = slotForPlaythrough(options, version, playthroughId)
|
||||
if not slotId then return false, "no such save" end
|
||||
local cart = cartOfScope(scopeKey)
|
||||
local ok, err
|
||||
if cart then
|
||||
ok, err = SaveData.deleteCartSlot(cart, slotId)
|
||||
else
|
||||
ok, err = SaveData.deleteSlot(scopeKey, slotId)
|
||||
end
|
||||
if not ok then return nil, err or "could not delete the save" end
|
||||
options = SaveData.loadOptions()
|
||||
if type(options.playthroughIds) == "table"
|
||||
and type(options.playthroughIds[scopeKey]) == "table" then
|
||||
options.playthroughIds[scopeKey][slotId] = nil
|
||||
SaveData.saveOptions(options)
|
||||
end
|
||||
return slotId, cart
|
||||
end,
|
||||
|
||||
list = function()
|
||||
local SaveData = saveApi()
|
||||
local out = {}
|
||||
@@ -402,6 +452,22 @@ function SyncEngine:noteSaveWritten()
|
||||
self.uploadAt = self.clock + SyncEngine.UPLOAD_DEBOUNCE
|
||||
end
|
||||
|
||||
function SyncEngine:noteSaveDeleted(key)
|
||||
if type(key) ~= "string" or key == "" then return false end
|
||||
local rev = SyncState.rev(self.state, key)
|
||||
SyncState.forget(self.state, key)
|
||||
if rev == nil or not self:linked() then
|
||||
self:_persist()
|
||||
return false
|
||||
end
|
||||
SyncState.markDeleted(self.state, key, rev, self.now())
|
||||
self:_persist()
|
||||
if self.state.enabled then
|
||||
self.uploadAt = self.clock + SyncEngine.UPLOAD_DEBOUNCE
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
function SyncEngine:update(dt)
|
||||
self.clock = self.clock + (tonumber(dt) or 0)
|
||||
if self.pending then
|
||||
@@ -650,12 +716,14 @@ function SyncEngine:_planFrom(remoteState)
|
||||
self.devices = list
|
||||
end
|
||||
local remote = type(remoteState.saves) == "table" and remoteState.saves or {}
|
||||
local tombs = type(remoteState.deleted) == "table" and remoteState.deleted or {}
|
||||
local locals = self.saves.list() or {}
|
||||
local seen = {}
|
||||
for _, entry in ipairs(locals) do
|
||||
local key = SyncState.key(entry.version, entry.playthroughId)
|
||||
if key then
|
||||
seen[key] = true
|
||||
SyncState.clearDeleted(self.state, key)
|
||||
local row = remote[key]
|
||||
local knownRev = SyncState.rev(self.state, key)
|
||||
local stamp = unixSeconds(SyncState.stamp(self.state, key))
|
||||
@@ -668,7 +736,14 @@ function SyncEngine:_planFrom(remoteState)
|
||||
end
|
||||
local remoteRev = row and tonumber(row.rev)
|
||||
local remoteChanged = row ~= nil and remoteRev ~= knownRev
|
||||
if not row then
|
||||
local tomb = not row and type(tombs[key]) == "table" and tombs[key] or nil
|
||||
local buried = tomb ~= nil and knownRev ~= nil
|
||||
and (tonumber(tomb.rev) or 0) >= knownRev
|
||||
and not (localChanged and liveStamp
|
||||
and liveStamp > (unixSeconds(tomb.deletedAt) or 0))
|
||||
if buried then
|
||||
self:_removeLocal(entry, key, tomb)
|
||||
elseif not row then
|
||||
self:_queueUpload(entry, key, false)
|
||||
elseif localChanged and remoteChanged then
|
||||
if SyncEngine.sameProgress(entry.meta, SyncEngine.metaOf(row)) then
|
||||
@@ -683,6 +758,17 @@ function SyncEngine:_planFrom(remoteState)
|
||||
end
|
||||
end
|
||||
end
|
||||
for key, pending in pairs(self.state.pendingDeletes or {}) do
|
||||
local row = remote[key]
|
||||
if not seen[key] then
|
||||
if row and (tonumber(row.rev) or 0) > (tonumber(pending.rev) or 0) then
|
||||
SyncState.clearDeleted(self.state, key)
|
||||
else
|
||||
seen[key] = true
|
||||
self:_queueDelete(key, pending.rev)
|
||||
end
|
||||
end
|
||||
end
|
||||
for key, row in pairs(remote) do
|
||||
if not seen[key] and key ~= self.protectedKey then
|
||||
local version, id = SyncState.splitKey(key)
|
||||
@@ -694,6 +780,42 @@ function SyncEngine:_planFrom(remoteState)
|
||||
if #self.queue == 0 then self:_finish() end
|
||||
end
|
||||
|
||||
function SyncEngine:_removeLocal(entry, key, tomb)
|
||||
if key == self.protectedKey then return end
|
||||
local slotId, cartId
|
||||
if type(self.saves.remove) == "function" then
|
||||
slotId, cartId = self.saves.remove(entry.version, entry.playthroughId)
|
||||
end
|
||||
SyncState.forget(self.state, key)
|
||||
if slotId then
|
||||
self.lastDownloads = self.lastDownloads or {}
|
||||
self.lastDownloads[#self.lastDownloads + 1] = {
|
||||
version = entry.version,
|
||||
cart = cartId or entry.cart,
|
||||
slot = slotId,
|
||||
removed = true,
|
||||
device = type(tomb.device) == "string" and tomb.device ~= ""
|
||||
and tomb.device or nil,
|
||||
}
|
||||
self.changed = true
|
||||
end
|
||||
end
|
||||
|
||||
function SyncEngine:_queueDelete(key, rev)
|
||||
self:_enqueue(function(eng)
|
||||
eng.phase = "uploading"
|
||||
eng.status = "Removing deleted saves..."
|
||||
local version, id = SyncState.splitKey(key)
|
||||
local handle, err = eng.client:deleteSave(version, id, rev)
|
||||
eng:_request(handle, err, function(e)
|
||||
SyncState.clearDeleted(e.state, key)
|
||||
SyncState.forget(e.state, key)
|
||||
e:_persist()
|
||||
if not e:busy() then e:_finish() end
|
||||
end)
|
||||
end)
|
||||
end
|
||||
|
||||
function SyncEngine:_addConflict(entry, key, row)
|
||||
local remoteMeta = SyncEngine.displayMeta(SyncEngine.metaOf(row))
|
||||
self.conflicts[#self.conflicts + 1] = {
|
||||
|
||||
Reference in New Issue
Block a user