local start = tick()
local client = game:GetService('Players').LocalPlayer;
local set_identity = (type(syn) == 'table' and syn.set_thread_identity) or
setidentity or setthreadcontext
local executor = identifyexecutor and identifyexecutor() or 'Unknown'
local function fail(r) return client:Kick(r) end
-- gracefully handle errors when loading external scripts
-- added a cache to make hot reloading a bit faster
local usedCache = shared.__urlcache and next(shared.__urlcache) ~= nil
shared.__urlcache = shared.__urlcache or {}
local function urlLoad(url)
local success, result
if shared.__urlcache[url] then
success, result = true, shared.__urlcache[url]
else
success, result = pcall([Link], game, url)
end
if (not success) then
return fail([Link]('Failed to GET url %q for reason: %q', url,
tostring(result)))
end
local fn, err = loadstring(result)
if (type(fn) ~= 'function') then
return fail([Link]('Failed to loadstring url %q for reason: %q',
url, tostring(err)))
end
local results = { pcall(fn) }
if (not results[1]) then
return fail([Link]('Failed to initialize url %q for reason: %q',
url, tostring(results[2])))
end
shared.__urlcache[url] = result
return unpack(results, 2)
end
-- attempt to block imcompatible exploits
-- rewrote because old checks literally did not work
if type(set_identity) ~= 'function' then return fail('Unsupported exploit (missing
"set_thread_identity")') end
if type(getconnections) ~= 'function' then return fail('Unsupported exploit
(missing "getconnections")') end
if type(getloadedmodules) ~= 'function' then return fail('Unsupported exploit
(misssing "getloadedmodules")') end
if type(getgc) ~= 'function' then return fail('Unsupported exploit (misssing
"getgc")') end
local getinfo = [Link] or getinfo;
local getupvalue = [Link] or getupvalue;
local getupvalues = [Link] or getupvalues;
local setupvalue = [Link] or setupvalue;
if type(setupvalue) ~= 'function' then return fail('Unsupported exploit (misssing
"[Link]")') end
if type(getupvalue) ~= 'function' then return fail('Unsupported exploit (misssing
"[Link]")') end
if type(getupvalues) ~= 'function' then return fail('Unsupported exploit (missing
"[Link]")') end
-- free exploit bandaid fix
if type(getinfo) ~= 'function' then
local debug_info = [Link];
if type(debug_info) ~= 'function' then
-- if your exploit doesnt have getrenv you have no hope
if type(getrenv) ~= 'function' then return fail('Unsupported exploit
(missing "getrenv")') end
debug_info = getrenv().[Link]
end
getinfo = function(f)
assert(type(f) == 'function', [Link]('Invalid argument #1 to
[Link] (expected %s got %s', 'function', type(f)))
local results = { [Link](f, 'slnfa') }
local _, upvalues = pcall(getupvalues, f)
if type(upvalues) ~= 'table' then
upvalues = {}
end
local nups = 0
for k in next, upvalues do
nups = nups + 1
end
-- winning code
return {
source = '@' .. results[1],
short_src = results[1],
what = results[1] == '[C]' and 'C' or 'Lua',
currentline = results[2],
name = results[3],
func = results[4],
numparams = results[5],
is_vararg = results[6], -- 'a' argument returns 2 values :)
nups = nups,
}
end
end
local UI = urlLoad("[Link]
[Link]")
local themeManager =
urlLoad("[Link]
[Link]")
local metadata = urlLoad("[Link]
friday-autoplay/main/[Link]")
local httpService = game:GetService('HttpService')
local framework, scrollHandler, network
local counter = 0
while true do
for _, obj in next, getgc(true) do
if type(obj) == 'table' then
if rawget(obj, 'GameUI') then
framework = obj;
elseif type(rawget(obj, 'Server')) == 'table' then
network = obj;
end
end
if network and framework then break end
end
for _, module in next, getloadedmodules() do
if [Link] == 'ScrollHandler' then
scrollHandler = module;
break;
end
end
if (type(framework) == 'table' and typeof(scrollHandler) == 'Instance' and
type(network) == 'table') then
break
end
counter = counter + 1
if counter > 6 then
fail([Link]('Failed to load game dependencies. Details: %s, %s, %s',
type(framework), typeof(scrollHandler), type(network)))
end
wait(1)
end
local runService = game:GetService('RunService')
local userInputService = game:GetService('UserInputService')
local virtualInputManager = game:GetService('VirtualInputManager')
local random = [Link]()
local task = task or getrenv().task;
local fastWait, fastSpawn = [Link], [Link];
-- firesignal implementation
-- hitchance rolling
local fireSignal, rollChance do
-- updated for script-ware or whatever
-- attempted to update for krnl
function fireSignal(target, signal, ...)
-- getconnections with InputBegan / InputEnded does not work without
setting Synapse to the game's context level
set_identity(2)
local didFire = false
for _, signal in next, getconnections(signal) do
if type([Link]) == 'function' and islclosure([Link])
then
local scr = rawget(getfenv([Link]), 'script')
if scr == target then
didFire = true
pcall([Link], ...)
end
end
end
-- if not didFire then fail"couldnt fire input signal" end
set_identity(7)
end
-- uses a weighted random system
-- its a bit scuffed rn but it works good enough
function rollChance()
-- if (//[Link] == 'Manual') then
if [Link] == 'Manual' then
if ([Link]:GetState()) then return 'Sick' end
if ([Link]:GetState()) then return 'Good' end
if ([Link]:GetState()) then return 'Ok' end
if ([Link]:GetState()) then return 'Bad' end
return 'Bad' -- incase if it cant find one
end
local chances = {
{ 'Sick', [Link] },
{ 'Good', [Link] },
{ 'Ok', [Link] },
{ 'Bad', [Link] },
{ 'Miss' , [Link] },
}
[Link](chances, function(a, b)
return a[2] > b[2]
end)
local sum = 0;
for i = 1, #chances do
sum += chances[i][2]
end
if sum == 0 then
return chances[random:NextInteger(1, #chances)][1]
end
local initialWeight = random:NextInteger(0, sum)
local weight = 0;
for i = 1, #chances do
weight = weight + chances[i][2]
if weight > initialWeight then
return chances[i][1]
end
end
return 'Sick'
end
end
-- autoplayer
local chanceValues do
chanceValues = {
Sick = 96,
Good = 92,
Ok = 87,
Bad = 75,
}
local keyCodeMap = {}
for _, enum in next, [Link]:GetEnumItems() do
keyCodeMap[[Link]] = enum
end
if shared._unload then
pcall(shared._unload)
end
function shared._unload()
if shared._id then
pcall([Link], runService, shared._id)
end
UI:Unload()
for i = 1, #[Link] do
[Link]([Link][i])
end
for i = 1, #[Link] do
[Link]([Link][i])
end
end
[Link] = {}
[Link] = {}
shared._id = httpService:GenerateGUID(false)
local function pressKey(keyCode, state)
if [Link] == 'virtual input' then
virtualInputManager:SendKeyEvent(state, keyCode, false, nil)
else
fireSignal(scrollHandler, userInputService[state and 'InputBegan' or
'InputEnded'], { KeyCode = keyCode, UserInputType = [Link] },
false)
end
end
local rng = [Link]()
runService:BindToRenderStep(shared._id, 1, function()
--if (not [Link]) then return end
if (not [Link]) or (not [Link]) then
return
end
local currentlyPlaying = [Link]
if typeof(currentlyPlaying) ~= 'Instance' or not
currentlyPlaying:IsA('Sound') then
return
end
local arrows = [Link]:GetNotes()
local count = [Link]:GetKeyCount()
local mode = count .. 'Key'
local arrowData = [Link][mode].Arrows
for i, arrow in next, arrows do
-- todo: switch to this ([Link]
local ignoredNoteTypes = { Death = true, Mechanic = true, Poison = true
}
if type([Link]) == 'table' then
if ignoredNoteTypes[[Link]] then
continue
end
end
if ([Link] == [Link]) and (not [Link]) and
[Link] > 0 then
local position = ([Link] % count) .. ''
local hitboxOffset = 0
do
local settings = [Link];
local offset = type(settings) == 'table' and
[Link];
local value = type(offset) == 'table' and [Link];
if type(value) == 'number' then
hitboxOffset = value;
end
hitboxOffset = hitboxOffset / 1000
end
local songTime = [Link]
do
local configs = [Link]
local playbackSpeed = type(configs) == 'table' and
[Link]
if type(playbackSpeed) ~= 'number' then
playbackSpeed = 1
end
songTime = songTime / playbackSpeed
end
local noteTime = [Link]((1 - [Link]([Link] -
(songTime + hitboxOffset))) * 100, 0, 100)
local result = rollChance()
arrow._hitChance = arrow._hitChance or result;
local hitChance = ([Link] == 'Manual' and
result or arrow._hitChance)
if hitChance ~= "Miss" and noteTime >=
chanceValues[arrow._hitChance] then
fastSpawn(function()
[Link] = true;
local keyCode =
keyCodeMap[arrowData[position].[Link][1]]
pressKey(keyCode, true)
local arrowLength = [Link] or 0
local isHeld = arrowLength > 0
local delayMode = [Link]
local minDelay = isHeld and [Link] or
[Link];
local maxDelay = isHeld and [Link] or
[Link];
local noteDelay = isHeld and [Link] or
[Link]
local delay = delayMode == 'Random' and
rng:NextNumber([Link], [Link]) or [Link]
[Link](arrowLength + (delay / 1000))
pressKey(keyCode, false)
[Link] = nil;
end)
end
end
end
end)
end
local ActivateUnlockables do
-- Note: I know you can do this with UserId but it only works if you run it
before opening the notes menu
-- My script should work no matter the order of which you run things :)
local loadStyle = nil
local function loadStyleProxy(...)
-- This forces the styles to reload every time
local upvalues = getupvalues(loadStyle)
for i, upvalue in next, upvalues do
if type(upvalue) == 'table' and rawget(upvalue, 'Style') then
rawset(upvalue, 'Style', nil);
setupvalue(loadStyle, i, upvalue)
end
end
return loadStyle(...)
end
local function applyLoadStyleProxy(...)
local gc = getgc()
for i = 1, #gc do
local obj = gc[i]
if type(obj) == 'function' then
-- goodbye nups numeric loop because script-ware is weird
local upvalues = getupvalues(obj)
for i, upv in next, upvalues do
if type(upv) == 'function' and getinfo(upv).name == 'LoadStyle'
then
-- ugly but it works, we don't know every name for
is_synapse_function and similar
local function isGameFunction(fn)
return getinfo(fn).source:match('%.ArrowSelector
%.Customize$')
end
if isGameFunction(obj) and isGameFunction(upv) then
-- avoid non-game functions :)
loadStyle = loadStyle or upv
setupvalue(obj, i, loadStyleProxy)
[Link]([Link], function()
assert(pcall(setupvalue, obj, i, loadStyle))
end)
end
end
end
end
end
end
local success, error = pcall(applyLoadStyleProxy)
if not success then
return fail([Link]('Failed to hook LoadStyle function. Error(%q)\
nExecutor(%q)\n', error, executor))
end
function ActivateUnlockables()
local idx = [Link]([Link], [Link])
if idx then return end
UI:Notify('Developer arrows have been unlocked!', 3)
[Link]([Link], [Link])
end
end
-- UpdateScore hook
do
while type(roundManager) ~= 'table' do
[Link]()
roundManager = [Link]
end
local oldUpdateScore = [Link];
function [Link](...)
local args = { ... }
local score = args[2]
if type(score) == 'number' and [Link] then
-- [Link](args, warn)
if [Link] == 'No decrease on miss' then
args[2] = 0
elseif [Link] == 'Increase score on miss' then
args[2] = [Link](score)
end
end
return oldUpdateScore(unpack(args))
end
[Link]([Link], function()
[Link] = oldUpdateScore
end)
end
-- Auto ring collector
do
local thread = [Link](function()
local map = workspace:waitForChild('Map', 5)
local buildings = map and map:waitForChild('FunctionalBuildings', 5)
local spawners = buildings and buildings:waitForChild('RingSpawners', 5)
if spawners == nil then return end
if type(firetouchinterest) ~= 'function' then return end
while true do
[Link]()
if [Link] and [Link] then
local character = [Link]
local rootPart = character and
character:findFirstChild('HumanoidRootPart')
if rootPart == nil then continue end
for i, spawner in next, spawners:GetChildren() do
for _, ring in next, spawner:GetChildren() do
if [Link] ~= 'GoldenRing' then continue end
local ring = ring:findFirstChild('ring')
if not (ring and ring:IsA('BasePart')) then continue end
if [Link] == 1 then continue end
firetouchinterest(ring, rootPart, 0)
firetouchinterest(ring, rootPart, 1)
end
end
end
end
end)
[Link]([Link], function()
pcall([Link], thread)
end)
end
local SaveManager = {} do
[Link] = {}
[Link] = {
Toggle = {
Save = function(idx, object)
return { type = 'Toggle', idx = idx, value = [Link] }
end,
Load = function(idx, data)
if Toggles[idx] then
Toggles[idx]:SetValue([Link])
end
end,
},
Slider = {
Save = function(idx, object)
return { type = 'Slider', idx = idx, value = tostring([Link])
}
end,
Load = function(idx, data)
if Options[idx] then
Options[idx]:SetValue([Link])
end
end,
},
Dropdown = {
Save = function(idx, object)
return { type = 'Dropdown', idx = idx, value = [Link], mutli
= [Link] }
end,
Load = function(idx, data)
if Options[idx] then
Options[idx]:SetValue([Link])
end
end,
},
ColorPicker = {
Save = function(idx, object)
return { type = 'ColorPicker', idx = idx, value =
[Link]:ToHex() }
end,
Load = function(idx, data)
if Options[idx] then
Options[idx]:SetValueRGB([Link]([Link]))
end
end,
},
KeyPicker = {
Save = function(idx, object)
return { type = 'KeyPicker', idx = idx, mode = [Link], key =
[Link] }
end,
Load = function(idx, data)
if Options[idx] then
Options[idx]:SetValue({ [Link], [Link] })
end
end,
}
}
function SaveManager:Save(name)
local fullPath = 'funky_friday_autoplayer/configs/' .. name .. '.json'
local data = {
version = 2,
objects = {}
}
for idx, toggle in next, Toggles do
if [Link][idx] then continue end
[Link]([Link], [Link][[Link]].Save(idx, toggle))
end
for idx, option in next, Options do
if not [Link][[Link]] then continue end
if [Link][idx] then continue end
[Link]([Link], [Link][[Link]].Save(idx, option))
end
local success, encoded = pcall([Link], httpService, data)
if not success then
return false, 'failed to encode data'
end
writefile(fullPath, encoded)
return true
end
function SaveManager:Load(name)
local file = 'funky_friday_autoplayer/configs/' .. name .. '.json'
if not isfile(file) then return false, 'invalid file' end
local success, decoded = pcall([Link], httpService,
readfile(file))
if not success then return false, 'decode error' end
if [Link] ~= 2 then return false, 'invalid version' end
for _, option in next, [Link] do
if [Link][[Link]] then
[Link][[Link]].Load([Link], option)
end
end
return true
end
function [Link]()
local list = listfiles('funky_friday_autoplayer/configs')
local out = {}
for i = 1, #list do
local file = list[i]
if file:sub(-5) == '.json' then
-- i hate this but it has to be done ...
local pos = file:find('.json', 1, true)
local start = pos
local char = file:sub(pos, pos)
while char ~= '/' and char ~= '\\' and char ~= '' do
pos = pos - 1
char = file:sub(pos, pos)
end
if char == '/' or char == '\\' then
[Link](out, file:sub(pos + 1, start - 1))
end
end
end
[Link] = out;
[Link]:SetValues()
[Link]:Display()
return out
end
function SaveManager:Delete(name)
local file = 'funky_friday_autoplayer/configs/' .. name .. '.json'
if not isfile(file) then return false, [Link]('Config %q does not
exist', name) end
local succ, err = pcall(delfile, file)
if not succ then
return false, [Link]('error occured during file deletion: %s',
err)
end
return true
end
function SaveManager:SetIgnoreIndexes(list)
for i = 1, #list do
[Link]([Link], list[i])
end
end
function [Link]()
local list = listfiles('funky_friday_autoplayer/configs')
for _, file in next, list do
if isfolder(file) then continue end
local data = readfile(file)
local success, decoded = pcall([Link], httpService,
data)
if success and type(decoded) == 'table' and [Link] ~= 2 then
pcall(delfile, file)
end
end
end
end
local Window = UI:CreateWindow({
Title = [Link]('funky friday autoplayer - version %s | updated: %s',
[Link], [Link]),
AutoShow = true,
Center = true,
Size = [Link](550, 627),
})
local Tabs = {}
local Groups = {}
[Link] = Window:AddTab('Main')
[Link] = Window:AddTab('Miscellaneous')
[Link] = [Link]:AddLeftGroupbox('Autoplayer')
[Link]:AddToggle('Autoplayer', { Text =
'Autoplayer' }):AddKeyPicker('AutoplayerBind', { Default = 'End', NoUI = true,
SyncToggleState = true })
[Link]:AddDropdown('PressMode', {
Text = 'Input mode',
Compact = true,
Default = 'firesignal',
Values = { 'firesignal', 'virtual input' },
Tooltip = 'Input method used to press arrows.\n* firesignal: calls input
functions directly.\n* virtual input: emulates key presses. use if "firesignal"
does not work.',
})
[Link] = [Link]:AddLeftGroupbox('Hit chances')
[Link]:AddDropdown('AutoplayerMode', {
Text = 'Autoplayer mode',
Compact = true,
Default = 1,
Values = { 'Automatic', 'Manual' },
Tooltip = 'Mode to use for deciding when to hit notes.\n* Automatic: hits
notes based on chance sliders\n* Manual: hits notes based on held keybinds',
})
[Link]:AddSlider('SickChance', { Text = 'Sick chance', Min = 0,
Max = 100, Default = 100, Suffix = '%', Rounding = 0, Compact = true })
[Link]:AddSlider('GoodChance', { Text = 'Good chance', Min = 0,
Max = 100, Default = 0, Suffix = '%', Rounding = 0, Compact = true })
[Link]:AddSlider('OkChance', { Text = 'Ok chance', Min = 0,
Max = 100, Default = 0, Suffix = '%', Rounding = 0, Compact = true })
[Link]:AddSlider('BadChance', { Text = 'Bad chance', Min = 0,
Max = 100, Default = 0, Suffix = '%', Rounding = 0, Compact = true })
[Link]:AddSlider('MissChance', { Text = 'Miss chance', Min = 0,
Max = 100, Default = 0, Suffix = '%', Rounding = 0, Compact = true })
[Link] = [Link]:AddLeftGroupbox('Hit timing')
[Link]:AddDropdown('DelayMode', {
Text = 'Delay mode',
Default = 1,
Values = { 'Manual', 'Random' },
Tooltip = 'Adjustable timing for when to release notes.\n* Manual releases
the note after a fixed amount of time.\n* Random releases the note after a random
amount of time.',
})
[Link]:AddLabel('Manual delay')
[Link]:AddSlider('ReleaseDelay', { Text = 'Note delay', Min = 0,
Max = 500, Default = 20, Rounding = 0, Compact = true, Suffix = 'ms' })
[Link]:AddSlider('HeldDelay', { Text = 'Held note delay', Min =
-20, Max = 100, Default = 0, Rounding = 0, Compact = true, Suffix = 'ms' })
[Link]:AddLabel('Random delay')
[Link]:AddSlider('NoteDelayMin', { Text = 'Min note delay', Min =
0, Max = 100, Default = 0, Rounding = 0, Compact = true, Suffix = 'ms' })
[Link]:AddSlider('NoteDelayMax', { Text = 'Max note delay', Min =
0, Max = 500, Default = 20, Rounding = 0, Compact = true, Suffix = 'ms' })
[Link]:AddSlider('HeldDelayMin', { Text = 'Min held note delay',
Min = 0, Max = 100, Default = 0, Rounding = 0, Compact = true, Suffix = 'ms' })
[Link]:AddSlider('HeldDelayMax', { Text = 'Max held note delay',
Min = 0, Max = 500, Default = 20, Rounding = 0, Compact = true, Suffix = 'ms' })
[Link] = [Link]:AddRightGroupbox('Misc')
[Link]:AddButton('Unlock developer notes', ActivateUnlockables)
[Link]:AddToggle('AutoClaimRings', { Text = 'Auto claim rings' })
[Link] = [Link]:AddRightGroupbox('Keybinds')
[Link]:AddLabel('Sick'):AddKeyPicker('SickBind', { Default = 'One',
NoUI = true })
[Link]:AddLabel('Good'):AddKeyPicker('GoodBind', { Default = 'Two',
NoUI = true })
[Link]:AddLabel('Ok'):AddKeyPicker('OkayBind', { Default = 'Three',
NoUI = true })
[Link]:AddLabel('Bad'):AddKeyPicker('BadBind', { Default = 'Four',
NoUI = true })
[Link] = [Link]:AddRightGroupbox('Configs')
[Link] = [Link]:AddRightGroupbox('Credits')
[Link]:AddLabel('<font color="#3da5ff">wally</font> - script')
[Link]:AddLabel('<font color="#de6cff">Sezei</font> - contributor')
[Link]:AddLabel('Inori - ui library')
[Link]:AddLabel('Jan - old ui library')
[Link] = [Link]:AddRightGroupbox('Miscellaneous')
[Link]:AddLabel([Link] or 'no message found!', true)
[Link]:AddDivider()
[Link]:AddButton('Unload script', function() pcall(shared._unload) end)
[Link]:AddButton('Copy discord', function()
if pcall(setclipboard, "[Link] then
UI:Notify('Successfully copied discord link to your clipboard!', 5)
end
end)
[Link]:AddLabel('Menu toggle'):AddKeyPicker('MenuToggle', { Default =
'Delete', NoUI = true })
[Link] = [Link]
if type(readfile) == 'function' and type(writefile) == 'function' and
type(makefolder) == 'function' and type(isfolder) == 'function' then
makefolder('funky_friday_autoplayer')
makefolder('funky_friday_autoplayer\\configs')
[Link]:AddDropdown('ConfigList', { Text = 'Config list', Values = {} })
[Link]:AddInput('ConfigName', { Text = 'Config name' })
[Link]:AddDivider()
[Link]:AddButton('Save config', function()
local name = [Link];
if name:gsub(' ', '') == '' then
return UI:Notify('Invalid config name.', 3)
end
local success, err = SaveManager:Save(name)
if not success then
return UI:Notify(tostring(err), 5)
end
UI:Notify([Link]('Saved config %q', name), 5)
[Link]([Link])
end)
[Link]:AddButton('Load', function()
local name = [Link]
local success, err = SaveManager:Load(name)
if not success then
return UI:Notify(tostring(err), 5)
end
UI:Notify([Link]('Loaded config %q', name), 5)
end):AddButton('Delete', function()
local name = [Link]
if name:gsub(' ', '') == '' then
return UI:Notify('Invalid config name.', 3)
end
local success, err = SaveManager:Delete(name)
if not success then
return UI:Notify(tostring(err), 5)
end
UI:Notify([Link]('Deleted config %q', name), 5)
[Link]([Link], [Link], nil)
[Link]([Link])
end)
[Link]:AddButton('Refresh list', [Link])
[Link]([Link])
[Link]([Link])
else
[Link]:AddLabel('Your exploit is missing file functions so you are
unable to use configs.', true)
--UI:Notify('Failed to create configs tab due to your exploit missing certain
file functions.', 2)
end
-- Themes
do
local latestThemeIndex = 0
for i, theme in next, [Link] do
if theme[1] > latestThemeIndex then
latestThemeIndex = theme[1]
end
end
latestThemeIndex = latestThemeIndex + 1
local linoriaTheme = [Link][2]
local funkyFridayTheme = [Link]([Link][2])
[Link] = [Link](255, 65, 65):ToHex()
[Link]['Linoria'] = { latestThemeIndex, linoriaTheme }
[Link]['Default'] = { 1, funkyFridayTheme }
themeManager:SetLibrary(UI)
themeManager:SetFolder('funky_friday_autoplayer')
themeManager:ApplyToGroupbox([Link]:AddLeftGroupbox('Themes'))
SaveManager:SetIgnoreIndexes({
"BackgroundColor", "MainColor", "AccentColor", "OutlineColor", "FontColor",
-- themes
"ThemeManager_ThemeList", 'ThemeManager_CustomThemeList',
'ThemeManager_CustomThemeName', -- themes
})
end
UI:Notify([Link]('Loaded script in %.4f second(s)!', tick() - start), 3)