Skip to content

Commit

Permalink
Merge pull request #813 from AntlerForce/Moose_replay_OldEngine2
Browse files Browse the repository at this point in the history
Download prior engine versions on demand: Moose
  • Loading branch information
AntlerForce authored Dec 1, 2024
2 parents aa7f395 + 7e07737 commit 80685dd
Show file tree
Hide file tree
Showing 7 changed files with 203 additions and 49 deletions.
51 changes: 32 additions & 19 deletions LuaMenu/widgets/api_download_handler.lua
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,14 @@ local USE_WRAPPER_DOWNLOAD = true
local typeMap = {
game = "RAPID",
map = "MAP",
engine = "ENGINE",
resource = "RESOURCE",
}
local reverseTypeMap = {
RAPID = "game",
MAP = "map",
ENGINE = "engine",
RESOURCE = "resource",
}

--------------------------------------------------------------------------------
Expand Down Expand Up @@ -132,7 +136,7 @@ local function DownloadQueueUpdate()
local front = downloadQueue[1]
if not front.active then
if USE_WRAPPER_DOWNLOAD and WG.WrapperLoopback and WG.WrapperLoopback.DownloadFile then
WG.WrapperLoopback.DownloadFile(front.name, typeMap[front.fileType])
WG.WrapperLoopback.DownloadFile(front.name, typeMap[front.fileType], front.resource)
CallListeners("DownloadStarted", front.id, front.name, front.fileType)
else
VFS.DownloadArchive(front.name, front.fileType)
Expand Down Expand Up @@ -239,7 +243,7 @@ end
--------------------------------------------------------------------------------
-- Externals Functions

function externalFunctions.QueueDownload(name, fileType, priority, retryCount)
function externalFunctions.QueueDownload(name, fileType, priority, retryCount, resource)
priority = priority or 1
if priority == -1 then
priority = topPriority + 1
Expand All @@ -266,9 +270,10 @@ function externalFunctions.QueueDownload(name, fileType, priority, retryCount)
priority = priority,
id = downloadCount,
retryCount = retryCount or 0,
resource = resource,
}
requestUpdate = true
CallListeners("DownloadQueued", downloadCount, name, fileType)
CallListeners("DownloadQueued", downloadCount, name, fileType, resource)
end

function externalFunctions.SetDownloadTopPriority(name, fileType)
Expand All @@ -283,20 +288,13 @@ function externalFunctions.SetDownloadTopPriority(name, fileType)
return true
end

function externalFunctions.CancelDownload(name, fileType)
function externalFunctions.CancelDownload(name, fileType, success)
local index = GetDownloadIndex(downloadQueue, name, fileType)
if not index then
return false
end

if downloadQueue[index].active then
if USE_WRAPPER_DOWNLOAD and WG.WrapperLoopback and WG.WrapperLoopback.AbortDownload then
WG.WrapperLoopback.AbortDownload(name, typeMap[fileType])
end
return
end

