From 00aa2060f32ca28067ca511815b45107ee671af0 Mon Sep 17 00:00:00 2001 From: Not Date: Sun, 10 Jul 2022 20:29:05 +0200 Subject: [PATCH 1/3] 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 -- 2.45.2 From 907c07a25d414360e3243f72de79213b14bd9cb4 Mon Sep 17 00:00:00 2001 From: Not Date: Sun, 10 Jul 2022 20:47:01 +0200 Subject: [PATCH 2/3] resave scores if checksums have been written --- leaderboard.lua | 51 ++++++++++++++++++++++++++++++++----------------- 1 file changed, 33 insertions(+), 18 deletions(-) diff --git a/leaderboard.lua b/leaderboard.lua index 05a5eaa..1509d8a 100644 --- a/leaderboard.lua +++ b/leaderboard.lua @@ -289,9 +289,30 @@ local function writeScore(fh, score) ) end +local function saveScores() + local f = assert(io.open(FILENAME + ".txt", "w")) + if f == nil then + 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 + writeScore(f, score) + end + end + end + + f:close() +end + -- Read the leaderboard local f = io.open(FILENAME + ".txt", "r") if f then + -- track if scores checksums have been written + local checksumWrite = false + for l in f:lines() do -- Leaderboard is stored in the following tab separated format -- mapnum, name, skin, color, time, splits, flags, stat, map_checksum @@ -326,11 +347,14 @@ if f then local mapnum = tonumber(t[1]) -- Checksums - local cks = t[9] or mapChecksum(mapnum) + local cks = t[9] - -- We have no previous recognition of this map - -- remove it if cks == nil then + checksumWrite = true + cks = mapChecksum(mapnum) + + -- We have no previous recognition of this map + -- remove it if cks == nil then local rsfh = io.open(FILENAME + "_removed_scores.txt", "a") if not rsfh then @@ -363,6 +387,11 @@ if f then sortScores() f:close() + + -- save scores + if checksumWrite then + saveScores() + end else print("Failed to open file: ", FILENAME + ".txt") end @@ -1232,21 +1261,7 @@ local function saveTime(player) StatTrack = true end - local f = assert(io.open(FILENAME + ".txt", "w")) - if f == nil then - 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 - writeScore(f, score) - end - end - end - - f:close() + saveScores() end -- DEBUGGING -- 2.45.2 From db0696294b2580ec538821fa24ecbadad4e2f35c Mon Sep 17 00:00:00 2001 From: Not Date: Tue, 19 Jul 2022 21:03:40 +0200 Subject: [PATCH 3/3] 4char padding, do proper string concat on map..checksum --- leaderboard.lua | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/leaderboard.lua b/leaderboard.lua index 1509d8a..bc633b5 100644 --- a/leaderboard.lua +++ b/leaderboard.lua @@ -165,7 +165,7 @@ local function mapChecksum(mapnum) return nil end - local digest = string.format("%02x", djb2(mh.lvlttl+mh.subttl+mh.zonttl)) + local digest = string.format("%04x", djb2(mh.lvlttl+mh.subttl+mh.zonttl)) return string.sub(digest, #digest - 3) end @@ -173,13 +173,13 @@ local function setST(t, map, flags, scoreTable) local mode = flags & ST_SEP local cks = mapChecksum(map) t[mode] = t[mode] or {} - t[mode][map + (cks or "")] = scoreTable + t[mode][tostring(map)..(cks or "")] = scoreTable end local function getST(t, map, flags) local mode = flags & ST_SEP local cks = mapChecksum(map) - return t[mode] and t[mode][map + (cks or "")] or nil + return t[mode] and t[mode][tostring(map)..(cks or "")] or nil end local function setScoreTable(map, flags, scoreTable) -- 2.45.2