mirror of
https://github.com/bryanthaboi/gen1recomp.git
synced 2026-08-15 15:51:17 +02:00
dfeacc36b0
- fixed issue with wayland users drag and drop causing CTD
207 lines
6.8 KiB
Lua
207 lines
6.8 KiB
Lua
-- Which games a mod is for. One derivation for the manifest's `games` key,
|
|
-- the legacy `gen2compat` flag, and the labels both mod surfaces draw:
|
|
-- src/mods/LauncherMods.lua and src/mods/ManagerState.lua read this rather
|
|
-- than each keeping its own copy of the rule.
|
|
local GameVersion = require("src.core.GameVersion")
|
|
|
|
local ModTargets = {}
|
|
|
|
-- every version of one generation, in launcher order (GameVersion.ORDER)
|
|
function ModTargets.generationVersions(gen)
|
|
local out = {}
|
|
for _, id in ipairs(GameVersion.ORDER) do
|
|
if GameVersion.generation(id) == gen then out[#out + 1] = id end
|
|
end
|
|
return out
|
|
end
|
|
|
|
-- the generations this engine has games for, ascending
|
|
local function generations()
|
|
local seen, out = {}, {}
|
|
for _, id in ipairs(GameVersion.ORDER) do
|
|
local gen = GameVersion.generation(id)
|
|
if not seen[gen] then
|
|
seen[gen] = true
|
|
out[#out + 1] = gen
|
|
end
|
|
end
|
|
table.sort(out)
|
|
return out
|
|
end
|
|
|
|
-- one manifest token -> the version ids it covers, or nil when it names no
|
|
-- game this engine knows: "red" | "gen1" | "all"
|
|
function ModTargets.expand(token)
|
|
if type(token) ~= "string" then return nil end
|
|
local key = token:lower():match("^%s*(.-)%s*$")
|
|
if key == "all" then return GameVersion.ORDER end
|
|
if GameVersion.VERSIONS[key] then return { key } end
|
|
local gen = key:match("^gen%s*(%d+)$")
|
|
if gen then
|
|
local list = ModTargets.generationVersions(tonumber(gen))
|
|
if #list > 0 then return list end
|
|
end
|
|
return nil
|
|
end
|
|
|
|
-- version-id lists are always ORDER-sorted and deduped, so two manifests that
|
|
-- say the same thing different ways encode and compare the same
|
|
local function fromSet(set)
|
|
local out = {}
|
|
for _, id in ipairs(GameVersion.ORDER) do
|
|
if set[id] then out[#out + 1] = id end
|
|
end
|
|
return out
|
|
end
|
|
|
|
-- normalize a manifest `games` array; second return is the tokens that named
|
|
-- no game, which Manifest reports at its own api level
|
|
function ModTargets.normalize(list)
|
|
local set, unknown = {}, {}
|
|
for _, token in ipairs(type(list) == "table" and list or {}) do
|
|
local ids = ModTargets.expand(token)
|
|
if ids then
|
|
for _, id in ipairs(ids) do set[id] = true end
|
|
else
|
|
unknown[#unknown + 1] = tostring(token)
|
|
end
|
|
end
|
|
return fromSet(set), unknown
|
|
end
|
|
|
|
function ModTargets.union(a, b)
|
|
local set = {}
|
|
for _, list in ipairs({ a or {}, b or {} }) do
|
|
for _, id in ipairs(list) do set[id] = true end
|
|
end
|
|
return fromSet(set)
|
|
end
|
|
|
|
-- The pre-`games` reading of a manifest: Gen 1 always, Gen 2 only where the
|
|
-- author claimed gen2compat (src/mods/Manifest.lua).
|
|
function ModTargets.legacy(gen2compat)
|
|
local out = ModTargets.generationVersions(1)
|
|
if gen2compat then
|
|
return ModTargets.union(out, ModTargets.generationVersions(2))
|
|
end
|
|
return out
|
|
end
|
|
|
|
-- does a version-id list hold any game of that generation
|
|
function ModTargets.covers(versions, gen)
|
|
for _, id in ipairs(versions or {}) do
|
|
if GameVersion.generation(id) == gen then return true end
|
|
end
|
|
return false
|
|
end
|
|
|
|
-- the version ids a validated manifest targets; Manifest.validate resolves
|
|
-- `games` at load, so this is the same answer everywhere
|
|
function ModTargets.versions(manifest)
|
|
local games = manifest and manifest.games
|
|
if type(games) == "table" and #games > 0 then return games end
|
|
return ModTargets.legacy(manifest and manifest.gen2compat)
|
|
end
|
|
|
|
-- Does the mod target this game? `version` is a version id; pass nil with a
|
|
-- generation to ask about a whole generation (the loader's injected seam).
|
|
function ModTargets.supports(manifest, version, generation)
|
|
local versions = ModTargets.versions(manifest)
|
|
if version and GameVersion.VERSIONS[version] then
|
|
for _, id in ipairs(versions) do
|
|
if id == version then return true end
|
|
end
|
|
return false
|
|
end
|
|
return ModTargets.covers(versions, generation or GameVersion.generation())
|
|
end
|
|
|
|
-- What will actually happen here: the loader gates on this same answer, per
|
|
-- version (Loader:_gateGeneration), and the player's override forces past it,
|
|
-- so the two UIs report a run, not a claim.
|
|
function ModTargets.runsHere(manifest, version, generation, forced)
|
|
if forced then return true end
|
|
return ModTargets.supports(manifest, version, generation)
|
|
end
|
|
|
|
-- "Gen 1" / "Gen 1+2" while a mod takes whole generations, the version names
|
|
-- ("Red/Gold") once it takes only some of one
|
|
function ModTargets.label(manifest)
|
|
local versions = ModTargets.versions(manifest)
|
|
local set = {}
|
|
for _, id in ipairs(versions) do set[id] = true end
|
|
local whole, partial = {}, false
|
|
for _, gen in ipairs(generations()) do
|
|
local all, any = true, false
|
|
for _, id in ipairs(ModTargets.generationVersions(gen)) do
|
|
if set[id] then any = true else all = false end
|
|
end
|
|
if any and all then whole[#whole + 1] = tostring(gen)
|
|
elseif any then partial = true end
|
|
end
|
|
if #whole > 0 and not partial then
|
|
return "Gen " .. table.concat(whole, "+")
|
|
end
|
|
local names = {}
|
|
for _, id in ipairs(versions) do
|
|
names[#names + 1] = GameVersion.info(id).label or id
|
|
end
|
|
if #names == 0 then return "No game" end
|
|
return table.concat(names, "/")
|
|
end
|
|
|
|
-- the same label as an all-caps chip, for the launcher tag and the GB font
|
|
function ModTargets.chip(manifest)
|
|
return ModTargets.label(manifest):upper()
|
|
end
|
|
|
|
-- one game's own name, for a line that has to say which one this is
|
|
function ModTargets.gameLabel(version)
|
|
local info = version and GameVersion.info(version)
|
|
return (info and info.label) or tostring(version)
|
|
end
|
|
|
|
-- One launcher-voice line for a mod that does not target `version`
|
|
-- (src/mods/LauncherMods.lua statusFor).
|
|
function ModTargets.detail(manifest, version)
|
|
return ("For %s, not %s"):format(ModTargets.label(manifest),
|
|
ModTargets.gameLabel(version))
|
|
end
|
|
|
|
-- Does a dependency spec apply to this game / version?
|
|
-- If spec.games is provided, it must match version / generation.
|
|
-- If spec.game_version is provided, the engine version must satisfy it.
|
|
function ModTargets.specApplies(spec, version, generation)
|
|
if not spec then return false end
|
|
if type(spec.games) == "table" and #spec.games > 0 then
|
|
if version or generation then
|
|
local match = false
|
|
for _, id in ipairs(spec.games) do
|
|
if version and id == version then
|
|
match = true
|
|
break
|
|
end
|
|
if generation and GameVersion.generation(id) == generation then
|
|
match = true
|
|
break
|
|
end
|
|
end
|
|
if not match then return false end
|
|
end
|
|
end
|
|
if spec.game_version then
|
|
local ok = pcall(function()
|
|
local Semver = require("src.mods.Semver")
|
|
local Version = require("src.core.Version")
|
|
if Version and Version.engine and Version.engine:match("^0%.0%.0%-") == nil then
|
|
return Semver.satisfies(Version.engine, spec.game_version)
|
|
end
|
|
return true
|
|
end)
|
|
if not ok then return false end
|
|
end
|
|
return true
|
|
end
|
|
|
|
return ModTargets
|