From 00aa2060f32ca28067ca511815b45107ee671af0 Mon Sep 17 00:00:00 2001 From: Not Date: Sun, 10 Jul 2022 20:29:05 +0200 Subject: [PATCH] use checksums to identify maps --- leaderboard.lua | 95 +++++++++++++++++++++++++++++++++++++------------ 1 file changed, 72 insertions(+), 23 deletions(-) diff --git a/leaderboard.lua b/leaderboard.lua index 4ceb83e..05a5eaa 100644 --- a/leaderboard.lua +++ b/leaderboard.lua @@ -35,7 +35,7 @@ local StatTrack = false local UNCLAIMED = "Unclaimed Record" local HELP_MESSAGE = "\x89Leaderboard Commands:\nretry exit findmap changelevel spba_clearcheats lb_gui rival scroll encore" -local FILENAME = "leaderboard.txt" +local FILENAME = "leaderboard" -- Retry / changelevel map local nextMap = nil @@ -150,15 +150,36 @@ local cv_interrupt = CV_RegisterVar({ end }) +local function djb2(message) + local digest = 5381 + for c in message:gmatch(".") do + digest = (($ << 5) + $) + string.byte(c) + end + + return digest +end + +local function mapChecksum(mapnum) + local mh = mapheaderinfo[mapnum] + if not mh then + return nil + end + + local digest = string.format("%02x", djb2(mh.lvlttl+mh.subttl+mh.zonttl)) + return string.sub(digest, #digest - 3) +end + local function setST(t, map, flags, scoreTable) local mode = flags & ST_SEP + local cks = mapChecksum(map) t[mode] = t[mode] or {} - t[mode][map] = scoreTable + t[mode][map + (cks or "")] = scoreTable end local function getST(t, map, flags) local mode = flags & ST_SEP - return t[mode] and t[mode][map] or nil + local cks = mapChecksum(map) + return t[mode] and t[mode][map + (cks or "")] or nil end local function setScoreTable(map, flags, scoreTable) @@ -222,7 +243,7 @@ local cv_spb_separate = CV_RegisterVar({ end }) -local function score_t(map, name, skin, color, time, splits, flags, stat) +local function score_t(map, name, skin, color, time, splits, flags, stat, checksum) return { ["map"] = map, ["name"] = name, @@ -231,7 +252,8 @@ local function score_t(map, name, skin, color, time, splits, flags, stat) ["time"] = time, ["splits"] = splits, ["flags"] = flags, - ["stat"] = stat + ["stat"] = stat, + ["checksum"] = checksum } end @@ -253,12 +275,26 @@ local function stat_str(stat) return "0" end +local function writeScore(fh, score) + fh:write( + score["map"], "\t", + score["name"], "\t", + score["skin"], "\t", + score["color"], "\t", + score["time"], "\t", + table.concat(score["splits"], " "), "\t", + score["flags"], "\t", + stat_str(score["stat"]), "\t", + score["checksum"], "\n" + ) +end + -- Read the leaderboard -local f = io.open(FILENAME, "r") +local f = io.open(FILENAME + ".txt", "r") if f then for l in f:lines() do -- Leaderboard is stored in the following tab separated format - -- mapnum, name, skin, color, time, splits, flags, stat + -- mapnum, name, skin, color, time, splits, flags, stat, map_checksum local t = {} for word in (l+"\t"):gmatch("(.-)\t") do table.insert(t, word) @@ -287,17 +323,38 @@ if f then end end + local mapnum = tonumber(t[1]) + + -- Checksums + local cks = t[9] or mapChecksum(mapnum) + + -- We have no previous recognition of this map + -- remove it + if cks == nil then + if cks == nil then + local rsfh = io.open(FILENAME + "_removed_scores.txt", "a") + if not rsfh then + print("Failed to open file: ", FILENAME + "_removed_scores.txt") + continue + end + rsfh:write(l, "\n") + rsfh:close() + continue + end + end + table.insert( scoreTable, score_t( - tonumber(t[1]), + mapnum, t[2], t[3], t[4], tonumber(t[5]), spl, flags, - stats + stats, + cks ) ) @@ -307,7 +364,7 @@ if f then sortScores() f:close() else - print("Failed to open file: ", FILENAME) + print("Failed to open file: ", FILENAME + ".txt") end function allowJoin(v) @@ -1129,7 +1186,8 @@ local function saveTime(player) timeFinished, splits, Flags, - stat_t(player.HMRs or pskin.kartspeed, player.HMRw or pskin.kartweight) + stat_t(player.HMRs or pskin.kartspeed, player.HMRw or pskin.kartweight), + mapChecksum(gamemap) ) -- Check if you beat your previous best @@ -1174,25 +1232,16 @@ local function saveTime(player) StatTrack = true end - local f = assert(io.open(FILENAME, "w")) + local f = assert(io.open(FILENAME + ".txt", "w")) if f == nil then - print("Failed to open file for writing: " + FILENAME) + print("Failed to open file for writing: " + FILENAME + ".txt") return end for _, tbl in pairs(lb) do for _, scoreTable in pairs(tbl) do for _, score in ipairs(scoreTable) do - f:write( - score["map"], "\t", - score["name"], "\t", - score["skin"], "\t", - score["color"], "\t", - score["time"], "\t", - table.concat(score["splits"], " "), "\t", - score["flags"], "\t", - stat_str(score["stat"]), "\n" - ) + writeScore(f, score) end end end