Release OctoBus 1.3.9 with persistent window controls

This commit is contained in:
2026-11-08 23:06:57 -04:00
parent bc8591d764
commit 8c5d96ae01
6 changed files with 159 additions and 27 deletions
+105 -15
View File
@@ -502,6 +502,10 @@ local OB_OK, OB_ERR = pcall(function ()
local function OnBoot(boot)
local old = DB.boot or DB.bootPrev
-- the uptime answer is whole seconds, so the same restart can come out a second
-- earlier or later on another ask: keep the first value, or every timer set from it
-- would suddenly count as "seen since the restart"
if DB.boot and math.abs(boot - DB.boot) <= 5 then boot = DB.boot end
DB.boot = boot
DB.bootPrev = nil
local restarted = old and math.abs(boot - old) > 300
@@ -520,7 +524,12 @@ local OB_OK, OB_ERR = pcall(function ()
local e = r.entry
local P = Period(r)
local c = Phase(r)
if c and P and P > 0 and (DB.seenAt[e] or 0) < boot then
-- seenAt within a few seconds of the restart was set by the restart itself (nobody
-- is logged in that early), not by a sighting. A "shared" time that is exactly the
-- old offset again is someone's guess that 1.3.5 passed on as a sighting.
local guessed = DB.src[e] == "shared" and DB.anchor[e] and DB.bootPhaseBoot[e] ~= boot and c
and math.abs(DB.anchor[e] - boot - c) < 2
if c and P and P > 0 and ((DB.seenAt[e] or 0) <= boot + 5 or guessed) then
DB.anchor[e] = boot + c
if not DB.origin[e] or DB.origin[e] < boot then
-- the stored schedule is from an earlier server run: start this run's
@@ -533,13 +542,16 @@ local OB_OK, OB_ERR = pcall(function ()
DB.lastObs[e] = nil
end
DB.corrected[e] = boot
-- a guess, not a sighting: never shared, and a real sighting or shared time replaces it
DB.src[e] = "guess"
if restarted and DB.bootTheory then DB.seenAt[e] = boot end -- "~" instead of "?"
end
end
-- learn offsets from routes already seen since this restart
for i = 1, table.getn(ROUTES) do
local r = ROUTES[i]
if (DB.seenAt[r.entry] or 0) > boot and DB.anchor[r.entry] then LearnPhase(r, DB.anchor[r.entry]) end
local e = r.entry
if (DB.seenAt[e] or 0) > boot + 5 and DB.anchor[e] and DB.src[e] ~= "guess" then LearnPhase(r, DB.anchor[e]) end
end
end
@@ -916,7 +928,7 @@ local OB_OK, OB_ERR = pcall(function ()
local BD_R, BD_G, BD_B = 0.900, 0.850, 0.900
local function CreateBackdrop(f)
f:SetBackdrop({
bgFile = "Interface\\Tooltips\\UI-Tooltip-Background",
bgFile = "Interface\\Buttons\\WHITE8X8",
edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
tile = true, tileSize = 16, edgeSize = 16,
insets = { left = 4, right = 4, top = 4, bottom = 4 },
@@ -1004,6 +1016,17 @@ local OB_OK, OB_ERR = pcall(function ()
panel:EnableMouse(true)
CreateBackdrop(panel)
panel.goldBar = panel:CreateTexture(nil, "ARTWORK")
panel.goldBar:SetTexture("Interface\\PaperDollInfoFrame\\UI-Character-General-TopLeft")
panel.goldBar:SetTexCoord(80/256, 255/256, 18/256, 32/256)
panel.goldBar:SetPoint("TOPLEFT", panel, "TOPLEFT", 4, -4)
panel.goldBar:SetPoint("TOPRIGHT", panel, "TOPRIGHT", -4, -4)
panel.goldBar:Hide()
local function MapAttached()
return CFG.snapMap and ShaguTweaks and ShaguTweaks.WorldMapWindowActive and WorldMapFrame
end
panel.title = panel:CreateFontString(nil, "OVERLAY")
panel.title:SetFont(font, 13)
panel.title:SetPoint("TOP", panel, "TOP", 0, -8)
@@ -1024,8 +1047,13 @@ local OB_OK, OB_ERR = pcall(function ()
local function PlaceDivider(y, a)
panel.divL:SetPoint("TOPLEFT", panel, "TOPLEFT", 10, y)
panel.divR:SetPoint("TOPRIGHT", panel, "TOPRIGHT", -10, y)
panel.divL:SetGradientAlpha("HORIZONTAL", 0.8, 0.8, 0.8, 0, 0.8, 0.8, 0.8, a)
panel.divR:SetGradientAlpha("HORIZONTAL", 0.8, 0.8, 0.8, a, 0.8, 0.8, 0.8, 0)
local r, g, b = .8, .8, .8
if ShaguTweaks and ShaguTweaks.GoldMode and not ShaguTweaks.DarkMode then
local edge = ShaguTweaks.UIBorder
r, g, b = edge and edge.r or .8, edge and edge.g or .62, edge and edge.b or .32
end
panel.divL:SetGradientAlpha("HORIZONTAL", r, g, b, 0, r, g, b, a)
panel.divR:SetGradientAlpha("HORIZONTAL", r, g, b, a, r, g, b, 0)
end
panel.status = panel:CreateFontString(nil, "OVERLAY")
@@ -1040,7 +1068,30 @@ local OB_OK, OB_ERR = pcall(function ()
-- The window is pinned by one corner (CFG.anchor, set in the settings window; default
-- bottom-left), so when the list gets longer or shorter the other edges move.
local function SaveMapOffset()
if not MapAttached() then return end
local left, top = panel:GetLeft(), panel:GetTop()
local ml, mt = WorldMapFrame:GetLeft(), WorldMapFrame:GetTop()
if not left or not top or not ml or not mt then return end
local ratio = WorldMapFrame:GetEffectiveScale() / panel:GetEffectiveScale()
CFG.mapX = left - ml * ratio
CFG.mapY = top - mt * ratio
end
local function AnchorToMap()
if not MapAttached() then return end
if not CFG.mapX or not CFG.mapY then SaveMapOffset() end
if not CFG.mapX or not CFG.mapY then return end
panel:ClearAllPoints()
panel:SetPoint("TOPLEFT", WorldMapFrame, "TOPLEFT", CFG.mapX, CFG.mapY)
end
local function SavePos()
if MapAttached() then
SaveMapOffset()
AnchorToMap()
return
end
local a = CFG.anchor or "BOTTOMLEFT"
local x = string.find(a, "RIGHT") and panel:GetRight() or panel:GetLeft()
local y = string.find(a, "TOP") and panel:GetTop() or panel:GetBottom()
@@ -1112,7 +1163,7 @@ local OB_OK, OB_ERR = pcall(function ()
local l, t = panel:GetLeft(), panel:GetTop()
panel:SetScale(sc)
CFG.scale = sc
if l and t then
if l and t and not MapAttached() then
local newEff = panel:GetEffectiveScale()
panel:ClearAllPoints()
panel:SetPoint("TOPLEFT", UIParent, "BOTTOMLEFT", l * oldEff / newEff, t * oldEff / newEff)
@@ -1312,6 +1363,21 @@ local OB_OK, OB_ERR = pcall(function ()
ROW_H = math.floor(18 * textScale + 0.5)
TOP = math.floor(14 + 18 * textScale + 0.5)
panel:SetWidth(WIDTH)
panel.goldBar:SetHeight(TOP - 9)
if ShaguTweaks and ShaguTweaks.GoldMode and not ShaguTweaks.DarkMode then
local tint = ShaguTweaks.UITint
local mods, translate = ShaguTweaks.mods, ShaguTweaks.T
local golden = mods and translate and mods[translate["Golden UI"]]
local bar = golden and golden.config and golden.config["goldmode.bar"]
-- Same opaque stone artwork and multiplied palette as ShaguDPS.
panel.goldBar:SetVertexColor(
(tint and tint.r or 1) * (bar and bar.r or .8),
(tint and tint.g or .78) * (bar and bar.g or .63),
(tint and tint.b or .4) * (bar and bar.b or .62), wa)
panel.goldBar:Show()
else
panel.goldBar:Hide()
end
StyleText(panel.title, math.floor(13 * textScale + 0.5))
PlaceDivider(-(TOP - 5), 0.6 * math.min(1, bg + 0.25) * wa)
StyleText(panel.status, math.floor(9 * textScale + 0.5))
@@ -1495,6 +1561,10 @@ local OB_OK, OB_ERR = pcall(function ()
end
local function PlacePanel()
if MapAttached() then
AnchorToMap()
return
end
panel:ClearAllPoints()
if CFG.pos then
panel:SetPoint(CFG.pos.a or "BOTTOMLEFT", UIParent, "BOTTOMLEFT", CFG.pos.x, CFG.pos.y)
@@ -1521,16 +1591,17 @@ local OB_OK, OB_ERR = pcall(function ()
end
-- override: nil = automatic, "show" = forced open anywhere, "hide" = forced closed.
-- Crossing into or out of the auto-show area puts it back to automatic.
-- Manual choices persist until toggled again or /ob resetpos restores auto mode.
local override = nil
local lastArea = nil
local attached, goldMode = nil, nil
local function ApplyVisibility()
local area = InOrg()
if area ~= lastArea then
lastArea = area
override = nil
end
override = CFG.visibility
local map = MapAttached() and true or false
local gold = ShaguTweaks and ShaguTweaks.GoldMode and not ShaguTweaks.DarkMode and true or false
if map ~= attached then attached = map PlacePanel() end
if gold ~= goldMode then goldMode = gold ApplyLook() end
local want
if override == "show" then want = true
elseif override == "hide" then want = false
@@ -1550,6 +1621,7 @@ local OB_OK, OB_ERR = pcall(function ()
local function ToggleShown()
if panel:IsShown() then override = "hide" else override = "show" end
CFG.visibility = override
ApplyVisibility()
end
@@ -1764,6 +1836,7 @@ local OB_OK, OB_ERR = pcall(function ()
CFG.angle = nil
PlaceButton()
override = nil
CFG.visibility = nil
panel:Hide()
ApplyVisibility()
Say("window and minimap icon moved back to their default spots, auto mode restored.")
@@ -1797,6 +1870,7 @@ local OB_OK, OB_ERR = pcall(function ()
else
local n = CalStart()
override = "show"
CFG.visibility = override
ApplyVisibility()
Say("calibrating " .. n .. " transports. Stand where you can see the docks (between the two towers), do not /reload, and wait.")
Say("each transport needs " .. "1 fresh arrival (2 the first time). Rows turn + when done. /ob calibrate stop cancels.")
@@ -1851,6 +1925,7 @@ local OB_OK, OB_ERR = pcall(function ()
recZone, recTaxi = nil, nil
recOn = true
override = "show"
CFG.visibility = override
ApplyVisibility()
Say("recording every transport the DLL reports. /ob debug off to stop; log out or /reload to save it.")
else
@@ -1922,7 +1997,7 @@ local OB_OK, OB_ERR = pcall(function ()
for i = 1, table.getn(ROUTES) do
local e = ROUTES[i].entry
local a = DB.anchor[e]
if a and a > DB.boot and (DB.seenAt[e] or 0) > DB.boot and (DB.src[e] == "dll" or (not own and DB.src[e] == "shared")) then
if a and a > DB.boot and (DB.seenAt[e] or 0) > DB.boot + 5 and (DB.src[e] == "dll" or (not own and DB.src[e] == "shared")) then
table.insert(parts, e .. ":" .. string.format("%.1f", a - DB.boot))
end
end
@@ -1947,7 +2022,11 @@ local OB_OK, OB_ERR = pcall(function ()
if not r or not DB.boot or not CFG.share then return end
if rel < 0 or rel > time() - DB.boot + 600 then return end
-- our own DLL sighting in this run wins
if DB.src[e] == "dll" and (DB.seenAt[e] or 0) > DB.boot then return end
if DB.src[e] == "dll" and (DB.seenAt[e] or 0) > DB.boot + 5 then return end
-- a time that is just the restart offset again is someone's guess passed on as a
-- sighting (OctoBus 1.3.5 did that): ignore it
local c = DB.bootPhaseBoot[e] ~= DB.boot and Phase(r)
if c and math.abs(rel - c) < 2 then return end
local a = DB.boot + rel
if DB.src[e] == "shared" and DB.anchor[e] and math.abs(DB.anchor[e] - a) < 0.5 then return end
local P = Period(r)
@@ -2025,7 +2104,18 @@ local OB_OK, OB_ERR = pcall(function ()
cfg = CFG,
ApplyLook = function() ApplyLook() Refresh() end,
Refresh = function() Refresh() end,
Show = function() override = "show" ApplyVisibility() end,
Show = function() CFG.visibility = "show" ApplyVisibility() end,
SetSnapMap = function(v)
if v then
CFG.snapMap = true
SaveMapOffset()
AnchorToMap()
else
CFG.snapMap = false
-- Keep the current screen position when detaching too.
SavePos()
end
end,
SetAnchor = function(a)
CFG.anchor = a
if panel:GetLeft() then SavePos() end -- keeps the window where it is, pinned by the new corner