myspace / CommonLua /Dlc.lua
sirnii's picture
Upload 1816 files
b6a38d7 verified
raw
history blame
28.9 kB
--[==[
DLC OS-specific files have the following structure:
DLC content is:
|- autorun.lua
|- revisions.lua
|- Lua.hpk (if containing newer version of Lua, causes reload)
|- Data.hkp (if containing newer version of Data)
|- Data/... (additional data)
|- Maps/...
|- Sounds.hpk
|- EntityTextures.hpk (additional entity textures)
|- ...
The Autorun returns a table with a description of the dlc:
return {
name = "Colossus",
display_name = T{"Colossus"}, -- optional, must be a T with an id if present
pre_load = function() end,
post_load = function() end,
required_lua_revision = 12345, -- skip loading this DLC below this revision
}
DLC mount steps:
1. Enumerate and mount OS-specific DLC packs (validating them on steam/pc)
-- result is a list of folders containing autorun.lua files
2. Execute autorun.lua and revisions.lua; autorun.lua should set g_AvailableDlc[dlc.name] = true
3. Check required_lua_revision and call dlc:pre_load() for each dlc that passes the check
4. If necessary reload localization, lua and data from the lasest packs (it can update the follow up Dlc load steps)
5. If necessary reload the latest Dlc assets
-- reload entities
-- reload BinAssets
-- reload sounds
-- reload music
6. Call the dlc:post_load() for each dlc
]==]
if FirstLoad then
-- "" and false are "no dlc" values for the missions and achievements systems respectively
g_AvailableDlc = {[""] = true, [false] = true} -- [achievement name] = true ; DLC code is expected to properly init this!
g_DlcDisplayNames = {} -- [achievement name] = "translated string"
DlcFolders = false
DlcDefinitions = false
DataLoaded = false
end
if FirstLoad and Platform.playstation then
local err, list = AsyncPlayStationAddcontList(0)
g_AddcontStatus = {}
if not err then
for _, addcont in ipairs(list) do
g_AddcontStatus[addcont.label] = addcont.status
end
end
end
dlc_print = CreatePrint{
--"dlc"
}
--[[@@@
Returns if the player has a specific DLC installed.
@function bool IsDlcAvailable(string dlc)
@param dlc - The ID of a DLC.
@result bool - If the DLC is available and loaded.
]]
function IsDlcAvailable(dlc)
dlc = dlc or false
return g_AvailableDlc[dlc]
end
function IsDlcOwned(dlc)
end
function DLCPath(dlc)
if not dlc or dlc == "" then return "" end
return "DLC/" .. dlc
end
-- Use, for example, for marking savegames. In all other cases use IsDlcAvailable
function GetAvailableDlcList()
local dlcs = {}
for dlc, v in pairs(g_AvailableDlc) do
if v and dlc ~= "" and dlc ~= false then
dlcs[ 1 + #dlcs ] = dlc
end
end
table.sort(dlcs)
return dlcs
end
function GetDeveloperDlcs()
local dlcs = Platform.developer and IsFSUnpacked() and io.listfiles("svnProject/Dlc/", "*", "folders") or empty_table
for i, folder in ipairs(dlcs) do
dlcs[i] = string.gsub(folder, "svnProject/Dlc/", "")
end
table.sort(dlcs)
return dlcs
end
DbgAllDlcs = false
DbgAreDlcsMissing = return_true
DbgIgnoreMissingDlcs = rawget(_G, "DbgIgnoreMissingDlcs") or {}
if Platform.developer and IsFSUnpacked() then
DbgAllDlcs = GetDeveloperDlcs()
function DbgAreDlcsMissing()
for _, dlc in ipairs(DbgAllDlcs or empty_table) do
if not DbgIgnoreMissingDlcs[dlc] and not g_AvailableDlc[dlc] then
return dlc
end
end
end
end
-- Helper function for tying a savegame to a set of required DLCs
-- metadata = FillDlcMetadata(metadata, dlcs)
function FillDlcMetadata(metadata, dlcs)
metadata = metadata or {}
dlcs = dlcs or GetAvailableDlcList()
local t = {}
for _, dlc in ipairs(dlcs) do
t[#t+1] = {id = dlc, name = g_DlcDisplayNames[dlc] or dlc}
end
metadata.dlcs = t
return metadata
end
-- Step 1. Enumerate and mount OS-specific DLC packs (validating them on steam/pc)
function DlcMountOsPacks()
dlc_print("Mount Os Packs")
local folders = {}
local error = false
if Platform.demo then
dlc_print("Mount Os Packs early out: no DLCs in demo")
return folders, error
end
if Platform.playstation then
for label, status in pairs(g_AddcontStatus) do
if status == const.PlaystationAddcontStatusInstalled then
local addcont_error, mount_point = AsyncPlayStationAddcontMount(0, label)
local pack_error = MountPack(label, mount_point .. "/content.hpk")
error = error or addcont_error or pack_error
table.insert(folders, label)
end
end
dlc_print(string.format("PS4 Addcont: %d listed (%d mounted)", #g_AddcontStatus, #folders))
end
if Platform.appstore then
local content = AppStore.ListDownloadedContent()
for i=1, #content do
local folder = "Dlc" .. i
local err = MountPack(folder, content[i].path)
if not err then
folders[#folders+1] = folder
end
end
end
if Platform.xbox then
local list
error, list = Xbox.EnumerateLocalDlcs()
if not error then
for idx = 1, #list do
local folders_index = #folders+1
local err, mountDir = AsyncXboxMountDLC(list[idx][1])
if not err then
err = MountPack("Dlc" .. folders_index, mountDir .. "/content.hpk")
error = error or err
if not err then
folders[folders_index] = "Dlc" .. folders_index
end
end
end
end
end
if Platform.windows_store then
local err, list = WindowsStore.MountDlcs()
if not err then
for i=1, #list do
local folder = list[i]
local folders_index = #folders+1
err = MountPack("Dlc" .. folders_index, folder .. "/content.hpk")
if not err then
folders[folders_index] = "Dlc" .. folders_index
end
end
end
end
if not DlcFolders then -- Load the embedded DLCs only once
if Platform.developer and IsFSUnpacked() then
local dev_list = Platform.developer and IsFSUnpacked() and io.listfiles("svnProject/Dlc/", "*", "folders") or empty_table
for _, folder in ipairs(dev_list) do
local dlc = string.gsub(folder, "svnProject/Dlc/", "")
if not (LocalStorage.DisableDLC and LocalStorage.DisableDLC[dlc]) then
folders[#folders + 1] = folder
end
end
else
local files = io.listfiles("AppData/DLC/", "*.hpk", "non recursive") or {}
table.iappend(files, io.listfiles("DLC/", "*.hpk", "non recursive"))
if Platform.linux then
table.iappend(files, io.listfiles("dlc/", "*.hpk", "non recursive"))
end
if Platform.pgo_train then
table.iappend(files, io.listfiles("../win32-dlc", "*.hpk", "non recursive"))
end
dlc_print("Dlc os packs: ", files)
for i=1,#files do
local folder = "Dlc" .. tostring(#folders+1)
local err = MountPack(folder, files[i])
if not err then
table.insert(folders, folder)
end
end
end
end
dlc_print("Dlc folders: ", folders)
return folders, error
end
-- 2. Execute autorun.lua and revisions.lua
function DlcAutoruns(folders)
dlc_print("Dlc Autoruns")
local dlcs = {}
-- dlc.folder points to the autorun mount
for i = 1, #folders do
local folder = folders[i]
local dlc = dofile(folder .. "/autorun.lua")
if type(dlc) == "function" then
dlc = dlc(folder)
end
if type(dlc) == "table" then
dlc_print("Autorun executed for", dlc.name)
dlc.folder = folder
if Platform.developer and folder:starts_with("svnProject/Dlc") then
dlc.lua_revision, dlc.assets_revision = LuaRevision, AssetsRevision
else
dlc.lua_revision, dlc.assets_revision = dofile(folder .. "/revisions.lua")
end
table.insert(dlcs, dlc)
DebugPrint(string.format("DLC %s loaded, lua revision %d, assets revision %d\n", tostring(dlc.name), dlc.lua_revision or 0, dlc.assets_revision or 0))
else
print("Autorun failed:", folder)
end
end
return dlcs
end
-- 3. Call the dlc:pre_load() to all dlcs. Let a DLC decide that it doesn't want to be installed
function DlcPreLoad(dlcs)
local revision
for i = #dlcs, 1, -1 do
local required_lua_revision = dlcs[i].required_lua_revision
if required_lua_revision and required_lua_revision <= LuaRevision then
required_lua_revision = nil -- the required revision is lower, ignore condition
end
revision = Max(revision, required_lua_revision)
local pre_load = dlcs[i].pre_load or empty_func
if required_lua_revision or pre_load(dlcs[i]) == "remove" then
dlc_print("Dlc removed:", dlcs[i].name, required_lua_revision or "")
table.remove_value(DlcFolders, dlcs[i].folder)
table.remove(dlcs, i)
end
end
return revision
end
function GetDlcRequiresTitleUpdateMessage()
local id = TGetID(MessageText.DlcRequiresUpdate)
if id and TranslationTable[id] then
return TranslationTable[id]
end
-- fallback
local language, strMessage = GetLanguage(), nil
if language == "French" then
strMessage = "Certains contenus téléchargeables nécessitent l'installation d'une mise à jour du jeu pour fonctionner."
elseif language == "Italian" then
strMessage = "Alcuni contenuti scaricabili richiedono un aggiornamento del titolo per essere utilizzati."
elseif language == "German" then
strMessage = "Bei einigen Inhalten zum Herunterladen ist ein Update notwendig, damit sie funktionieren."
elseif language == "Spanish" or language == "Latam" then
strMessage = "Ciertos contenidos descargables requieren una actualización para funcionar."
elseif language == "Polish" then
strMessage = "Część zawartości do pobrania wymaga aktualizacji gry."
elseif language == "Russian" then
strMessage = "Загружаемый контент требует обновления игры."
else
strMessage = "Some downloadable content requires a title update in order to work."
end
return strMessage
end
local function find(dlcs, path, rev, rev_name)
local found
for i = #dlcs, 1, -1 do
local dlc = dlcs[i]
if dlc[rev_name] > rev and io.exists(dlc.folder .. path) then
rev = dlc[rev_name]
found = dlc
end
end
if found then
return found.folder .. path, found
end
end
-- 4. If necessary reload localization, lua and data from the lasest packs (it can update the follow up Dlc load steps)
function DlcReloadLua(dlcs, late_dlc_reload)
local lang_reload
local reload = late_dlc_reload
-- mount latest localization
local lang_pack = find(dlcs, "/Local/" .. GetLanguage() .. ".hpk", LuaRevision, "lua_revision")
if lang_pack then
dlc_print(" - localization:", lang_pack)
MountPack("", lang_pack, "", "CurrentLanguage")
lang_reload = true
end
-- English language for e.g. the Mod Editor on PC
if config.GedLanguageEnglish then
local engl_pack = find(dlcs, "/Local/English.hpk", LuaRevision, "lua_revision")
if engl_pack then
MountPack("", engl_pack, "", "EnglishLanguage")
end
end
-- reload entities
local binassets_path = "/BinAssets.hpk"
local binassets_pack = find(dlcs, binassets_path, AssetsRevision, "assets_revision")
if binassets_pack then
dlc_print(" - BinAssets:", binassets_pack)
UnmountByPath("BinAssets")
local err = MountPack("BinAssets", binassets_pack)
dlc_print(" - BinAssets:", binassets_pack, "ERROR", err)
ReloadEntities("BinAssets/entities.dat")
ReloadTextureHeaders()
reload = true
end
-- reload Lua
if late_dlc_reload then -- clean the global tables to prevent duplication
Presets = {}
ClassDescendants("Preset", function(name, class)
if class.GlobalMap then
_G[class.GlobalMap] = {}
end
end)
end
local lua_pack, dlc = find(dlcs, "/Lua.hpk", LuaRevision, "lua_revision")
if lua_pack then
dlc_print(" - lua:", dlc.folder .. "/Lua.hpk")
assert(not config.RunUnpacked)
UnmountByLabel("Lua")
LuaPackfile = lua_pack
reload = true
end
local data_pack, dlc = find(dlcs, "/Data.hpk", LuaRevision, "lua_revision")
if data_pack then
assert(io.exists(dlc.folder .. "/Data.hpk"))
UnmountByLabel("Data")
DataPackfile = data_pack
end
for i = 1, #dlcs do
if io.exists(dlcs[i].folder .. "/Code/") then
reload = true
break
end
end
reload = reload or config.Mods and next(ModsLoaded)
if reload then
ReloadLua(true)
end
if lang_reload and not reload then
LoadTranslationTables()
end
end
function DlcMountVoices(dlcs, skip_sort)
UnmountByLabel("DlcVoices")
if not dlcs then return end
-- Mount all available voices packs in the multi (order by assets revision in case we want to fix a voice from one DLC from a later one)
local sorted_dlcs
if not skip_sort then
sorted_dlcs = table.copy(dlcs)
table.stable_sort(sorted_dlcs, function (a, b) return a.assets_revision < b.assets_revision end)
end
for i, dlc in ipairs(sorted_dlcs or dlcs) do
local voice_pack = string.format("%s/Local/Voices/%s.hpk", dlc.folder, GetVoiceLanguage())
if MountPack("CurrentLanguage/Voices", voice_pack, "seethrough,label:DlcVoices") then
dlc_print(" - localization voice: ", voice_pack)
end
end
end
function DlcMountMapPacks(dlcs)
for _, dlc in ipairs(dlcs) do
for _, map_pack in ipairs(io.listfiles(dlc.folder .. "/Maps", "*.hpk")) do
local map_name = string.match(map_pack, ".*/Maps/([^/]*).hpk")
if map_name then
MapPackfile[map_name] = map_pack
end
end
end
end
function DlcMountUI(dlcs)
local asset_path = dlcs.folder .. "/UI/"
if io.exists(asset_path) then
local err = MountFolder("UI", asset_path, "seethrough")
dlc_print(" - UI:", asset_path, "ERROR", err)
end
end
function DlcMountNonEntityTextures(dlcs)
local asset_path = find(dlcs, "/AdditionalNETextures.hpk", AssetsRevision, "assets_revision")
if asset_path then
UnmountByLabel("AdditionalNETextures")
local err = MountPack("", asset_path, "priority:high,seethrough,label:AdditionalNETextures")
dlc_print(" - non-entity textures:", asset_path, "ERROR", err)
end
end
function DlcMountAdditionalEntityTextures(dlcs)
local asset_path = find(dlcs, "/AdditionalTextures.hpk", AssetsRevision, "assets_revision")
if asset_path then
UnmountByLabel("AdditionalTextures")
local err = MountPack("", asset_path, "priority:high,seethrough,label:AdditionalTextures")
dlc_print(" - entity textures:", asset_path, "ERROR", err)
end
end
function DlcMountSounds(dlcs)
local asset_path = dlcs.folder .. "/Sounds/"
if io.exists(asset_path) then
local err = MountFolder("Sounds", asset_path, "seethrough")
dlc_print(" - Sounds:", asset_path, "ERROR", err)
end
end
function DlcMountMeshesAndAnimations(dlcs)
local meshes_pack = find(dlcs, "/Meshes.hpk", AssetsRevision, "assets_revision")
if meshes_pack then
dlc_print(" - Meshes:", meshes_pack)
UnmountByPath("Meshes")
MountPack("Meshes", meshes_pack)
else
-- If we reload DLCs in packed mode, make sure to have the original meshes first
if MountsByPath("Meshes") == 0 and not IsFSUnpacked() then
MountPack("Meshes", "Packs/Meshes.hpk")
end
end
local animations_pack = find(dlcs, "/Animations.hpk", AssetsRevision, "assets_revision")
if animations_pack then
dlc_print(" - Animations:", animations_pack)
UnmountByPath("Animations")
MountPack("Animations", animations_pack)
else
if MountsByPath("Animations") == 0 and not IsFSUnpacked() then
MountPack("Animations", "Packs/Animations.hpk")
end
end
-- mount additional meshes and animations for each DLC
for i, dlc in ipairs(dlcs) do
MountPack("", dlc.folder .. "/DlcMeshes.hpk", "seethrough,label:DlcMeshes")
MountPack("", dlc.folder .. "/DlcAnimations.hpk", "seethrough,label:DlcAnimations")
MountPack("", dlc.folder .. "/DlcSkeletons.hpk", "seethrough,label:DlcSkeletons")
MountPack("BinAssets", dlc.folder .. "/DlcBinAssets.hpk", "seethrough,label:DlcBinAssets")
end
--common assets should be processed before the rest
UnmountByLabel("CommonAssets")
MountPack("", "Packs/CommonAssets.hpk", "seethrough,label:CommonAssets")
end
function DlcReloadShaders(dlcs)
-- box DX9 and DX11 shader packs should be provided or missing
local asset_path, dlc = find(dlcs, "/ShaderCache" .. config.GraphicsApi .. ".hpk", AssetsRevision, "assets_revision")
if asset_path then
dlc_print(" - ShaderCache:", asset_path)
UnmountByPath("ShaderCache")
MountPack("ShaderCache", asset_path, "seethrough,in_mem,priority:high")
-- NOTE: new shader cache will be reloaded not on start up(main menu) but on next map/savegame load
hr.ForceShaderCacheReload = true
end
end
function DlcAddMusic(dlcs)
local asset_path = dlcs.folder .. "/Music/"
if io.exists(asset_path) then
local err = MountFolder("Music/" .. dlc.name, asset_path)
dlc_print(" - Music:", asset_path, "ERROR", err)
Playlists[dlc.name] = PlaylistCreate("Music/" .. dlc.name)
end
end
function DlcAddCubemaps(dlcs)
local asset_path = dlcs.folder .. "/Cubemaps/"
if io.exists(asset_path) then
local err = MountFolder("Cubemaps", asset_path, "seethrough")
dlc_print(" - Cubemaps:", asset_path, "ERROR", err)
end
end
function DlcAddBillboards(dlcs)
local asset_path = dlcs.folder .. "/Textures/Billboards/"
if io.exists(asset_path) then
local err = MountFolder("Textures/Billboards", asset_path, "seethrough")
dlc_print(" - Billboards:", asset_path, "ERROR", err)
end
end
function DlcMountMovies(dlcs)
if IsFSUnpacked() then return end
for _, dlc in ipairs(dlcs) do
local path = dlc.folder .. "/Movies/"
if io.exists(path) then
local err = MountFolder("Movies/", path, "seethrough")
dlc_print(" - DlcMovies:", path, err and "ERROR", err)
end
end
end
function DlcMountBinAssets(dlcs)
if IsFSUnpacked() then return end
for _, dlc in ipairs(dlcs) do
local path = dlc.folder .. "/BinAssets/"
if io.exists(path) then
local err = MountFolder("BinAssets/", path, "seethrough")
dlc_print(" - DlcBinAssets:", path, err and "ERROR", err)
end
end
end
function DlcMountMisc(dlcs)
UnmountByLabel("DlcMisc")
for _, dlc in ipairs(dlcs) do
local path = dlc.folder .. "/Misc/"
if io.exists(path) then
local err = MountFolder("Misc/", path, "seethrough,label:DlcMisc")
dlc_print(" - DlcMisc:", path, err and "ERROR", err)
end
end
end
-- 5. If necessary reload the latest Dlc assets
function DlcReloadAssets(dlcs)
dlcs = table.copy(dlcs)
table.stable_sort(dlcs, function (a, b) return a.assets_revision < b.assets_revision end)
-- mount map packs found in Maps/
DlcMountMapPacks(dlcs)
for _, dlc in pairs(dlcs) do
-- mount the dlc UI
DlcMountUI(dlc)
-- mount the dlc sounds
DlcMountSounds(dlc)
-- mount the dlc music to the default playlist
DlcAddMusic(dlc)
-- mount the dlc cubemaps
DlcAddCubemaps(dlc)
-- mount the dlc billboards
DlcAddBillboards(dlc)
end
-- mount the most recent additional non-entity textures
DlcMountNonEntityTextures(dlcs)
-- mount the most recent additional entity textures
DlcMountAdditionalEntityTextures(dlcs)
-- mount latest meshes and animations plus additional ones in Dlcs
DlcMountMeshesAndAnimations(dlcs)
-- find latest shaders; OpenGL shaders are not reloaded
DlcReloadShaders(dlcs)
-- mount movies
DlcMountMovies(dlcs)
--
DlcMountBinAssets(dlcs)
-- mount Misc
DlcMountMisc(dlcs)
-- mount voices
DlcMountVoices(dlcs, true)
end
-- 6. Call the dlc.post_load() for each dlc
function DlcPostLoad(dlcs)
for _, dlc in ipairs(dlcs) do
if dlc.post_load then dlc:post_load() end
end
end
function DlcErrorHandler(err)
print("DlcErrorHandler", err, GetStack())
end
function WaitInitialDlcLoad() -- does nothing on reloads (like what happens on Xbox)
if not DlcFolders then
WaitMsg("DlcsLoaded")
end
end
function LoadDlcs(force_reload)
if Platform.developer and (LuaRevision == 0 or AssetsRevision == 0) then
for i=1, 50 do
Sleep(50)
if LuaRevision ~= 0 and AssetsRevision ~= 0 then break end
end
if LuaRevision == 0 or AssetsRevision == 0 then
print("Couldn't get LuaRevision or AssetsRevision, DLC loading may be off")
end
end
if DlcFolders and not force_reload then
return
end
if force_reload then
ForceReloadBinAssets()
DlcFolders = false
end
if Platform.appstore then
local err = CopyDownloadedDLCs()
if err then
print("Failed to copy downloaded DLCs", err)
end
end
LoadingScreenOpen("idDlcLoading", "dlc loading", T(808151841545, "Checking for downloadable content... Please wait."))
-- 1. Mount OS packs
local bCorrupt = false
local folders, err = DlcMountOsPacks()
if err == "File is corrupt" then
bCorrupt = true
err = false
end
if err then
DlcErrorHandler(err)
end
local dlcs = DlcAutoruns(folders)
table.stable_sort(dlcs, function (a, b) return a.lua_revision < b.lua_revision end)
UnmountByLabel("Dlc")
local seen_dlcs = {}
for i, dlc in ripairs(dlcs) do
if seen_dlcs[dlc.name] then
table.remove(dlcs, i)
else
seen_dlcs[dlc.name] = true
dlc.title = dlc.title or dlc.display_name and _InternalTranslate(dlc.display_name) or dlc.name
if not dlc.folder:starts_with("svnProject/Dlc/") then
local org_folder = dlc.folder
dlc.folder = "Dlc/" .. dlc.name
MountFolder(dlc.folder, org_folder, "priority:high,label:Dlc")
end
end
end
DlcFolders = table.map(dlcs, "folder")
DlcDefinitions = table.copy(dlcs)
local bRevision = DlcPreLoad(dlcs)
dlc_print("Dlc tables after preload:\n", table.map(dlcs, "name"))
if config.Mods then
-- load mod items in the same loading screen
ModsReloadDefs()
ModsReloadItems(nil, nil, true)
end
DlcReloadLua(dlcs, force_reload)
DlcReloadAssets(dlcs)
local metaCheck = const.PrecacheDontCheck
if Platform.test then
metaCheck = Platform.pc and const.PrecacheCheckUpToDate or const.PrecacheCheckExists
end
for _, dlc in ipairs(dlcs) do
ResourceManager.LoadPrecacheMetadata("BinAssets/resources-" .. dlc.name .. ".meta", metaCheck)
end
DlcPostLoad(dlcs)
-- Collect and translate the DLC display names.
-- We are just after the step that would reload the localization, so this would handle the case
-- where a DLC display name is translated in the new DLC-provided localization
local dlc_names = GetAvailableDlcList()
for i=1, #dlc_names do
local dlc_metadata = table.find_value(dlcs, "name", dlc_names[i])
assert(dlc_metadata)
local display_name = dlc_metadata.display_name
if display_name then
if not IsT(display_name) or not TGetID(display_name) then
print("DLC", dlc_names[i], "display_name must be a localized T!")
end
display_name = _InternalTranslate(display_name)
assert(type(display_name)=="string")
g_DlcDisplayNames[ dlc_names[i] ] = display_name
end
end
local dlc_names = GetAvailableDlcList()
if next(dlc_names) then
local infos = {}
for i=1, #dlc_names do
local dlcname = dlc_names[i]
infos[i] = string.format("%s(%s)", dlcname, g_DlcDisplayNames[dlcname] or "")
end
print("Available DLCs:", table.concat(infos, ","))
end
Msg("DlcsLoaded")
LoadData(dlcs)
if config.Mods and next(ModsLoaded) then
ContinueModsReloadItems()
end
if not Platform.developer then
if not config.Mods or not Platform.pc then -- the mod creation (available on PC only) needs the data and lua sources to be able to copy functions
UnmountByLabel("Lua")
UnmountByLabel("Data")
end
end
-- Messages should be shown after LoadData(), as there are UI presets that need to be present
local interactive = not (Platform.developer and GetIgnoreDebugErrors())
if interactive then
if bCorrupt then
WaitMessage(GetLoadingScreenDialog() or terminal.desktop, "", T(619878690503, --[[error_message]] "A downloadable content file appears to be damaged and cannot be loaded. Please delete it from the Memory section of the Dashboard and download it again."), nil, terminal.desktop)
end
if bRevision then
local message = Untranslated(GetDlcRequiresTitleUpdateMessage())
WaitMessage(GetLoadingScreenDialog() or terminal.desktop, "", message)
end
end
LoadingScreenClose("idDlcLoading", "dlc loading")
UIL.Invalidate()
end
function LoadData(dlcs)
PauseInfiniteLoopDetection("LoadData")
collectgarbage("collect")
collectgarbage("stop")
Msg("DataLoading")
MsgClear("DataLoading")
LoadPresetFiles("CommonLua/Data")
LoadPresetFolders("CommonLua/Data")
ForEachLib("Data", function (lib, path)
LoadPresetFiles(path)
LoadPresetFolders(path)
end)
LoadPresetFolder("Data")
for _, dlc in ipairs(dlcs or empty_table) do
LoadPresetFolder(dlc.folder .. "/Presets")
end
Msg("DataPreprocess")
MsgClear("DataPreprocess")
Msg("DataPostprocess")
MsgClear("DataPostprocess")
Msg("DataLoaded")
MsgClear("DataLoaded")
DataLoaded = true
local mem = collectgarbage("count")
collectgarbage("collect")
collectgarbage("restart")
-- printf("Load Data mem %dk, peak %dk", collectgarbage("count"), mem)
ResumeInfiniteLoopDetection("LoadData")
end
function WaitDataLoaded()
if not DataLoaded then
WaitMsg("DataLoaded")
end
end
if Platform.xbox then
local oldLoadDlcs = LoadDlcs
function LoadDlcs(...)
SuspendSigninChecks("load dlcs")
SuspendInviteChecks("load dlcs")
sprocall(oldLoadDlcs, ...)
ResumeSigninChecks("load dlcs")
ResumeInviteChecks("load dlcs")
end
end
function OnMsg.BugReportStart(print_func)
local list = GetAvailableDlcList()
table.sort(list)
print_func("Dlcs: " .. table.concat(list, ", "))
end
function DlcComboItems(additional_item)
local items = {{ text = "", value = ""}}
for _, def in ipairs(DlcDefinitions) do
if not def.deprecated then
local name, title = def.name, def.title
if name ~= title then
title = name .. " (" .. title .. ")"
end
items[#items + 1] = {text = title, value = name}
end
end
if additional_item then
table.insert(items, 2, additional_item)
end
return items
end
function DlcCombo(additional_item)
return function()
return DlcComboItems(additional_item)
end
end
function RedownloadContent(list, progress)
if not NetIsConnected() then return "disconnected" end
progress(0)
AsyncCreatePath("AppData/DLC")
AsyncCreatePath("AppData/DownloadedDLC")
for i = 1, #list do
local dlc_name = list[i]
local name = dlc_name .. ".hpk"
local download_file = string.format("AppData/DownloadedDLC/%s.download", dlc_name)
local dlc_file = string.format("AppData/DLC/%s.hpk", dlc_name)
local err, def = NetCall("rfnGetContentDef", name)
if not err and def then
local err, local_def = CreateContentDef(download_file, def.chunk_size)
if err == "Path Not Found" or err == "File Not Found" then
err, local_def = CreateContentDef(dlc_file, def.chunk_size)
end
if local_def then local_def.name = name end
local start_progress = 100 * (i - 1) / #list
local file_progress = 100 * i / #list - start_progress
start_progress = start_progress + file_progress / 10
progress(start_progress)
err = NetDownloadContent(download_file, def,
function (x, y)
progress(start_progress + MulDivRound(file_progress * 9 / 10, x, y))
end,
local_def)
if not err then
local downloaded_dlc_file = string.format("AppData/DownloadedDLC/%s.hpk", dlc_name)
os.remove(downloaded_dlc_file)
os.rename(download_file, downloaded_dlc_file)
end
end
progress(100 * i / #list)
end
end
function CopyDownloadedDLCs()
AsyncCreatePath("AppData/DLC")
AsyncCreatePath("AppData/DownloadedDLC")
local err, new_dlcs = AsyncListFiles("AppData/DownloadedDLC", "*.hpk", "relative")
if err then return err end
for i = 1, #new_dlcs do
local src = "AppData/DownloadedDLC/" .. new_dlcs[i]
if not AsyncCopyFile(src, "AppData/DLC/" .. new_dlcs[i], "raw") then
AsyncFileDelete(src)
end
end
end
function DlcsLoadCode()
for i = 1, #(DlcFolders or "") do
dofolder(DlcFolders[i] .. "/Code/")
end
end
function ReloadDevDlcs()
CreateRealTimeThread(function()
OpenPreGameMainMenu()
DlcFolders = false
for dlc in pairs(LocalStorage.DisableDLC or empty_table) do
g_AvailableDlc[dlc] = nil
end
SaveLocalStorage()
ClassDescendants("Preset", function(name, preset, Presets)
--purge presets, which are saved in Data, we are reloading it
if preset:GetSaveFolder() == "Data" then
if preset.GlobalMap then
_G[preset.GlobalMap] = {}
end
Presets[preset.PresetClass or name] = {}
end
end, Presets)
LoadDlcs("force reload")
end)
end
function SetAllDevDlcs(enable)
local disabled = not enable
LocalStorage.DisableDLC = LocalStorage.DisableDLC or {}
for _, file in ipairs(io.listfiles("svnProject/Dlc/", "*", "folders")) do
local dlc = string.gsub(file, "svnProject/Dlc/", "")
if (LocalStorage.DisableDLC[dlc] or false) ~= disabled then
LocalStorage.DisableDLC[dlc] = disabled
DelayedCall(0, ReloadDevDlcs)
end
end
end
function SaveDLCOwnershipDataToDisk(data, file_path)
local machine_id = GetMachineID()
if (machine_id or "") ~= "" then -- don't save to disk without machine id
data.machine_id = machine_id
--encrypt data and machine id and save to disk
SaveLuaTableToDisk(data, file_path, g_encryption_key)
end
end
function LoadDLCOwnershipDataFromDisk(file_path)
if io.exists(file_path) then
--decrypt the file
local data, err = LoadLuaTableFromDisk(file_path, nil, g_encryption_key)
if not err then
if data and (data.machine_id or "") == GetMachineID() then -- check against current machine id
data.machine_id = nil -- remove the machine_id from the data, no need for it
return data
end
end
end
return {}
end