- Copy
addon_bs.lua
togarrysmod/lua
- Edit
garrysmod/lua/menu/menu.lua
and addto the end of itinclude("addon_bs.lua")
- Open/restart gmod
- Type
abs start 107821465
into console before starting a game - The script will automatically mount and unmount addons for you. You will need to handle starting new games / restarting gmod yourself. (It will remember where it is across reboots)
- Use
abs restore
to put everything back where it was at the end
Last active
March 21, 2023 00:17
-
-
Save Lexicality/df4af28e4f05312dbfd0136211859a9c to your computer and use it in GitHub Desktop.
Binary search utility for finding troublesome addons
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
--[[ | |
Addon Binary Searcher | |
Copyright 2018 Lex Robinson | |
Licensed under the Apache License, Version 2.0 (the "License"); | |
you may not use this file except in compliance with the License. | |
You may obtain a copy of the License at | |
http://www.apache.org/licenses/LICENSE-2.0 | |
Unless required by applicable law or agreed to in writing, software | |
distributed under the License is distributed on an "AS IS" BASIS, | |
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
See the License for the specific language governing permissions and | |
limitations under the License. | |
--]] | |
print("Addon binary search script active") | |
local print_ = print | |
local function print(...) | |
print_("ABS:", ...) | |
end | |
local function f(s, ...) | |
return s:format(...) | |
end | |
local function printf(...) | |
return print(f(...)) | |
end | |
local function json_encode(value) | |
if type(value) ~= "table" then | |
value = { _a="a", value } | |
end | |
return util.TableToJSON(value) | |
end | |
local function json_decode(str) | |
value = util.JSONToTable(str) | |
if value and value._a == "a" then | |
return value[1] | |
end | |
return value | |
end | |
local function db_setup() | |
sql.Query("CREATE TABLE IF NOT EXISTS addon_bs (key TEXT PRIMARY KEY, value BLOB)") | |
end | |
local function db_get(key, default) | |
local v = sql.QueryValue(f("SELECT value FROM addon_bs WHERE key=%s", sql.SQLStr(key))) | |
if v == false then | |
error(sql.LastError()) | |
end | |
if v then | |
return json_decode(v) | |
else | |
return default | |
end | |
end | |
local function db_delete(key) | |
key = sql.SQLStr(key) | |
local r = sql.Query(f("DELETE FROM addon_bs WHERE key=%s", key)) | |
if r == false then | |
error(sql.LastError()) | |
end | |
end | |
local function db_set(key, value) | |
if value == nil then | |
db_delete(key) | |
end | |
key = sql.SQLStr(key) | |
value = sql.SQLStr(json_encode(value)) | |
local r = sql.Query(f("INSERT OR REPLACE INTO addon_bs (key, value) VALUES (%s, %s)", key, value)) | |
if r == false then | |
error(sql.LastError()) | |
end | |
end | |
local function get_enabled_addons(not_this_one) | |
local ids = {} | |
for _, addon in pairs(engine.GetAddons()) do | |
if addon.mounted then | |
-- Sanity check | |
if addon.wsid == "0" then | |
ErrorNoHalt(f("Unexpected non workshop gma %q from %q found!", addon.title, addon.file)) | |
elseif addon.wsid ~= not_this_one then | |
table.insert(ids, addon.wsid) | |
end | |
end | |
end | |
return ids | |
end | |
local ADDON_NAMES = {} | |
local function split(arr) | |
local n = math.floor(#arr/2) | |
return {unpack(arr, 1, n)}, {unpack(arr, n + 1)} | |
end | |
local function abs_test(ids) | |
local test, rest = split(ids) | |
printf("Test narrowed to %d addons", #test) | |
if #test < 10 then | |
for _, id in pairs(test) do | |
print("", ADDON_NAMES[id] or f("??? %s", id)) | |
end | |
end | |
db_set("test", { test = test, rest = rest }) | |
local gold = db_get("golden boy") | |
if not gold then | |
error("everything broke, start again from the beginning") | |
end | |
steamworks.SetShouldMountAddon(gold, true) | |
for _, id in pairs(get_enabled_addons(gold)) do | |
steamworks.SetShouldMountAddon(id, false) | |
end | |
for _, id in pairs(test) do | |
steamworks.SetShouldMountAddon(id, true) | |
end | |
steamworks.ApplyAddons() | |
print("Problem still happening? Use 'abs yes' or 'abs no'.") | |
end | |
local function abs_test_result(which) | |
local test = db_get("test") | |
if not test then | |
print("No test in progress?") | |
return | |
end | |
local ids = test[which] | |
if #ids > 1 then | |
abs_test(ids) | |
else | |
local id = ids[1] | |
printf("Your asshole is: %q (%s)", ADDON_NAMES[id], id) | |
steamworks.ViewFile(id) | |
end | |
end | |
local function abs_yes() | |
abs_test_result("test") | |
end | |
local function abs_no() | |
abs_test_result("rest") | |
end | |
local function abs_start(id) | |
db_setup() | |
if not id then | |
print("Please specify your target addon. EG 'abs start 107821465'") | |
return | |
end | |
for _, addon in pairs(engine.GetAddons()) do | |
ADDON_NAMES[addon.wsid] = addon.title | |
end | |
local name = ADDON_NAMES[id] | |
if not name then | |
printf("Unknown addon %s?", id) | |
return | |
end | |
printf("Trying to find out who is conflicting with %q...", name) | |
db_set("golden boy", id) | |
local ids = get_enabled_addons(id) | |
printf("Testing against the currently enabled %d addons.", #ids) | |
db_set("starting state", ids) | |
abs_test(ids) | |
end | |
local function abs_restore() | |
local starters = db_get("starting state") | |
if not starters then | |
print("No state to restore to?") | |
return | |
end | |
print(("Restoring %s addons"):format(#starters)) | |
for _, id in pairs(starters) do | |
steamworks.SetShouldMountAddon(id, true) | |
end | |
steamworks.ApplyAddons() | |
db_delete("starting state") | |
db_delete("test") | |
end | |
local ACTIONS = { | |
start = abs_start, | |
restore = abs_restore, | |
yes = abs_yes, | |
no = abs_no, | |
} | |
concommand.Add("abs", function(_, _, args, full) | |
local wat = args[1] | |
local func = ACTIONS[wat] | |
if not func then | |
if wat ~= "help" then | |
print("Unknown command '" .. wat .."'") | |
end | |
print("Available commands:") | |
print("", "help") | |
for key in pairs(ACTIONS) do | |
print("", key) | |
end | |
return | |
end | |
func(unpack(args, 2)) | |
end) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment