1. -- 8/2/21
  2. -- + Added 'Manual' mode which allows you to force the notes to hit a specific type by holding down a keybind.
  3. -- * Switched fastWait and fastSpawn to Roblox's task libraries
  4. -- * Attempted to fix 'invalid key to next' errors
  5. -- 5/12/21
  6. -- Attempted to fix the autoplayer missing as much.
  7. -- 5/16/21
  8. -- Attempt to fix invisible notes.
  9. -- Added hit chances & an autoplayer toggle
  10. -- ! Hit chances are a bit rough but should work.
  11. -- I have only tested on Synapse X
  12. -- Script-Ware v2 should work fine
  13. -- KRNL should work fine
  14. -- Needed functions: setthreadcontext, getconnections, getgc, getloaodedmodules
  15. -- That should be it!
  16. -- You may find some contact information on the GitHub repo.
  17. local library = loadstring(game:HttpGet("https://raw.githubusercontent.com/wally-rblx/uwuware-ui/main/main.lua"))()
  18. local framework, scrollHandler
  19. while true do
  20. for _, obj in next, getgc(true) do
  21. if type(obj) == 'table' and rawget(obj, 'GameUI') then
  22. framework = obj;
  23. break
  24. end
  25. end
  26. for _, module in next, getloadedmodules() do
  27. if module.Name == 'ScrollHandler' then
  28. scrollHandler = module;
  29. break;
  30. end
  31. end
  32. if (type(framework) == 'table') and (typeof(scrollHandler) == 'Instance') then
  33. break
  34. end
  35. wait(1)
  36. end
  37. local runService = game:GetService('RunService')
  38. local userInputService = game:GetService('UserInputService')
  39. local client = game:GetService('Players').LocalPlayer;
  40. local random = Random.new()
  41. local task = task or getrenv().task;
  42. local fastWait, fastSpawn = task.wait, task.spawn;
  43. local fireSignal, rollChance do
  44. -- updated for script-ware or whatever
  45. -- attempted to update for krnl
  46. local set_identity = (type(syn) == 'table' and syn.set_thread_identity) or setidentity or setthreadcontext
  47. function fireSignal(target, signal, ...)
  48. -- getconnections with InputBegan / InputEnded does not work without setting Synapse to the game's context level
  49. set_identity(2)
  50. for _, signal in next, getconnections(signal) do
  51. if type(signal.Function) == 'function' and islclosure(signal.Function) then
  52. local scr = rawget(getfenv(signal.Function), 'script')
  53. if scr == target then
  54. pcall(signal.Function, ...)
  55. end
  56. end
  57. end
  58. set_identity(7)
  59. end
  60. -- uses a weighted random system
  61. -- its a bit scuffed rn but it works good enough
  62. function rollChance()
  63. if (library.flags.autoPlayerMode == 'Manual') then
  64. if (library.flags.sickHeld) then return 'Sick' end
  65. if (library.flags.goodHeld) then return 'Good' end
  66. if (library.flags.okayHeld) then return 'Ok' end
  67. if (library.flags.missHeld) then return 'Bad' end
  68. return 'Bad' -- incase if it cant find one
  69. end
  70. local chances = {
  71. { type = 'Sick', value = library.flags.sickChance },
  72. { type = 'Good', value = library.flags.goodChance },
  73. { type = 'Ok', value = library.flags.okChance },
  74. { type = 'Bad', value = library.flags.badChance },
  75. }
  76. table.sort(chances, function(a, b)
  77. return a.value > b.value
  78. end)
  79. local sum = 0;
  80. for i = 1, #chances do
  81. sum += chances[i].value
  82. end
  83. if sum == 0 then
  84. -- forgot to change this before?
  85. -- fixed 6/5/21
  86. return chances[random:NextInteger(1, 4)].type
  87. end
  88. local initialWeight = random:NextInteger(0, sum)
  89. local weight = 0;
  90. for i = 1, #chances do
  91. weight = weight + chances[i].value
  92. if weight > initialWeight then
  93. return chances[i].type
  94. end
  95. end
  96. return 'Sick' -- just incase it fails?
  97. end
  98. end
  99. local map = { [0] = 'Left', [1] = 'Down', [2] = 'Up', [3] = 'Right', }
  100. local keys = { Up = Enum.KeyCode.Up; Down = Enum.KeyCode.Down; Left = Enum.KeyCode.Left; Right = Enum.KeyCode.Right; }
  101. -- they are "weird" because they are in the middle of their Upper & Lower ranges
  102. -- should hopefully make them more precise!
  103. local chanceValues = {
  104. Sick = 96,
  105. Good = 92,
  106. Ok = 87,
  107. Bad = 75
  108. }
  109. local hitChances = {}
  110. if shared._id then
  111. pcall(runService.UnbindFromRenderStep, runService, shared._id)
  112. end
  113. shared._id = game:GetService('HttpService'):GenerateGUID(false)
  114. runService:BindToRenderStep(shared._id, 1, function()
  115. if (not library.flags.autoPlayer) then return end
  116. local arrows = {}
  117. for _, obj in next, framework.UI.ActiveSections do
  118. arrows[#arrows + 1] = obj;
  119. end
  120. for idx = 1, #arrows do
  121. local arrow = arrows[idx]
  122. if type(arrow) ~= 'table' then
  123. continue
  124. end
  125. if (arrow.Side == framework.UI.CurrentSide) and (not arrow.Marked) then
  126. local indice = (arrow.Data.Position % 4)
  127. local position = map[indice]
  128. if (position) then
  129. local currentTime = framework.SongPlayer.CurrentlyPlaying.TimePosition
  130. local distance = (1 - math.abs(arrow.Data.Time - currentTime)) * 100
  131. if (arrow.Data.Time == 0) then
  132. continue
  133. end
  134. local result = rollChance()
  135. arrow._hitChance = arrow._hitChance or result;
  136. local hitChance = (library.flags.autoPlayerMode == 'Manual' and result or arrow._hitChance)
  137. if distance >= chanceValues[hitChance] then
  138. fastSpawn(function()
  139. arrow.Marked = true;
  140. fireSignal(scrollHandler, userInputService.InputBegan, { KeyCode = keys[position], UserInputType = Enum.UserInputType.Keyboard }, false)
  141. if arrow.Data.Length > 0 then
  142. -- wait depending on the arrows length so the animation can play
  143. fastWait(arrow.Data.Length)
  144. else
  145. -- 0.1 seems to make it miss more, this should be fine enough?
  146. fastWait(0.05)
  147. end
  148. fireSignal(scrollHandler, userInputService.InputEnded, { KeyCode = keys[position], UserInputType = Enum.UserInputType.Keyboard }, false)
  149. arrow.Marked = nil;
  150. end)
  151. end
  152. end
  153. end
  154. end
  155. end)
  156. local window = library:CreateWindow('Funky Friday') do
  157. local folder = window:AddFolder('Main') do
  158. folder:AddToggle({ text = 'Autoplayer', flag = 'autoPlayer' })
  159. folder:AddList({ text = 'Autoplayer mode', flag = 'autoPlayerMode', values = { 'Chances', 'Manual' } })
  160. folder:AddSlider({ text = 'Sick %', flag = 'sickChance', min = 0, max = 100, value = 100 })
  161. folder:AddSlider({ text = 'Good %', flag = 'goodChance', min = 0, max = 100, value = 0 })
  162. folder:AddSlider({ text = 'Ok %', flag = 'okChance', min = 0, max = 100, value = 0 })
  163. folder:AddSlider({ text = 'Bad %', flag = 'badChance', min = 0, max = 100, value = 0 })
  164. end
  165. local folder = window:AddFolder('Keybinds') do
  166. folder:AddBind({ text = 'Sick', flag = 'sickBind', key = Enum.KeyCode.One, hold = true, callback = function(val) library.flags.sickHeld = (not val) end, })
  167. folder:AddBind({ text = 'Good', flag = 'goodBind', key = Enum.KeyCode.Two, hold = true, callback = function(val) library.flags.goodHeld = (not val) end, })
  168. folder:AddBind({ text = 'Ok', flag = 'okBind', key = Enum.KeyCode.Three, hold = true, callback = function(val) library.flags.okayHeld = (not val) end, })
  169. folder:AddBind({ text = 'Bad', flag = 'badBind', key = Enum.KeyCode.Four, hold = true, callback = function(val) library.flags.missHeld = (not val) end, })
  170. end
  171. local folder = window:AddFolder('Credits') do
  172. folder:AddLabel({ text = 'Credits' })
  173. folder:AddLabel({ text = 'Jan - UI library' })
  174. folder:AddLabel({ text = 'wally - Script' })
  175. end
  176. window:AddLabel({ text = 'Version 1.3' })
  177. window:AddLabel({ text = 'Updated 8/2/21' })
  178. window:AddBind({ text = 'Menu toggle', key = Enum.KeyCode.Delete, callback = function() library:Close() end })
  179. end
  180. library:Init()