IncludeScript("stringtofile.nut") IncludeScript("contracts.nut") local ___root = getroottable() const MAX_ERRORS = 20 ::___GlobalFixes <- { function NoBoneFollowers() { local mapname = split(GetMapName(), "_") local mapname_len = mapname.len() local mapname_noversion = "" //these maps have animated bits that rely on bone followers //more often than not, mappers add an animated decoration model/easter egg and forget to disable bone followers //example: out of bounds dancing engineer //assume we don't want bone followers and whitelist the few that actually use them local whitelisted_maps = { "mvm_robotfactory" : null } foreach(i, str in mapname) if (mapname_len == 2 || (mapname_len > 2 && i != mapname_len - 1)) mapname_noversion += format("%s_", str) mapname_noversion = mapname_noversion.slice(0, mapname_noversion.len() - 1) //kill all bonefollowers //these are only used for physics calculations on server-side ragdolls for the most part and absolutely obliterate entity traffic/demo filesize // EntFire("phys_bone_follower", "RunScriptCode", @" // ClientPrint(null, 2, `\n\nBONE FOLLOWER DELETED!\n\n \n\nremember to disable bone followers on your prop_dynamics!!!\n\n`) // self.Kill() // ", 1) printl(mapname_noversion + " : " + mapname_len + " : ") if (mapname_noversion in whitelisted_maps) return // EntFire("phys_bone_follower", "Kill") } } ::___PotatoEvents <- { function OnGameEvent_teamplay_round_start(_) { foreach (name, func in ___GlobalFixes) func() if ("PotatoFeedback" in ___root) return EntFire("bignet", "RunScriptFile", "fb", 1) //run with a delay so the chat message isn't as easily missed } } __CollectGameEventCallbacks(___PotatoEvents) local error_table = {} seterrorhandler(function(e) { local stack = getstackinfos(2) local src = stack ? stack.src : null //stop spamming chat if this same exact error shows up too many times if ("e" in error_table && error_table[e] > MAX_ERRORS) return //increment/insert this error into the table "e" in error_table && !(src in whitelisted_files) ? error_table[e]++ : error_table[e] <- 1 if (error_table[e] >= MAX_ERRORS) { ClientPrint(null, 3, format("\x07FF0000ERROR HANDLER HALTED! Error '%s' has been thrown %d times!", e, MAX_ERRORS)) return } local Chat = @(m) (printl(m), ClientPrint(null, 2, m)) //more concise errors local whitelisted_files = { "contracts.nut" : null } local error_message = src in whitelisted_files ? format("\x07222FF0 %s: [%s]", src, e) : format("\x07FF0000AN ERROR HAS OCCURRED [%s].\nCheck console for details", e) ClientPrint(null, 3, error_message) Chat(format("\n====== TIMESTAMP: %g ======\nAN ERROR HAS OCCURRED [%s]", Time(), e)) Chat("CALLSTACK") local s, l = 2 while (s = getstackinfos(l++)) Chat(format("*FUNCTION [%s()] %s line [%d]", s.func, s.src, s.line)) Chat("LOCALS") if (stack) { foreach (n, v in stack.locals) { local t = type(v) t == "null" ? Chat(format("[%s] NULL" , n)) : t == "integer" ? Chat(format("[%s] %d" , n, v)) : t == "float" ? Chat(format("[%s] %.14g" , n, v)) : t == "string" ? Chat(format("[%s] \"%s\"", n, v)) : Chat(format("[%s] %s %s" , n, t, v.tostring())) } } }) ::printl <- function(text) { ClientPrint(null, 2, text+"\n") } if (!("Potato_CollectGameEventCallbacks" in ___root)) { ::Potato_CollectGameEventCallbacks <- __CollectGameEventCallbacks ::__CollectGameEventCallbacks <- function(table) { if (table == ___root) { error("ERROR: Collecting event callbacks in the root table is forbidden! Event callbacks must be namespaced\n") ClientPrint(null, HUD_PRINTTALK, "\x08FFB4B4FF**ERROR: Collecting event callbacks in the root table is forbidden! Event callbacks must be namespaced**\n\n Confused? ask your local VScript developer what a namespace is") return } Potato_CollectGameEventCallbacks(table) } }