config_defaults.declare(list)#config_defaults
Moves a saved setting to a new default once, if it still holds the old one.
"requires": { "config_defaults": "^1.0" }local config_defaults = require("lib/config_defaults")Игрокам ставить ничего не нужно: скрипт приносит библиотеку сам, любую версию в пределах диапазона. Правку можно проверить до публикации в dev-сессии, в scripts/lib/config_defaults/.
lib/config_defaults
Moves a saved setting to a new default once, if it still holds the old one. A saved config carries every key, so without this a changed default reaches only a player with no file (#573).
local D = require("lib/config_defaults")
D.declare({ { id = "mypack-range-900", key = "Combo.My pack.Range", from = 800, to = 900 } })
declare at file scope, before on_script_load. uTEA hosts the control and the pass
(scripts/utea.lua); with uTEA off call D.install() at file scope, D.run() from
on_script_load and D.update() from on_update.
A row: id (no comma or tab, never reused), key as config.export() writes it, from the old
default, to the new one. A second move of the same key is a second row after the first. uTEA's
rows are in changes.lua; the table only grows.
The pass, for each row with no mark on the current preset: no control (its pack is off) leaves the
row for a later run. A value equal to from becomes to, logged as [config_defaults] <preset>: <key> <from> -> <to>. Any other value stays. The row is marked either way, the preset is saved if
something moved (autosave may be off). update repeats the pass when config.current() changes.
Marks live in a hidden control (Misc.screen presets.defaults applied, it travels with a copied
file) and in data/config_defaults.txt (survives a build that drops the hidden key). One is
enough. Ids this build does not know stay in the list, they belong to the other channel.
An old file cannot tell "never touched" from "set to the same value": the second case gets the new
default once. After that any value stays, including the old one. A file restored over a preset that
already ran keeps its old values: the mark in data/ says the row is done.
Rename or remove a control and its old key stays in the file (load_config keeps what no control
claims). Never reuse a removed label for another meaning.
Test: tools\lua\lua.exe scripts\lib\config_defaults\selftest.lua.
A default that differs from docs/cfgdef_base.tsv (registration defaults of published 0.10.147)
must be reachable from the base value through rows of changes.lua, or
tools/utea_harness/test_config_defaults_573.lua fails with "default changed with no row". A
control moved by ui.menu_move is found by its old key (defaults_at.lua --was). Rebuilding the
base is never needed for the check to hold; if a later release is taken as the base anyway:
git archive refs/evolve/published/<ver> scripts tools/utea_harness tools/menu_dump.lua | tar -x -C <dir>
tools/lua/lua.exe tools/cfgdef/defaults_at.lua --root <dir> --out d.tsv
then keep the header line and drop the button and icon_grid rows (grids go through
combo_editor).
Код версии 1.0.6, как его получает клиент. Байткод в сборке собран из этих файлов.
init.lua119 строк
-- lib/config_defaults -- a new default reaches a config that already holds the old one.
-- a saved file has every key, so a moved default stops at it. a row in changes.lua moves the
-- value once, only if it still equals the old default; a value set by hand stays. an old file
-- cannot tell "never touched" from "set to the same": that is taken as never touched, once.
-- marks live twice: in the preset (a hidden control, it travels with a copied file) and in
-- data/ (survives a build that drops the hidden key). either one is enough, so a downgrade and
-- a way back never re-run a row. a pack adds its own rows with M.declare.
local M = {}
M.GROUP = "Misc.screen presets"
M.LABEL = "defaults applied"
local SIDECAR = "config_defaults.txt"
local rows, seen_id = {}, {}
local store -- the hidden control
local last -- preset of the last pass
local say = print
function M.declare(list)
for _, r in ipairs(list) do
if not (r.id and r.key) or r.from == nil or r.to == nil or r.id:find("[,\t\n]") then
error("config_defaults: bad row " .. tostring(r.id))
end
local had = seen_id[r.id]
-- a hot reload runs a pack's declare again, the lib stays
if had and (had.key ~= r.key or had.from ~= r.from or had.to ~= r.to) then
error("config_defaults: id twice " .. r.id)
end
if not had then
seen_id[r.id] = r
rows[#rows + 1] = r
end
end
end
local function sidecar_path() return fs.datadir() .. SIDECAR end
-- preset -> { [id] = true }; a torn last line costs nothing
local function read_sidecar()
local out = {}
local ok, text = pcall(fs.read, sidecar_path())
if not ok or not text then return out end
for preset, id in text:gmatch("([^\t\r\n]+)\t([^\t\r\n]+)") do
out[preset] = out[preset] or {}
out[preset][id] = true
end
return out
end
local function same(a, b)
if type(a) ~= type(b) then return false end
if type(a) == "number" then return math.abs(a - b) < 1e-4 end
return a == b
end
local function marks_of(preset)
local on = {}
for id in tostring(store:get() or ""):gmatch("[^,]+") do on[id] = true end
local side = preset ~= "" and read_sidecar()[preset]
if side then for id in pairs(side) do on[id] = true end end
return on
end
-- one pass over the current preset. a row whose control is missing (its pack is off) waits for
-- the run that has it. no file behind the session: every value is the current default, nothing
-- to move, and the marks go along into the first save (a value set there stays). returns how
-- many values moved.
function M.run()
local preset = config.current()
last = preset
if not store then return 0 end
local on, moved, fresh = marks_of(preset), 0, {}
for _, r in ipairs(rows) do
if not on[r.id] and config.has_control(r.key) then
if preset ~= "" and same(config.get(r.key), r.from) then
config.set(r.key, r.to)
moved = moved + 1
say(("[config_defaults] %s: %s %s -> %s"):format(preset, r.key, tostring(r.from), tostring(r.to)))
end
on[r.id] = true
fresh[#fresh + 1] = r.id
end
end
-- every mark goes back, a row this build does not know belongs to the other channel. also
-- the way marks known only to data/ get into a file that travels
local keep = {}
for id in pairs(on) do keep[#keep + 1] = id end
table.sort(keep)
local text = table.concat(keep, ",")
if text ~= tostring(store:get() or "") then store:set(text) end
-- the file before data/: a mark without the value would leave the old value for good.
-- autosave may be off, so not left to it
if moved > 0 then pcall(config.save, preset) end
if preset ~= "" and #fresh > 0 then
local lines = {}
for _, id in ipairs(fresh) do lines[#lines + 1] = preset .. "\t" .. id .. "\n" end
pcall(fs.append, sidecar_path(), table.concat(lines))
end
return moved
end
-- a preset switch: no event for it, the name is watched
function M.update()
if store and config.current() ~= last then M.run() end
end
function M.install(opts)
opts = opts or {}
say = opts.say or say
store = ui.textbox(M.GROUP, M.LABEL, "")
store:visible(false)
return store
end
function M.rows() return rows end
M.declare(require("lib/config_defaults/changes"))
return M
pack.json2 строк
{ "kind": "lib", "version": "1.0.6" }
changes.lua74 строк
-- every default moved on a key a saved config already holds. append only: an id once shipped
-- stays forever, its mark is what keeps a choice from being overwritten.
-- a row is { id, key, from, to }; key as config.export() writes it. a second move of the same
-- key is a second row, from = the first row's to. rows run in order.
-- grids are not here: core/combo_editor.lua has its own marks for new cells.
return {
{ id = "heal-items-on", key = "Combo.Item Manager.7. Heal items at low HP",
from = false, to = true },
{ id = "fog-mark-life-30", key = "Combo.Alerts.Enemy casts in the fog.Mark pales over, seconds",
from = 60, to = 30 },
-- 0 was also Jungle's stack key on every hero. a hotkey reads as its vk here: 0 -> -
{ id = "camp-stacker-key-minus", key = "Combo.Camp Stacker.Keys.1. Controlled Units Stack",
from = 48, to = 189 },
-- #555 step 3: the tile was lit and the module did nothing until a row was ticked
{ id = "dispel-disables-on", key = "Combo.Dispel.02. Dispel Disables (Stuns, Fears, Sleeps)",
from = false, to = true },
{ id = "dispel-silences-on", key = "Combo.Dispel.03. Dispel Silences",
from = false, to = true },
{ id = "dispel-roots-on", key = "Combo.Dispel.04. Dispel Roots",
from = false, to = true },
{ id = "dispel-disarms-on", key = "Combo.Dispel.08. Dispel Disarms",
from = false, to = true },
{ id = "dispel-manta-on", key = "Combo.Dispel.12. Use Manta",
from = false, to = true },
{ id = "dispel-greaves-on", key = "Combo.Dispel.13. Use Greaves",
from = false, to = true },
{ id = "dispel-lotus-on", key = "Combo.Dispel.14. Use Lotus Orb",
from = false, to = true },
{ id = "snatch-runes-on", key = "Combo.Snatcher.Snatch.1. Snatch Runes",
from = false, to = true },
{ id = "snatch-rapier-on", key = "Combo.Snatcher.Snatch.3. Snatch Rapier",
from = false, to = true },
{ id = "snatch-gem-on", key = "Combo.Snatcher.Snatch.4. Snatch Gem",
from = false, to = true },
-- #558: the switch only presses when a cast gains from it; off by hand stays off
{ id = "treads-on", key = "Combo.Power Treads.0. Enabled {{utea}}",
from = false, to = true },
-- #643: in the client its presses inside a cast point do not land, six presses a cast, no mana won
{ id = "treads-off", key = "Combo.Power Treads.0. Enabled {{utea}}",
from = true, to = false },
-- #657: the cast waits for the press now, +25 mana an axe q in the client; a hand off after
-- 0.10.150 reads as the 0.10.152 default and turns on too
{ id = "treads-on-657", key = "Combo.Power Treads.0. Enabled {{utea}}",
from = false, to = true },
-- #661: armor reads the engine total now, an axe 25 hit lands x0.63 and 6 s let no life break out
{ id = "huskar-lb-max-kill-95", key = "Combo.Heroes.Huskar.3.4 Longest fight the commitment may buy into (s)",
from = 60, to = 95 },
-- #661: the same, a level 4 wave on an axe 25 lands 91 of 145 and 100 kept the nuke off
{ id = "dazzle-wave-min-damage-50", key = "Combo.Heroes.Dazzle.4.1 Minimum damage before the nuke is worth casting",
from = 100, to = 50 },
-- #669: summons and toggles/autocasts no longer start with no key by default (owner's call)
{ id = "bm-razorback-nokey-off-669", key = "Combo.Heroes.Beastmaster.5. Keep the razorbacks up (no key)",
from = true, to = false },
{ id = "bm-raptors-nokey-off-669", key = "Combo.Heroes.Beastmaster.6. Summon Raptors when there is something to dive (no key)",
from = true, to = false },
{ id = "ld-bear-resummon-off-669", key = "Combo.Heroes.Lone Druid.Bear.1.1 Re-summon the bear when it is gone (no key)",
from = true, to = false },
{ id = "clinkz-searing-keep-off-669", key = "Combo.Heroes.Clinkz.5. Keep Searing Arrows switched on",
from = true, to = false },
{ id = "huskar-spear-autocast-off-669", key = "Combo.Heroes.Huskar.2. Burning Spear autocast",
from = true, to = false },
{ id = "leshrac-nova-nokey-off-669", key = "Combo.Heroes.Leshrac.5.7 Toggle it on with no key held",
from = true, to = false },
{ id = "pudge-rot-nokey-off-669", key = "Combo.Heroes.Pudge.2.4 Auto Rot with no key held",
from = true, to = false },
{ id = "medusa-split-nokey-off-669", key = "Combo.Heroes.Medusa.5.1 Keep it correct with no key held",
from = true, to = false },
{ id = "mars-bulwark-tank-off-669", key = "Combo.Heroes.Mars.5.2 Raise the shield to tank",
from = true, to = false },
-- #669: with no key held the phantasms are the player's, same as phantom lancer's images
{ id = "ck-illusions-nokey-off-669", key = "Combo.Heroes.Chaos Knight.Illusions.5.1 Let them fight with no combo key held",
from = true, to = false },
}
Заметок к версиям нет.
Пока ни один опубликованный скрипт её не требует.
Ещё у этого автора
escape
от hunnycHow many seconds a unit dropped at a point stays out of reach of what saves him: his towers, his fountain, his heroes walking at him, and his heroes in the fog from where `lib/fog_seen` last put them
"requires": { "escape": "^1.0" }local escape = require("lib/escape")menu_form
от hunnycSplits a top group into its main rows and an "Advanced" list.
"requires": { "menu_form": "^1.0" }local menu_form = require("lib/menu_form")screen_presets
от hunnycScreen presets for what evolve draws: "minimum", "usual" and "everything" over the groups the menu lists under the "screen" category (sections over heroes, map, timers, panels; the camera section is l
"requires": { "screen_presets": "^1.0" }local screen_presets = require("lib/screen_presets")