downloadQueue[index].removalType = "cancel"
downloadQueue[index].removalType = (success == "fail") and "fail" or "cancel"
removedDownloads[#removedDownloads + 1] = downloadQueue[index]

downloadQueue[index] = downloadQueue[#downloadQueue]
Expand Down Expand Up @@ -329,9 +327,22 @@ function externalFunctions.RemoveRemovedDownload(name, fileType)
return true
end

function externalFunctions.MaybeDownloadArchive(name, archiveType, priority)
if not VFS.HasArchive(name) then
local function haveEngineDir(path)
local springExecutable = Platform.osFamily == "Windows" and "spring.exe" or "spring"
return VFS.FileExists(path .. "//" .. springExecutable)
end

function externalFunctions.MaybeDownloadArchive(name, archiveType, priority, resource)
if archiveType == "resource" then
local haveEngine = haveEngineDir(resource.destination)
if not haveEngine then
externalFunctions.QueueDownload(name, archiveType, priority, _, resource)
end
return

elseif not VFS.HasArchive(name) then
externalFunctions.QueueDownload(name, archiveType, priority)
return
end
end

Expand All @@ -356,10 +367,12 @@ function wrapperFunctions.DownloadFinished(name, fileType, success, aborted)
RemoveDownload(name, fileType, true, (aborted and "cancel") or (success and "success") or "fail")
end

--Chotify:Post({
-- title = "Download " .. ((success and "Finished") or "Failed"),
-- body = (name or "???") .. " of type " .. (fileType or "???"),
--})
if not success then
Chotify:Post({
title = i18n("download_failed"),
body = (name or "???") .. " of type " .. (fileType or "???"),
})
end
end

function wrapperFunctions.DownloadFileProgress(name, progress, totalLength)
Expand All @@ -369,7 +382,7 @@ function wrapperFunctions.DownloadFileProgress(name, progress, totalLength)
end

totalLength = (tonumber(totalLength or 0) or 0)/1023^2
CallListeners("DownloadProgress", downloadQueue[index].id, totalLength*math.min(1, (tonumber(progress or 0) or 0)/100), totalLength, name)
CallListeners("DownloadProgress", downloadQueue[index].id, totalLength*math.min(1, (tonumber(progress or 0) or 0)/100), totalLength, downloadQueue[index].name)
end

function wrapperFunctions.ImageDownloadFinished(requestToken, imageUrl, imagePath)
Expand Down
27 changes: 27 additions & 0 deletions LuaMenu/widgets/chobby/components/configuration.lua
Original file line number Diff line number Diff line change
Expand Up @@ -379,6 +379,14 @@ function Configuration:init()
self.saneCharacters[saneCharacterList[i]] = true
end

local engineSaneCharacterList = {
"-", ".", " ",
}
self.engineSaneCharacters = {}
for i = 1, #engineSaneCharacterList do
self.engineSaneCharacters[engineSaneCharacterList[i]] = true
end

self.barMngSettings = {
autoBalance = true,
teamSize = true,
Expand Down Expand Up @@ -1051,6 +1059,25 @@ function Configuration:IsValidEngineVersion(engineVersion)
return validengine
end

function Configuration:SanitizeEngineVersion(engineVersion)
local ret = ""
local length = string.len(engineVersion)
for i = 1, length do
local c = string.sub(engineVersion, i, i)
if self.saneCharacters[c] or self.engineSaneCharacters[c] then
ret = ret .. c
end
end

local format = "(%d+)%.(%d+)%.(%d+)%-(%d+)%-g([%x][%x][%x][%x][%x][%x][%x])%s"
if not ret:match(format) then
Spring.Echo("Invalid engine version format: " .. engineVersion)
ret = ""
end

return ret
end

function Configuration:SanitizeName(name, usedNames)
local ret = ""
local length = string.len(name)
Expand Down
8 changes: 6 additions & 2 deletions LuaMenu/widgets/chobby/components/downloader.lua
Original file line number Diff line number Diff line change
Expand Up @@ -292,7 +292,11 @@ function Downloader:DownloadFailed(listener, downloadID, errorID)
self:UpdateQueue()
end

function Downloader:DownloadQueued(listener, downloadID, archiveName, archiveType)
self.downloads[downloadID] = { archiveName = archiveName, archiveType = archiveType, startTime = os.clock() }
function Downloader:DownloadQueued(listener, downloadID, archiveName, archiveType, resource)
self.downloads[downloadID] = {
archiveName = archiveName,
archiveType = archiveType,
resource = resource,
startTime = os.clock() }
self:UpdateQueue()
end
3 changes: 2 additions & 1 deletion LuaMenu/widgets/chobby/i18n/chililobby.lua
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ return {
delete_confirm = "Are you sure you want to delete this saved game?",
load_confirm = "Loading will lose any unsaved progress. Are you sure?",
replay_not_found = "Replay file not found, refresh the list!",
replay_different_version = "This replay requires a different engine version (FIXME download automatically if necessary)",
replay_different_version = "This replay requires a different engine version (will be downloaded automatically if necessary)",
--
start_download = 'Start download',
download_noun = 'Download',
Expand Down Expand Up @@ -204,6 +204,7 @@ return {
other = "%{count} items left to download.",
},
downloads_completed = "All downloads completed.",
download_failed = "Download Failed",
wip_challenges = "WiP Challenges",
["scenarios"] = "Scenarios",
-- Settings
Expand Down
2 changes: 2 additions & 0 deletions LuaMenu/widgets/gui_download_window.lua
Original file line number Diff line number Diff line change
Expand Up @@ -361,6 +361,8 @@ local function InitializeControls(window)
local function DownloadProgress(_, _, sizeCurrent, sizeTotal, name)
if downloads[name] then
downloads[name].SetProgress(sizeCurrent, sizeTotal)
else
Spring.Log(LOG_SECTION, LOG.ERROR, "DownloadWindow:DownloadProgressListener not found")
end
end

Expand Down
54 changes: 46 additions & 8 deletions LuaMenu/widgets/gui_steam_coop_handler.lua
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ local function MakeExclusivePopup(text, buttonText, ClickFunc, buttonClass, heig
if replacablePopup then
replacablePopup:Close()
end
replacablePopup = WG.Chobby.InformationPopup(text, {caption = buttonText, closeFunc = ClickFunc, buttonClass = buttonClass, height = height, width = 500})
replacablePopup = WG.Chobby.InformationPopup(text, {caption = buttonText, closeFunc = ClickFunc, buttonClass = buttonClass, height = height, width = 540})
end

local function CloseExclusivePopup()
Expand Down Expand Up @@ -159,7 +159,31 @@ end
--------------------------------------------------------------------------------
-- Downloading

local function CheckDownloads(gameName, mapName, DoneFunc, gameList)
-- outcome example: "105.1.1-1354-g72b2d55 BAR105" -> "engine/105.1.1-1354-g72b2d55 bar"
local function GetEnginePath(engineVersion)
return ("engine/" .. engineVersion:gsub(" BAR105", " bar")):lower() -- maybe there are more special cases to take in mind here for very old demos or future ones!
end

local function haveEngineVersion(engineVersion)
local springExecutable = Platform.osFamily == "Windows" and "spring.exe" or "spring"
return VFS.FileExists(GetEnginePath(engineVersion) .. "//" .. springExecutable)
end

-- outcome example: https://github.com/beyond-all-reason/spring/releases/download/spring_bar_%7BBAR105%7D105.1.1-1354-g72b2d55/spring_bar_.BAR105.105.1.1-1354-g72b2d55_windows-64-minimal-portable.7z
local function GetEngineDownloadUrl(engineVersion)
local sanitizedEngineVersion = WG.Chobby.Configuration:SanitizeEngineVersion(engineVersion)
local branch = sanitizedEngineVersion:match("%s([%w-.]*)") or ""
local pureVersion = sanitizedEngineVersion:gsub(" " .. branch, "")
local baseUrl = "https://github.com/beyond-all-reason/spring/releases/download/"
local versionDir = "spring_bar_%7B" .. branch .. "%7D" .. pureVersion .. "/"
local platform64 = Platform.osFamily:lower() .. "-64"
local fileName = "spring_bar_." .. branch .. "." .. pureVersion .. "_" .. platform64 .. "-minimal-portable.7z"
return baseUrl .. versionDir .. fileName
end

-- gameList = nil
-- local oneTimeResourceDl = false
local function CheckDownloads(gameName, mapName, DoneFunc, gameList, engineVersion)
local haveGame = (not gameName) or WG.Package.ArchiveExists(gameName)
if not haveGame then
WG.DownloadHandler.MaybeDownloadArchive(gameName, "game", -1)
Expand All @@ -179,12 +203,21 @@ local function CheckDownloads(gameName, mapName, DoneFunc, gameList)
end
end

if haveGame and haveMap then
local haveEngine = not engineVersion or haveEngineVersion(engineVersion)
if not haveEngine then
WG.DownloadHandler.MaybeDownloadArchive(engineVersion, "resource", -1,{ -- FB 2023-05-14: Use resource download until engine-download is supported by launcher
url = GetEngineDownloadUrl(engineVersion),
destination = GetEnginePath(engineVersion),
extract = true,
})
end

if haveGame and haveMap and haveEngine then
return true
end

local function Update()
if ((not gameName) or WG.Package.ArchiveExists(gameName)) and ((not mapName) or VFS.HasArchive(mapName)) then
if ((not gameName) or WG.Package.ArchiveExists(gameName)) and ((not mapName) or VFS.HasArchive(mapName)) and ((not engineVersion) or haveEngineVersion(engineVersion)) then
if gameList then
for i = 1, #gameList do
if not WG.Package.ArchiveExists(gameList[i]) then
Expand Down Expand Up @@ -230,8 +263,14 @@ local function CheckDownloads(gameName, mapName, DoneFunc, gameList)
downloading.downloads[mapName] = #downloading.progress
end

if not haveEngine then
dlString = dlString .. ("\n - " .. engineVersion .. ": %d%%")
downloading.progress[#downloading.progress + 1] = 0
downloading.downloads[engineVersion] = #downloading.progress
end

downloading.dlString = dlString
MakeExclusivePopup(string.format(dlString, unpack(downloading.progress)), "Cancel", CancelFunc, "negative_button", (gameList and (180 + (#gameList)*40)))
MakeExclusivePopup(string.format(dlString, unpack(downloading.progress)), "Cancel", CancelFunc, "negative_button", (gameList and (220 + (#gameList)*40)))
end


Expand Down Expand Up @@ -345,7 +384,7 @@ end
-- External functions: Widget <-> Widget

function SteamCoopHandler.AttemptGameStart(gameType, gameName, mapName, scriptTable, newFriendsReplaceAI, newReplayFile, newEngineVersion)
if coopClient then
if coopClient then -- ZK only, always false
local statusAndInvitesPanel = WG.Chobby.interfaceRoot.GetStatusAndInvitesPanel()
if statusAndInvitesPanel and statusAndInvitesPanel.GetChildByName("coopPanel") then
WG.Chobby.InformationPopup("Only the host of the coop party can launch games.")
Expand Down Expand Up @@ -394,7 +433,6 @@ function SteamCoopHandler.AttemptGameStart(gameType, gameName, mapName, scriptTa
MakeExclusivePopup("Wrapper is required to watch replays with old engine versions.")
return
end
local engine = string.gsub(string.gsub(startEngineVersion, " maintenance", ""), " develop", "")
local engine = string.gsub(startEngineVersion, "BAR105", "bar") -- because this is the path we use
local params = {
StartDemoName = startReplayFile, -- dont remove the 'demos/' string from it now
Expand Down Expand Up @@ -462,7 +500,7 @@ function SteamCoopHandler.AttemptGameStart(gameType, gameName, mapName, scriptTa
WG.WrapperLoopback.SteamHostGameRequest(args)
end

if CheckDownloads(gameName, mapName, DownloadsComplete) then
if CheckDownloads(gameName, mapName, DownloadsComplete, _, newEngineVersion) then
DownloadsComplete()
end
end
Expand Down
Loading

0 comments on commit 80685dd

Please sign in to comment.