v1.3.5: built-in restart offsets, timers set from server uptime at every login (accurate without the DLL)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WyQKCL92ZLwPi9qmYQtNdc
This commit is contained in:
Claude
2026-10-12 12:27:16 -04:00
parent 508afdf1e7
commit 4e8baff0c6
4 changed files with 42 additions and 24 deletions
+5
View File
@@ -1,5 +1,10 @@
# Changelog
## 1.3.5 (12 October 2026)
### New
- **Accurate without the DLL.** OctoBus now ships with each route's restart offset (how many seconds into its trip it docks, counted from the last server restart), measured on 12 October. At every login it asks the server how long it has been up and sets every route it has not seen since that restart from the restart time plus the offset. A brand new copy with no DLL and no sightings gets every timer right from the first login, and stays right after later restarts.
## 1.3.4 (12 October 2026)
### Fixed
+35 -22
View File
@@ -71,25 +71,28 @@ local OB_OK, OB_ERR = pcall(function ()
-- ~5 h (origin = first sighting, anchor = latest), stay at the dock, and where measured
-- on a ride, the far end (flipOffset = seconds after docking here that it docks there).
-- A new copy refines all of this from its own sightings.
-- period = trip length measured over 3 days (400-900 trips). bootPhase = seconds into
-- each trip at which it docks here, counted from the server's last restart (measured
-- 12 Oct 2026): with the server uptime this gives every timer without any sighting.
{ entry = 164871, homeZ = ORG, awayZ = { "Tirisfal Glades", "Undercity" },
name = "Undercity", kind = "zeppelin", x = 1318.1, y = -4658.0,
period = 356.2894, dwell = 64.0, origin = 1791471571.34, anchor = 1791489385.64,
period = 356.2894, bootPhase = 211.9, dwell = 64.0, origin = 1791471571.34, anchor = 1791489385.64,
flipFrom = "Undercity", flipTo = "Orgrimmar", flipOffset = 191.1, flipDwell = 64.0 },
{ entry = 175080, homeZ = ORG, awayZ = { "Stranglethorn Vale" },
name = "Grom'gol", kind = "zeppelin", x = 1360.8, y = -4631.3,
period = 303.4377, dwell = 64.1, origin = 1791471600.26, anchor = 1791489504.28,
period = 303.4377, bootPhase = 55.0, dwell = 64.1, origin = 1791471600.26, anchor = 1791489504.28,
flipFrom = "Grom'gol", flipTo = "Orgrimmar", flipOffset = 138.2, flipDwell = 64.1 },
{ entry = 190552, homeZ = ORG, awayZ = { "Badlands" },
name = "Kargath", kind = "zeppelin", x = 1206.1, y = -4158.7,
period = 373.9861, dwell = 63.9, origin = 1791471857.57, anchor = 1791489438.99,
period = 373.9861, bootPhase = 227.4, dwell = 63.9, origin = 1791471857.57, anchor = 1791489438.99,
flipFrom = "Kargath", flipTo = "Orgrimmar", flipOffset = 198.0, flipDwell = 64.2 },
{ entry = 190549, homeZ = ORG, awayZ = { "Mulgore", "Thunder Bluff" },
name = "Thunder Bluff", kind = "zeppelin", x = 1125.4, y = -4135.0,
period = 566.9955, dwell = 64.2, origin = 1791472003.14, anchor = 1791490140.28,
period = 566.9955, bootPhase = 334.5, dwell = 64.2, origin = 1791472003.14, anchor = 1791490140.28,
flipFrom = "Thunder Bluff", flipTo = "Orgrimmar", flipOffset = 275.8, flipDwell = 64.0 },
{ entry = 190550, homeZ = ORG, awayZ = { "The Hinterlands" },
name = "Sparkwater", kind = "boat", x = 876.1, y = -5204.1, boat = true,
period = 245.0354, dwell = 44.1, origin = 1791471573.69, anchor = 1791489460.91,
period = 245.0354, bootPhase = 168.6, dwell = 44.1, origin = 1791471573.69, anchor = 1791489460.91,
flipFrom = "Revantusk", flipTo = "Sparkwater", flipOffset = 123.2, flipDwell = 44.0 },
-- Grom'gol <-> Undercity zeppelin, timed at the Grom'gol dock (the only end measured).
-- Seen leaving Grom'gol 1791480459.89 and arriving 1791486390.25: 18 cycles of 333.02 s
@@ -97,7 +100,7 @@ local OB_OK, OB_ERR = pcall(function ()
-- is learned on the first ride from Grom'gol.
{ entry = 176495, homeZ = { "Stranglethorn Vale" }, awayZ = { "Tirisfal Glades", "Undercity" },
name = "Undercity", kind = "zeppelin", x = -12406.9, y = 211.8,
period = 333.0015, dwell = 64.0, origin = 1791480395.89, anchor = 1791486390.25,
period = 333.0015, bootPhase = 57.2, dwell = 64.0, origin = 1791480395.89, anchor = 1791486390.25,
flipFrom = "Undercity", flipTo = "Grom'gol" },
-- Ratchet -> Booty Bay boat, timed at the Ratchet dock. Never visible from Orgrimmar, so
-- the row shows when to fly out ("fly") rather than when it docks. Ratchet arrivals
@@ -105,7 +108,7 @@ local OB_OK, OB_ERR = pcall(function ()
-- two days' rides: docks 178.6 s after Ratchet, stays 64.2 s.
{ entry = 20808, homeZ = { "Ratchet" }, awayZ = { "Stranglethorn Vale" }, planZ = ORG,
name = "Ratchet", kind = "boat", x = -1005.6, y = -3841.6, far = true,
period = 364.0298, dwell = 63.7, origin = 1791479926.67, anchor = 1791490117.34,
period = 364.0298, bootPhase = 234.0, dwell = 63.7, origin = 1791479926.67, anchor = 1791490117.34,
flipFrom = "Booty Bay", flipTo = "Ratchet", flipOffset = 178.6, flipDwell = 64.2 },
}
@@ -480,33 +483,43 @@ local OB_OK, OB_ERR = pcall(function ()
DB.bootPhaseBoot[e] = DB.boot
end
local function Phase(r) return DB.bootPhase[r.entry] or r.bootPhase end
local function OnBoot(boot)
local old = DB.boot or DB.bootPrev
DB.boot = boot
DB.bootPrev = nil
if old and math.abs(boot - old) > 300 then
local restarted = old and math.abs(boot - old) > 300
if restarted then
-- the server restarted at 'boot': every route seen before then is off
DB.restartAt = boot
DB.restartRoute = "server uptime"
for i = 1, table.getn(ROUTES) do
local r = ROUTES[i]
local e = r.entry
local P = Period(r)
if DB.bootPhase[e] and P and P > 0 and (DB.seenAt[e] or 0) < boot then
DB.anchor[e] = boot + DB.bootPhase[e]
DB.pW0[e] = (DB.pW0[e] or 0) + (DB.pK[e] or 0)
elseif DB.restartAt and DB.restartAt > boot then
-- same server run: a restart noticed earlier from a jump happened at 'boot'
DB.restartAt = boot
end
-- every route not seen since this restart is put at restart time + its offset (learned,
-- or built in), also on a new copy's very first login
for i = 1, table.getn(ROUTES) do
local r = ROUTES[i]
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
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
-- measurement here, keeping the trip length and the evidence behind it
DB.pW0[e] = (DB.pW0[e] or 700) + (DB.pK[e] or 0)
DB.pP0[e] = P
DB.pK[e] = 0
DB.origin[e] = DB.anchor[e]
DB.pending[e] = nil
DB.lastObs[e] = nil
DB.corrected[e] = boot
if DB.bootTheory then DB.seenAt[e] = boot end -- corrected: "~" instead of "?"
end
DB.corrected[e] = boot
if restarted and DB.bootTheory then DB.seenAt[e] = boot end -- "~" instead of "?"
end
else
-- same server run: a restart noticed earlier from a jump happened at 'boot'
if DB.restartAt and DB.restartAt > boot then DB.restartAt = boot end
end
-- learn offsets from routes already seen since this restart
for i = 1, table.getn(ROUTES) do
@@ -630,7 +643,7 @@ local OB_OK, OB_ERR = pcall(function ()
if k >= 1 and math.abs(resid) < tol then
-- trip length = all evidence weighted by trips covered: earlier server runs
-- (pP0 over pW0 trips) plus this run (delta over k trips)
local W0 = DB.pW0[e] or 0
local W0 = DB.pW0[e] or 700 -- the built-in trip length: ~700 trips measured
local P0 = DB.pP0[e] or P
DB.period[e] = (P0 * W0 + delta) / (W0 + k)
DB.pK[e] = k
@@ -649,7 +662,7 @@ local OB_OK, OB_ERR = pcall(function ()
end
if fits then
-- a new server run: keep the trip length and how much evidence is behind it
DB.pW0[e] = (DB.pW0[e] or 0) + (DB.pK[e] or 0)
DB.pW0[e] = (DB.pW0[e] or 700) + (DB.pK[e] or 0)
DB.pP0[e] = Period(r)
DB.pK[e] = 0
DB.origin[e] = pd
+1 -1
View File
@@ -2,7 +2,7 @@
## Title: |cff33ffccOcto|rBus
## Notes: Zeppelin and boat arrival timers for Orgrimmar. Reads live positions from ZepSense.dll; minimap icon toggles the window.
## Author: Phridgey
## Version: 1.3.4
## Version: 1.3.5
## SavedVariables: OctoBusDB
OctoBus.lua
+1 -1
View File
@@ -91,7 +91,7 @@ Each route runs on a fixed cycle. Once the addon sees one transport arrive, it c
- **`/ob calibrate`** (optional): watches every transport on purpose. Stand between the two towers where you can see the docks, do not `/reload`, and wait; rows are marked complete as each route is confirmed. A transport being out of view for a while is normal. If nothing at all has been seen after about 10 minutes, move closer to the towers. `/ob calibrate stop` cancels.
- Transports are not reported from deep inside the city (bank / auction house area), so calibrate near the towers.
- **Far ends are learned by riding.** When a transport stands still for 20 s away from its home dock, it is docked at the far end: the addon stores when it docked there (relative to its schedule) and how long it stayed. This needs the home end to have been seen earlier in the same session (for example, it leaving Orgrimmar with you on board), and the transport to be seen arriving. No recording is needed.
- **Server restarts.** A restart starts every transport's schedule over. When you log in, OctoBus quietly asks the server how long it has been up (`.server info`) and so knows exactly when it restarted. Each route docks a fixed number of seconds into its trip after a restart; OctoBus learns that once per route, from any sighting, and after later restarts corrects every route straight away from the restart time. Until that has been seen to hold across one restart, corrected routes keep the `?` mark. A sighting that jumps by more than drift can explain also counts as a restart.
- **Server restarts.** A restart starts every transport's schedule over. When you log in, OctoBus quietly asks the server how long it has been up (`.server info`) and so knows exactly when it restarted. Each route docks a fixed number of seconds into its trip after a restart. These offsets are built in, so even without the DLL every route is set from the restart time at each login; with the DLL, OctoBus also re-learns them from its own sightings. Until that has been seen to hold across one restart, corrected routes keep the `?` mark. A sighting that jumps by more than drift can explain also counts as a restart.
- **Both ends keep the timers in sync.** Seeing a transport arrive at, or leave, either end of its route re-syncs that route. At the far end this uses the measured far-end timing; if the home end was already seen in the same session, a far-end arrival sharpens the far-end timing instead.
- **One odd sighting does not wipe a route's history.** A sighting that does not fit the schedule is set aside; the schedule only starts over (for example after a server restart) when a second sighting agrees with it.