Advertisement
Pomni_tries_pastebin

Untitled

May 5th, 2025
20
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 40.01 KB | Gaming | 0 0
  1. local UserInputService = game:GetService("UserInputService")
  2. local RunService = game:GetService("RunService")
  3. local HttpService = game:GetService("HttpService")
  4. local CoreGui = game:GetService("CoreGui")
  5. local Players = game:GetService("Players")
  6. local Workspace = game:GetService("Workspace")
  7.  
  8. local LocalPlayer = Players.LocalPlayer
  9. local Mouse = LocalPlayer:GetMouse() -- Mouse is still available for Target property
  10.  
  11. local Keybinds = {
  12.     AddSavestate = "BtnAddSavestate",
  13.     RemoveSavestate = "BtnRemoveSavestate",
  14.     BackSavestate = "BtnBackSavestate",
  15.     GoFrameBack = "BtnGoFrameBack",
  16.     GoFrameForward = "BtnGoFrameForward",
  17.     SaveRun = "BtnSaveRun",
  18.     UserPause = "BtnUserPause",
  19.     CollisionToggler = "BtnCollisionToggler",
  20.     ResetToNormal = "BtnResetToNormal",
  21.     ViewTAS = "BtnViewTAS"
  22. }
  23.  
  24. local Savestates = {}
  25. local PlayerInfo = {}
  26. local TimePaused = 0
  27. local Pause = true
  28. local TimePauseHolder
  29. local TimeStart
  30. local FrameCountLabel
  31. local SavestatesCountLabel
  32. local TimeTextLabel
  33. local CapLockPauseLabel -- This will be repurposed for a status label
  34. local KeyBindFrame
  35. local HUD
  36. local MainConnectionLoop
  37. local KeybindsConnect
  38. local InputEndConnect -- Less relevant for mobile buttons, but kept for potential future use
  39. local DiedConnect
  40. local MobileButtonFrame
  41.  
  42. local CurrentAnimationState = { Name = "Idle", Weight = 0 }
  43.  
  44. local function getCurrentCFrame()
  45.     if LocalPlayer.Character and LocalPlayer.Character:FindFirstChild("HumanoidRootPart") then
  46.         return LocalPlayer.Character.HumanoidRootPart.CFrame
  47.     end
  48.     return CFrame.new()
  49. end
  50.  
  51. local function getCurrentVelocity()
  52.     if LocalPlayer.Character and LocalPlayer.Character:FindFirstChild("HumanoidRootPart") then
  53.         return LocalPlayer.Character.HumanoidRootPart.Velocity
  54.     end
  55.     return Vector3.new()
  56. end
  57.  
  58. local function getCurrentCameraCFrame()
  59.     return Workspace.CurrentCamera.CFrame
  60. end
  61.  
  62. local function ReturnPlayerInfo()
  63.     return {
  64.         CFrame = getCurrentCFrame(),
  65.         CameraCFrame = getCurrentCameraCFrame(),
  66.         Velocity = getCurrentVelocity(),
  67.         Animation = CurrentAnimationState,
  68.         Time = tick() - TimeStart - TimePaused,
  69.     }
  70. end
  71.  
  72. local function UpdateGUIText()
  73.     if SavestatesCountLabel then
  74.         SavestatesCountLabel.Text = "Savestates: " .. #Savestates
  75.     end
  76.     if FrameCountLabel then
  77.         FrameCountLabel.Text = "Frames: " .. #PlayerInfo
  78.     end
  79. end
  80.  
  81. local function FormatTime(TimeValue)
  82.     local m = math.floor(TimeValue / 60)
  83.     local s = math.floor(TimeValue % 60)
  84.     local ms = math.floor((TimeValue * 1000) % 1000)
  85.     local msStr = tostring(ms)
  86.     local sStr = tostring(s)
  87.  
  88.     while #msStr < 3 do msStr = '0' .. msStr end
  89.     while #sStr < 2 do sStr = '0' .. sStr end
  90.  
  91.     return m .. ":" .. sStr .. "." .. msStr
  92. end
  93.  
  94.  
  95. local function UpdateTimeGUI()
  96.     if TimeTextLabel then
  97.         local TimePlayed = tick() - TimeStart - TimePaused
  98.         TimeTextLabel.Text = FormatTime(TimePlayed)
  99.     end
  100. end
  101.  
  102. local function SetCharacterState(InfoState)
  103.     if not LocalPlayer.Character or not LocalPlayer.Character:FindFirstChild("HumanoidRootPart") or not LocalPlayer.Character:FindFirstChild("Humanoid") then return end
  104.  
  105.     local Hum = LocalPlayer.Character.Humanoid
  106.     local RootPart = LocalPlayer.Character.HumanoidRootPart
  107.  
  108.     RootPart.CFrame = InfoState.CFrame
  109.     RootPart.Velocity = InfoState.Velocity
  110.     Workspace.CurrentCamera.CFrame = InfoState.CameraCFrame
  111.  
  112.     CurrentAnimationState = InfoState.Animation or { Name = "Idle", Weight = 0 }
  113.  
  114.     if CurrentAnimationState.Name and Hum then
  115.         local Animator = Hum:FindFirstChildOfClass("Animator")
  116.         if Animator then
  117.              local PlayingTracks = Animator:GetPlayingAnimationTracks()
  118.              for _, track in ipairs(PlayingTracks) do
  119.                  if track.Name == CurrentAnimationState.Name then
  120.                     track:AdjustSpeed(CurrentAnimationState.Weight or 1)
  121.                     -- Note: Setting TimePosition directly might not always look smooth,
  122.                     -- but it's the closest we can get to syncing animation state.
  123.                     -- More advanced animation handling might be needed for complex animations.
  124.                     -- track.TimePosition = 0 -- Consider if you always want to reset animation
  125.                     break
  126.                  end
  127.              end
  128.         end
  129.     end
  130. end
  131.  
  132. local function SetUpGui()
  133.     if HUD then HUD:Destroy() end
  134.  
  135.     HUD = Instance.new("ScreenGui", CoreGui)
  136.     HUD.Name = "TASRecorderGUI"
  137.     HUD.ResetOnSpawn = false
  138.     HUD.ZIndexBehavior = Enum.ZIndexBehavior.Sibling
  139.  
  140.     local MainFrame = Instance.new("Frame", HUD)
  141.     MainFrame.AnchorPoint = Vector2.new(0.5, 1)
  142.     MainFrame.Position = UDim2.new(0.5, 0, 1, -10)
  143.     MainFrame.Size = UDim2.new(0.4, 0, 0, 100) -- Adjusted size for mobile
  144.     MainFrame.BackgroundColor3 = Color3.fromRGB(30, 30, 30)
  145.     MainFrame.BackgroundTransparency = 0.3
  146.     MainFrame.BorderColor3 = Color3.fromRGB(200, 200, 200)
  147.     MainFrame.BorderSizePixel = 1
  148.  
  149.     local UIListLayout = Instance.new("UIListLayout", MainFrame)
  150.     UIListLayout.Padding = UDim.new(0, 5)
  151.     UIListLayout.SortOrder = Enum.SortOrder.LayoutOrder
  152.     UIListLayout.HorizontalAlignment = Enum.HorizontalAlignment.Center
  153.  
  154.     TimeTextLabel = Instance.new("TextLabel", MainFrame)
  155.     TimeTextLabel.Name = "TimeText"
  156.     TimeTextLabel.LayoutOrder = 1
  157.     TimeTextLabel.Size = UDim2.new(1, -10, 0, 20)
  158.     TimeTextLabel.Position = UDim2.new(0, 5, 0, 5)
  159.     TimeTextLabel.BackgroundTransparency = 1
  160.     TimeTextLabel.Font = Enum.Font.SourceSansBold
  161.     TimeTextLabel.Text = "0:00.000"
  162.     TimeTextLabel.TextColor3 = Color3.fromRGB(255, 255, 255)
  163.     TimeTextLabel.TextScaled = true
  164.     TimeTextLabel.TextXAlignment = Enum.TextXAlignment.Left
  165.  
  166.     SavestatesCountLabel = Instance.new("TextLabel", MainFrame)
  167.     SavestatesCountLabel.Name = "SavestatesCount"
  168.     SavestatesCountLabel.LayoutOrder = 2
  169.     SavestatesCountLabel.Size = UDim2.new(1, -10, 0, 15)
  170.     SavestatesCountLabel.BackgroundTransparency = 1
  171.     SavestatesCountLabel.Font = Enum.Font.SourceSans
  172.     SavestatesCountLabel.Text = "Savestates: 0"
  173.     SavestatesCountLabel.TextColor3 = Color3.fromRGB(220, 220, 220)
  174.     SavestatesCountLabel.TextScaled = true
  175.     SavestatesCountLabel.TextXAlignment = Enum.TextXAlignment.Left
  176.  
  177.     FrameCountLabel = Instance.new("TextLabel", MainFrame)
  178.     FrameCountLabel.Name = "FrameCount"
  179.     FrameCountLabel.LayoutOrder = 3
  180.     FrameCountLabel.Size = UDim2.new(1, -10, 0, 15)
  181.     FrameCountLabel.BackgroundTransparency = 1
  182.     FrameCountLabel.Font = Enum.Font.SourceSans
  183.     FrameCountLabel.Text = "Frames: 0"
  184.     FrameCountLabel.TextColor3 = Color3.fromRGB(220, 220, 220)
  185.     FrameCountLabel.TextScaled = true
  186.     FrameCountLabel.TextXAlignment = Enum.TextXAlignment.Left
  187.  
  188.     CapLockPauseLabel = Instance.new("TextLabel", MainFrame) -- Repurposed for status
  189.     CapLockPauseLabel.Name = "StatusLabel"
  190.     CapLockPauseLabel.LayoutOrder = 4
  191.     CapLockPauseLabel.Size = UDim2.new(1, -10, 0, 15)
  192.     CapLockPauseLabel.BackgroundTransparency = 1
  193.     CapLockPauseLabel.Font = Enum.Font.SourceSansBold
  194.     CapLockPauseLabel.Text = "Status: Paused"
  195.     CapLockPauseLabel.TextColor3 = Color3.fromRGB(255, 255, 0)
  196.     CapLockPauseLabel.TextScaled = true
  197.     CapLockPauseLabel.TextXAlignment = Enum.TextXAlignment.Left
  198.  
  199.  
  200.     -- Mobile Buttons Frame
  201.     MobileButtonFrame = Instance.new("Frame", HUD)
  202.     MobileButtonFrame.Name = "MobileButtonFrame"
  203.     MobileButtonFrame.AnchorPoint = Vector2.new(0, 0.5)
  204.     MobileButtonFrame.Position = UDim2.new(0, 10, 0.5, 0)
  205.     MobileButtonFrame.Size = UDim2.new(0, 80, 0.6, 0) -- Adjusted size and position
  206.     MobileButtonFrame.BackgroundColor3 = Color3.fromRGB(30, 30, 30)
  207.     MobileButtonFrame.BackgroundTransparency = 0.5
  208.     MobileButtonFrame.BorderColor3 = Color3.fromRGB(200, 200, 200)
  209.     MobileButtonFrame.BorderSizePixel = 1
  210.  
  211.     local ButtonListLayout = Instance.new("UIListLayout", MobileButtonFrame)
  212.     ButtonListLayout.Padding = UDim.new(0, 5)
  213.     ButtonListLayout.SortOrder = Enum.SortOrder.LayoutOrder
  214.     ButtonListLayout.FillDirection = Enum.FillDirection.Vertical
  215.     ButtonListLayout.HorizontalAlignment = Enum.HorizontalAlignment.Center
  216.  
  217.     local function CreateMobileButton(name, text, layoutOrder)
  218.         local Button = Instance.new("TextButton", MobileButtonFrame)
  219.         Button.Name = name
  220.         Button.LayoutOrder = layoutOrder
  221.         Button.Size = UDim2.new(1, -10, 0, 25) -- Adjusted button size
  222.         Button.BackgroundColor3 = Color3.fromRGB(60, 60, 60)
  223.         Button.TextColor3 = Color3.fromRGB(255, 255, 255)
  224.         Button.Text = text
  225.         Button.Font = Enum.Font.SourceSansBold
  226.         Button.TextScaled = true
  227.         Button.BorderSizePixel = 0
  228.         return Button
  229.     end
  230.  
  231.     local BtnUserPause = CreateMobileButton(Keybinds.UserPause, "Pause", 1)
  232.     local BtnAddSavestate = CreateMobileButton(Keybinds.AddSavestate, "Add SS", 2)
  233.     local BtnBackSavestate = CreateMobileButton(Keybinds.BackSavestate, "Back SS", 3)
  234.     local BtnGoFrameBack = CreateMobileButton(Keybinds.GoFrameBack, "<< Frame", 4)
  235.     local BtnGoFrameForward = CreateMobileButton(Keybinds.GoFrameForward, "Frame >>", 5)
  236.     local BtnSaveRun = CreateMobileButton(Keybinds.SaveRun, "Save Run", 6)
  237.     local BtnCollisionToggler = CreateMobileButton(Keybinds.CollisionToggler, "Toggle Collide", 7)
  238.     local BtnViewTAS = CreateMobileButton(Keybinds.ViewTAS, "View TAS", 8)
  239.     local BtnResetToNormal = CreateMobileButton(Keybinds.ResetToNormal, "Stop", 9)
  240.  
  241.     -- Connect button events
  242.     BtnUserPause.MouseButton1Click:Connect(UserPauseToggle)
  243.     BtnAddSavestate.MouseButton1Click:Connect(AddSavestate)
  244.     BtnBackSavestate.MouseButton1Click:Connect(BackSavestate)
  245.     BtnSaveRun.MouseButton1Click:Connect(SaveRun)
  246.     BtnCollisionToggler.MouseButton1Click:Connect(CollisionToggler)
  247.     BtnViewTAS.MouseButton1Click:Connect(function()
  248.          if not ViewingTAS then
  249.               local CurrentTASData = PrepareTasData()
  250.               ViewTASPlayback(CurrentTASData)
  251.          end
  252.     end)
  253.     BtnResetToNormal.MouseButton1Click:Connect(DisconnectAll)
  254.  
  255.     -- Frame forward/back can use InputBegan/InputEnded for hold functionality
  256.     BtnGoFrameForward.InputBegan:Connect(function(input)
  257.         if input.UserInputType == Enum.UserInputType.Touch or input.UserInputType == Enum.UserInputType.MouseButton1 then
  258.             task.spawn(FrameForwardStart)
  259.         end
  260.     end)
  261.     BtnGoFrameForward.InputEnded:Connect(function(input)
  262.          if input.UserInputType == Enum.UserInputType.Touch or input.UserInputType == Enum.UserInputType.MouseButton1 then
  263.             isFrameForwardHeld = false
  264.          end
  265.     end)
  266.  
  267.     BtnGoFrameBack.InputBegan:Connect(function(input)
  268.          if input.UserInputType == Enum.UserInputType.Touch or input.UserInputType == Enum.UserInputType.MouseButton1 then
  269.             task.spawn(FrameBackStart)
  270.          end
  271.     end)
  272.     BtnGoFrameBack.InputEnded:Connect(function(input)
  273.          if input.UserInputType == Enum.UserInputType.Touch or input.UserInputType == Enum.UserInputType.MouseButton1 then
  274.             isFrameBackHeld = false
  275.          end
  276.     end)
  277.  
  278.     -- Keybinds frame is likely not needed for mobile, but keeping the structure
  279.     -- in case you want to adapt it later or keep it for PC.
  280.     KeyBindFrame = Instance.new("Frame", HUD)
  281.     KeyBindFrame.Name = "KeyBindFrame"
  282.     KeyBindFrame.AnchorPoint = Vector2.new(0.5, 1)
  283.     KeyBindFrame.Position = UDim2.new(0.5, 0, 1, -120)
  284.     KeyBindFrame.Size = UDim2.new(0, 250, 0, 200)
  285.     KeyBindFrame.BackgroundColor3 = Color3.fromRGB(40, 40, 40)
  286.     KeyBindFrame.BackgroundTransparency = 0.2
  287.     KeyBindFrame.BorderColor3 = Color3.fromRGB(200, 200, 200)
  288.     KeyBindFrame.BorderSizePixel = 1
  289.     KeyBindFrame.Visible = false -- Hidden by default on mobile
  290.     KeyBindFrame.ClipsDescendants = true
  291.  
  292.     local KeybindListLayout = Instance.new("UIListLayout", KeyBindFrame)
  293.     KeybindListLayout.Padding = UDim.new(0, 2)
  294.     KeybindListLayout.HorizontalAlignment = Enum.HorizontalAlignment.Center
  295.     KeybindListLayout.SortOrder = Enum.SortOrder.LayoutOrder
  296.  
  297.     local function CreateKeybindLabel(Key, Action)
  298.         local Label = Instance.new("TextLabel", KeyBindFrame)
  299.         Label.Name = Action .. "Label"
  300.         Label.Size = UDim2.new(1, -10, 0, 15)
  301.         Label.Position = UDim2.new(0, 5, 0, 0)
  302.         Label.BackgroundTransparency = 1
  303.         Label.Font = Enum.Font.SourceSans
  304.         Label.Text = Key .. " : " .. Action
  305.         Label.TextColor3 = Color3.fromRGB(230, 230, 230)
  306.         Label.TextScaled = true
  307.         Label.TextXAlignment = Enum.TextXAlignment.Left
  308.         return Label
  309.     end
  310.  
  311.     -- These labels are for the hidden KeyBindFrame (PC view)
  312.     CreateKeybindLabel("CapsLock", "Pause/Unpause")
  313.     CreateKeybindLabel("One", "Add Savestate")
  314.     CreateKeybindLabel("Two", "Remove Savestate")
  315.     CreateKeybindLabel("Eight", "Go To Last Savestate")
  316.     CreateKeybindLabel("Four", "Go Frame Back")
  317.     CreateKeybindLabel("Five", "Go Frame Forward")
  318.     CreateKeybindLabel("Six", "Save Run")
  319.     CreateKeybindLabel("C", "Toggle Collision")
  320.     CreateKeybindLabel("Zero", "View TAS")
  321.     CreateKeybindLabel("Delete", "Stop Recording")
  322.  
  323.     -- A button to show/hide the keybinds frame (optional for mobile)
  324.     local KeybindsButton = Instance.new("TextButton", MainFrame)
  325.     KeybindsButton.Name = "KeybindsButton"
  326.     KeybindsButton.LayoutOrder = 5
  327.     KeybindsButton.Size = UDim2.new(1, -10, 0, 20)
  328.     KeybindsButton.BackgroundColor3 = Color3.fromRGB(80, 80, 80)
  329.     KeybindsButton.TextColor3 = Color3.fromRGB(255, 255, 255)
  330.     KeybindsButton.Text = "Show Keybinds (PC)"
  331.     KeybindsButton.Font = Enum.Font.SourceSansBold
  332.     KeybindsButton.TextScaled = true
  333.     KeybindsButton.Visible = false -- Hide by default on mobile
  334.  
  335.     -- Check if the device is mobile and adjust visibility
  336.     if UserInputService.TouchEnabled and not UserInputService.KeyboardEnabled and not UserInputService.GamepadEnabled then
  337.         KeybindsButton.Visible = false
  338.         KeyBindFrame.Visible = false
  339.         MobileButtonFrame.Visible = true
  340.     else
  341.         KeybindsButton.Visible = true
  342.         MobileButtonFrame.Visible = false
  343.         KeybindsButton.MouseButton1Click:Connect(function()
  344.             KeyBindFrame.Visible = not KeyBindFrame.Visible
  345.             if KeyBindFrame.Visible then
  346.                 KeybindsButton.Text = "Hide Keybinds (PC)"
  347.             else
  348.                 KeybindsButton.Text = "Show Keybinds (PC)"
  349.             end
  350.         end)
  351.     end
  352. end
  353.  
  354. local function UserPauseToggle()
  355.     Pause = not Pause
  356.     if LocalPlayer.Character and LocalPlayer.Character:FindFirstChild("HumanoidRootPart") then
  357.         LocalPlayer.Character.HumanoidRootPart.Anchored = Pause
  358.     end
  359.  
  360.     if Pause then
  361.         TimePauseHolder = tick()
  362.         if TimeTextLabel then TimeTextLabel.TextColor3 = Color3.fromRGB(255, 255, 0) end
  363.         if CapLockPauseLabel then
  364.              CapLockPauseLabel.Text = "Status: Paused"
  365.              CapLockPauseLabel.TextColor3 = Color3.fromRGB(255, 255, 0)
  366.         end
  367.     else
  368.         if TimePauseHolder then
  369.             TimePaused = TimePaused + (tick() - TimePauseHolder)
  370.             TimePauseHolder = nil
  371.         end
  372.         if TimeTextLabel then TimeTextLabel.TextColor3 = Color3.fromRGB(255, 255, 255) end
  373.         if CapLockPauseLabel then
  374.              CapLockPauseLabel.Text = "Status: Recording"
  375.              CapLockPauseLabel.TextColor3 = Color3.fromRGB(255, 255, 255)
  376.         end
  377.     end
  378. end
  379.  
  380. local function AddSavestate()
  381.     -- Save the current PlayerInfo as a new savestate
  382.     if #PlayerInfo > 0 then
  383.         table.insert(Savestates, PlayerInfo)
  384.         PlayerInfo = {} -- Start a new frame sequence for the next savestate
  385.         UpdateGUIText()
  386.         print("Savestate added. Total savestates: " .. #Savestates)
  387.     else
  388.         print("No frame data to save as a savestate.")
  389.     end
  390. end
  391.  
  392. local function RemoveSavestate()
  393.     if #Savestates > 0 then
  394.         -- Remove the last savestate
  395.         local lastSavestate = table.remove(Savestates)
  396.         print("Last savestate removed. Total savestates: " .. #Savestates)
  397.  
  398.         -- Attempt to restore state from the new last savestate if one exists
  399.         if #Savestates > 0 then
  400.             local lastFrameInLastSavestate = Savestates[#Savestates][#Savestates[#Savestates]]
  401.             PlayerInfo = {} -- Clear current frames
  402.             Pause = true
  403.             TimePauseHolder = tick()
  404.             TimeStart = tick() - lastFrameInLastSavestate.Time
  405.             TimePaused = 0
  406.             SetCharacterState(lastFrameInLastSavestate)
  407.             UpdateTimeGUI()
  408.              if CapLockPauseLabel then
  409.                  CapLockPauseLabel.Text = "Status: Paused (Restored SS)"
  410.                  CapLockPauseLabel.TextColor3 = Color3.fromRGB(255, 255, 0)
  411.              end
  412.         else
  413.             -- If no savestates left, reset entirely
  414.             PlayerInfo = {}
  415.             TimeStart = tick()
  416.             TimePaused = 0
  417.             if LocalPlayer.Character and LocalPlayer.Character:FindFirstChild("HumanoidRootPart") then
  418.                 LocalPlayer.Character.HumanoidRootPart.Anchored = true
  419.             end
  420.             Pause = true
  421.             TimePauseHolder = tick()
  422.             if CapLockPauseLabel then
  423.                  CapLockPauseLabel.Text = "Status: Paused (Reset)"
  424.                  CapLockPauseLabel.TextColor3 = Color3.fromRGB(255, 255, 0)
  425.             end
  426.         end
  427.         UpdateGUIText()
  428.     else
  429.         print("No savestates to remove.")
  430.     end
  431. end
  432.  
  433. local function BackSavestate()
  434.      if #Savestates > 0 and Savestates[#Savestates] and #Savestates[#Savestates] > 0 then
  435.         local InfoState = Savestates[#Savestates][#Savestates[#Savestates]]
  436.         PlayerInfo = {} -- Clear current frames
  437.         Pause = true
  438.         if LocalPlayer.Character and LocalPlayer.Character:FindFirstChild("HumanoidRootPart") then
  439.             LocalPlayer.Character.HumanoidRootPart.Anchored = true
  440.         end
  441.         TimePauseHolder = tick()
  442.         TimeStart = tick() - InfoState.Time
  443.         TimePaused = 0
  444.         SetCharacterState(InfoState)
  445.         if TimeTextLabel then TimeTextLabel.TextColor3 = Color3.fromRGB(255, 255, 0) end
  446.         if CapLockPauseLabel then
  447.              CapLockPauseLabel.Text = "Status: Paused (Go Back SS)"
  448.              CapLockPauseLabel.TextColor3 = Color3.fromRGB(255, 255, 0)
  449.         end
  450.         UpdateTimeGUI()
  451.         UpdateGUIText()
  452.         print("Returned to last savestate.")
  453.     else
  454.         print("No savestates to go back to.")
  455.     end
  456. end
  457.  
  458. local function GoFrameForward()
  459.     if Pause then
  460.         -- To step forward one frame, we need to temporarily unpause,
  461.         -- wait for one physics frame, then re-pause.
  462.         UserPauseToggle() -- Unpause
  463.         RunService.Heartbeat:Wait() -- Wait for one frame
  464.         UserPauseToggle() -- Repause
  465.         print("Stepped forward one frame.")
  466.     else
  467.         print("Cannot step frame forward while unpaused.")
  468.     end
  469. end
  470.  
  471. local isFrameForwardHeld = false
  472. local FrameForwardTask = nil
  473. local function FrameForwardStart()
  474.     if not Pause then
  475.         print("Cannot step frame forward while unpaused.")
  476.         return
  477.     end
  478.     if isFrameForwardHeld then return end -- Prevent multiple tasks
  479.     isFrameForwardHeld = true
  480.     print("Starting frame forward hold...")
  481.  
  482.     FrameForwardTask = task.spawn(function()
  483.         GoFrameForward() -- Step forward one frame immediately
  484.         while task.wait(0.05) and isFrameForwardHeld do -- Wait and check if still held
  485.             GoFrameForward()
  486.         end
  487.         print("Frame forward hold ended.")
  488.     end)
  489. end
  490.  
  491. local isFrameBackHeld = false
  492. local FrameBackTask = nil
  493. local function GoFrameBack()
  494.     if LocalPlayer.Character then
  495.         local TargetFrameInfo = nil
  496.         local frameSource = nil -- To track where the frame came from (PlayerInfo or Savestates)
  497.  
  498.         if #PlayerInfo > 0 then
  499.             -- If there are frames in the current sequence, go back within them
  500.             TargetFrameInfo = table.remove(PlayerInfo)
  501.             frameSource = "PlayerInfo"
  502.              if #PlayerInfo > 0 then
  503.                  TargetFrameInfo = PlayerInfo[#PlayerInfo]
  504.              elseif #Savestates > 0 and #Savestates[#Savestates] > 0 then
  505.                  -- If PlayerInfo is now empty, go to the last frame of the last savestate
  506.                  TargetFrameInfo = Savestates[#Savestates][#Savestates[#Savestates]]
  507.                  frameSource = "Savestates"
  508.              end
  509.         elseif #Savestates > 0 and #Savestates[#Savestates] > 0 then
  510.             -- If PlayerInfo is empty, go back within the last savestate
  511.              table.remove(Savestates[#Savestates]) -- Remove the last frame from the last savestate
  512.              if #Savestates[#Savestates] > 0 then
  513.                  TargetFrameInfo = Savestates[#Savestates][#Savestates[#Savestates]]
  514.                  frameSource = "Savestates"
  515.              elseif #Savestates > 1 then
  516.                  -- If the last savestate is now empty, remove it and go to the last frame of the new last savestate
  517.                  table.remove(Savestates)
  518.                  if #Savestates > 0 and #Savestates[#Savestates] > 0 then
  519.                       TargetFrameInfo = Savestates[#Savestates][#Savestates[#Savestates]]
  520.                       frameSource = "Savestates"
  521.                  end
  522.              end
  523.         end
  524.  
  525.         if TargetFrameInfo then
  526.             if not Pause then UserPauseToggle() end -- Ensure paused before setting state
  527.             TimePauseHolder = tick()
  528.             TimeStart = tick() - TargetFrameInfo.Time
  529.             TimePaused = 0
  530.             SetCharacterState(TargetFrameInfo)
  531.             UpdateTimeGUI()
  532.             UpdateGUIText()
  533.              if CapLockPauseLabel then
  534.                  CapLockPauseLabel.Text = "Status: Paused (Go Frame Back)"
  535.                  CapLockPauseLabel.TextColor3 = Color3.fromRGB(255, 255, 0)
  536.              end
  537.             print("Stepped back one frame. Source: " .. (frameSource or "N/A"))
  538.         else
  539.             print("Cannot step frame back. No previous frames or savestates.")
  540.         end
  541.     end
  542. end
  543.  
  544. local function FrameBackStart()
  545.     if not Pause then
  546.         print("Cannot step frame back while unpaused.")
  547.         return
  548.     end
  549.     if isFrameBackHeld then return end -- Prevent multiple tasks
  550.     isFrameBackHeld = true
  551.     print("Starting frame back hold...")
  552.  
  553.     FrameBackTask = task.spawn(function()
  554.         GoFrameBack() -- Step back one frame immediately
  555.         while task.wait(0.05) and isFrameBackHeld do -- Wait and check if still held
  556.             GoFrameBack()
  557.         end
  558.         print("Frame back hold ended.")
  559.     end)
  560. end
  561.  
  562.  
  563. local function CollisionToggler()
  564.     local Target = Mouse.Target -- Mouse.Target still works for finding what the camera is looking at
  565.     if Target and Target:IsA("BasePart") then
  566.         Target.CanCollide = not Target.CanCollide
  567.         Target.Transparency = Target.CanCollide and 0 or 0.7
  568.         print("Toggled collision for: " .. Target.Name .. " (CanCollide: " .. tostring(Target.CanCollide) .. ")")
  569.     else
  570.         print("No valid BasePart found to toggle collision.")
  571.     end
  572. end
  573.  
  574. local function PrepareTasData()
  575.     local FullTAS = {}
  576.     -- Add frames from existing savestates
  577.     for i = 1, #Savestates do
  578.         for j = 1, #Savestates[i] do
  579.             local Frame = Savestates[i][j]
  580.             local MinFrame = {}
  581.             local cfX, cfY, cfZ, cfR00, cfR01, cfR02, cfR10, cfR11, cfR12, cfR20, cfR21, cfR22 = Frame.CFrame:GetComponents()
  582.             local camX, camY, camZ, camR00, camR01, camR02, camR10, camR11, camR12, camR20, camR21, camR22 = Frame.CameraCFrame:GetComponents()
  583.  
  584.             MinFrame.CCFrame = {cfX, cfY, cfZ, cfR00, cfR01, cfR02, cfR10, cfR11, cfR12, cfR20, cfR21, cfR22}
  585.             MinFrame.CCameraCFrame = {camX, camY, camZ, camR00, camR01, camR02, camR10, camR11, camR12, camR20, camR21, camR22}
  586.             MinFrame.VVelocity = {Frame.Velocity.X, Frame.Velocity.Y, Frame.Velocity.Z}
  587.             MinFrame.AAnimation = Frame.Animation or {Name="Idle", Weight=0}
  588.             MinFrame.time = Frame.Time
  589.  
  590.             table.insert(FullTAS, MinFrame)
  591.         end
  592.     end
  593.     -- Add frames from the current, unsaved sequence
  594.     for i = 1, #PlayerInfo do
  595.          local Frame = PlayerInfo[i]
  596.          local MinFrame = {}
  597.          local cfX, cfY, cfZ, cfR00, cfR01, cfR02, cfR10, cfR11, cfR12, cfR20, cfR21, cfR22 = Frame.CFrame:GetComponents()
  598.          local camX, camY, camZ, camR00, camR01, camR02, camR10, camR11, camR12, camR20, camR21, camR22 = Frame.CameraCFrame:GetComponents()
  599.  
  600.          MinFrame.CCFrame = {cfX, cfY, cfZ, cfR00, cfR01, cfR02, cfR10, cfR11, cfR12, cfR20, cfR21, cfR22}
  601.          MinFrame.CCameraCFrame = {camX, camY, camZ, camR00, camR01, camR02, camR10, camR11, camR12, camR20, camR21, camR22}
  602.          MinFrame.VVelocity = {Frame.Velocity.X, Frame.Velocity.Y, Frame.Velocity.Z}
  603.          MinFrame.AAnimation = Frame.Animation or {Name="Idle", Weight=0}
  604.          MinFrame.time = Frame.Time
  605.  
  606.          table.insert(FullTAS, MinFrame)
  607.     end
  608.  
  609.     -- Sort the frames by time to ensure correct playback order
  610.     table.sort(FullTAS, function(a, b)
  611.         return a.time < b.time
  612.     end)
  613.  
  614.     return FullTAS
  615. end
  616.  
  617. local function SaveRun()
  618.     local FullTAS = PrepareTasData()
  619.     if #FullTAS > 0 then
  620.         local MapName = "Generic" -- You might want to find a way to get a meaningful map name
  621.         local GameName = "RobloxGame" -- Default name
  622.         local Success, Info = pcall(game.GetService(game, "MarketplaceService").GetProductInfo, game.GetService(game, "MarketplaceService"), game.PlaceId)
  623.         if Success and Info then
  624.              GameName = Info.Name
  625.         end
  626.         GameName = GameName:gsub("[^%w%s]", ""):gsub("%s+", "_") -- Sanitize name
  627.  
  628.         local FileName = GameName .. "_" .. MapName .. "_TAS.json"
  629.         local FilePath = "TAS_Recorder/" .. FileName
  630.  
  631.         local EncodedData = HttpService:JSONEncode(FullTAS)
  632.  
  633.         if writefile then -- Check if the environment supports file writing (e.g., exploit context)
  634.             if not isfolder("TAS_Recorder") then
  635.                  makefolder("TAS_Recorder")
  636.             end
  637.             writefile(FilePath, EncodedData)
  638.             print("TAS saved to: " .. FilePath)
  639.         else
  640.             print("File saving is not supported in this environment.")
  641.             print("TAS Data (JSON):")
  642.             print(EncodedData)
  643.         end
  644.     else
  645.         print("No TAS data to save.")
  646.     end
  647. end
  648.  
  649.  
  650. local ViewingTAS = false
  651. local function ViewTASPlayback(TAS)
  652.     if ViewingTAS or #TAS == 0 then
  653.         if #TAS == 0 then print("No TAS data to play.") end
  654.         return
  655.     end
  656.     ViewingTAS = true
  657.     print("Starting TAS Playback...")
  658.  
  659.     local StartTime = tick()
  660.     local CurrentFrameIndex = 1
  661.     local PlaybackConnection
  662.  
  663.     -- Ensure character is present and accessible
  664.     if not LocalPlayer.Character then
  665.         LocalPlayer.CharacterAdded:Wait()
  666.     end
  667.     local Character = LocalPlayer.Character
  668.     if not Character or not Character:FindFirstChild("HumanoidRootPart") then
  669.         print("Character not found for playback.")
  670.         ViewingTAS = false
  671.         return
  672.     end
  673.     local RootPart = Character.HumanoidRootPart
  674.     local Hum = Character:FindFirstChildOfClass("Humanoid")
  675.      if not Hum then
  676.          print("Humanoid not found for playback.")
  677.          ViewingTAS = false
  678.          return
  679.      end
  680.     local Animator = Hum:FindFirstChildOfClass("Animator")
  681.  
  682.  
  683.     -- Ensure player is not controlled by user input during playback
  684.     if Hum then
  685.          Hum.AutoRotate = false -- Prevent automatic rotation
  686.          Hum.WalkSpeed = 0
  687.          Hum.JumpPower = 0
  688.          -- You might need to disable built-in movement scripts here
  689.          -- This is game-specific and can be tricky.
  690.          -- Example: Disable scripts in Character.CharacterScripts
  691.     end
  692.      RootPart.Anchored = true -- Anchor the root part for precise positioning
  693.  
  694.     if not Pause then UserPauseToggle() end -- Ensure paused before starting playback
  695.  
  696.     local function StopPlayback()
  697.         if PlaybackConnection then
  698.             PlaybackConnection:Disconnect()
  699.             PlaybackConnection = nil
  700.         end
  701.          if Hum then
  702.              Hum.AutoRotate = true -- Restore default behavior
  703.              Hum.WalkSpeed = 16 -- Restore default walk speed
  704.              Hum.JumpPower = 50 -- Restore default jump power
  705.              -- Re-enable built-in movement scripts if you disabled them
  706.          end
  707.         RootPart.Anchored = false -- Unanchor the root part
  708.         ViewingTAS = false
  709.         print("TAS Playback finished.")
  710.         task.wait() -- Give a moment before potentially re-pausing
  711.         -- UserPauseToggle() -- Decide if you want to automatically re-pause
  712.     end
  713.  
  714.     PlaybackConnection = RunService.Heartbeat:Connect(function()
  715.         local ElapsedTime = tick() - StartTime
  716.         local TargetFrame = nil
  717.  
  718.         -- Find the correct frame based on elapsed time
  719.         -- We iterate through frames to catch up if the game lags
  720.         while CurrentFrameIndex <= #TAS and TAS[CurrentFrameIndex].time <= ElapsedTime do
  721.              TargetFrame = TAS[CurrentFrameIndex]
  722.              CurrentFrameIndex = CurrentFrameIndex + 1
  723.         end
  724.  
  725.         if TargetFrame then
  726.              local cfData = TargetFrame.CCFrame
  727.              local camData = TargetFrame.CCameraCFrame
  728.              RootPart.CFrame = CFrame.new(cfData[1], cfData[2], cfData[3], cfData[4], cfData[5], cfData[6], cfData[7], cfData[8], cfData[9], cfData[10], cfData[11], cfData[12])
  729.              RootPart.Velocity = Vector3.new(TargetFrame.VVelocity[1], TargetFrame.VVelocity[2], TargetFrame.VVelocity[3])
  730.              Workspace.CurrentCamera.CFrame = CFrame.new(camData[1], camData[2], camData[3], camData[4], camData[5], camData[6], camData[7], camData[8], camData[9], camData[10], camData[11], camData[12])
  731.  
  732.              local AnimInfo = TargetFrame.AAnimation
  733.              if AnimInfo and Animator then
  734.                  -- Attempt to find and play the correct animation track
  735.                  local foundTrack = nil
  736.                  for _, track in ipairs(Animator:GetPlayingAnimationTracks()) do
  737.                      if track.Name == AnimInfo.Name then
  738.                           foundTrack = track
  739.                           break
  740.                      end
  741.                  end
  742.                  -- If the track isn't playing, try finding it among the humanoid's children
  743.                  if not foundTrack then
  744.                       local potentialTrack = Hum:FindFirstChild(AnimInfo.Name, true)
  745.                       if potentialTrack and potentialTrack:IsA("AnimationTrack") then
  746.                           foundTrack = potentialTrack
  747.                       end
  748.                  end
  749.  
  750.                  if foundTrack then
  751.                      if not foundTrack.IsPlaying then foundTrack:Play() end
  752.                      foundTrack:AdjustSpeed(AnimInfo.Weight or 1)
  753.                      -- Note: Setting TimePosition precisely for playback is complex
  754.                      -- based on how Roblox handles animation replication and blending.
  755.                      -- You might need to experiment or use a custom animation system
  756.                      -- for perfect animation sync.
  757.                      -- foundTrack.TimePosition = (ElapsedTime - (TargetFrame.time - (1/60))) % foundTrack.Length -- Rough attempt at syncing position
  758.                  else
  759.                      -- Optionally print a warning if an animation track isn't found
  760.                      -- print("Warning: Animation track not found for:", AnimInfo.Name)
  761.                  end
  762.              end
  763.         end
  764.  
  765.         -- Stop playback when all frames are processed
  766.         if CurrentFrameIndex > #TAS then
  767.             StopPlayback()
  768.         end
  769.     end)
  770. end
  771.  
  772. local function DisconnectAll()
  773.     if MainConnectionLoop then MainConnectionLoop:Disconnect() end
  774.     if KeybindsConnect then KeybindsConnect:Disconnect() end
  775.     if InputEndConnect then InputEndConnect:Disconnect() end
  776.     if DiedConnect then DiedConnect:Disconnect() end
  777.     if HUD then HUD:Destroy() end
  778.  
  779.     -- Ensure character state is reset
  780.     if LocalPlayer.Character then
  781.        local RootPart = LocalPlayer.Character:FindFirstChild("HumanoidRootPart")
  782.        if RootPart then
  783.           RootPart.Anchored = false
  784.        end
  785.        local Hum = LocalPlayer.Character:FindFirstChildOfClass("Humanoid")
  786.        if Hum then
  787.            Hum.AutoRotate = true -- Restore default behavior
  788.            Hum.WalkSpeed = 16 -- Restore default walk speed
  789.            Hum.JumpPower = 50 -- Restore default jump power
  790.            -- Re-enable built-in movement scripts if you disabled them
  791.        end
  792.     end
  793.  
  794.     -- Stop any active tasks
  795.     if FrameForwardTask and coroutine.status(FrameForwardTask) ~= "dead" then
  796.          task.cancel(FrameForwardTask)
  797.     end
  798.     if FrameBackTask and coroutine.status(FrameBackTask) ~= "dead" then
  799.          task.cancel(FrameBackTask)
  800.     end
  801.  
  802.     isFrameForwardHeld = false
  803.     isFrameBackHeld = false
  804.     ViewingTAS = false -- Ensure this is reset
  805.  
  806.     print("TAS Recorder Stopped.")
  807. end
  808.  
  809. local function Initialize()
  810.     -- Disconnect any existing connections just in case
  811.     DisconnectAll()
  812.  
  813.     Savestates = {}
  814.     PlayerInfo = {}
  815.     TimePaused = 0
  816.     Pause = true
  817.     TimeStart = tick()
  818.     TimePauseHolder = tick()
  819.  
  820.     -- Initial state saved as the first frame of the first savestate
  821.     -- This allows returning to the start point.
  822.     local initialCFrame = getCurrentCFrame()
  823.     local initialCamCFrame = getCurrentCameraCFrame()
  824.     local initialVelocity = getCurrentVelocity()
  825.     local initialAnimation = { Name = "Idle", Weight = 0 } -- Attempt to get initial animation
  826.  
  827.     -- Try to get the current animation state more accurately
  828.     local Hum = LocalPlayer.Character and LocalPlayer.Character:FindFirstChildOfClass("Humanoid")
  829.     if Hum then
  830.         local Animator = Hum:FindFirstChildOfClass("Animator")
  831.         if Animator then
  832.             local PlayingTracks = Animator:GetPlayingAnimationTracks()
  833.             for _, track in ipairs(PlayingTracks) do
  834.                 -- Prioritize tracks with weight > 0, or just pick the first playing one
  835.                  if track.Weight > 0 then
  836.                      initialAnimation = { Name = track.Name, Weight = track.Weight }
  837.                      break
  838.                  elseif #PlayingTracks > 0 then
  839.                      initialAnimation = { Name = PlayingTracks[1].Name, Weight = PlayingTracks[1].Weight }
  840.                  end
  841.             end
  842.         end
  843.     end
  844.  
  845.  
  846.     table.insert(Savestates, {{
  847.         CFrame = initialCFrame,
  848.         CameraCFrame = initialCamCFrame,
  849.         Velocity = initialVelocity,
  850.         Animation = initialAnimation,
  851.         Time = 0 -- Time starts at 0 for the initial state
  852.     }})
  853.  
  854.     SetUpGui()
  855.  
  856.     MainConnectionLoop = RunService.Heartbeat:Connect(function(deltaTime)
  857.         if not Pause and not ViewingTAS then -- Only record when not paused and not viewing playback
  858.             UpdateTimeGUI()
  859.             local currentInfo = ReturnPlayerInfo()
  860.  
  861.             -- Attempt to get current animation state while recording
  862.             local currentHum = LocalPlayer.Character and LocalPlayer.Character:FindFirstChildOfClass("Humanoid")
  863.             if currentHum then
  864.                 local currentAnimator = currentHum:FindFirstChildOfClass("Animator")
  865.                 if currentAnimator then
  866.                     local PlayingTracks = currentAnimator:GetPlayingAnimationTracks()
  867.                      local activeAnim = { Name = "Idle", Weight = 0 }
  868.                      for _, track in ipairs(PlayingTracks) do
  869.                          -- Capture the most relevant animation (e.g., highest weight)
  870.                          if track.Weight > activeAnim.Weight then
  871.                              activeAnim = { Name = track.Name, Weight = track.Weight }
  872.                          end
  873.                      end
  874.                      currentInfo.Animation = activeAnim
  875.                 end
  876.             end
  877.  
  878.  
  879.             table.insert(PlayerInfo, currentInfo)
  880.             UpdateGUIText()
  881.         end
  882.     end)
  883.  
  884.     -- Keep keyboard input for PC users, but prioritize mobile buttons
  885.     KeybindsConnect = UserInputService.InputBegan:Connect(function(Input, Typing)
  886.         if Typing or UserInputService.TouchEnabled then return end -- Ignore keyboard input on touch devices
  887.         local KeyCode = Input.KeyCode
  888.  
  889.         if KeyCode == Enum.KeyCode[Keybinds.UserPause] then
  890.             UserPauseToggle()
  891.         elseif KeyCode == Enum.KeyCode.One then -- Using direct KeyCode for PC
  892.             AddSavestate()
  893.         elseif KeyCode == Enum.KeyCode.Two then
  894.             RemoveSavestate()
  895.         elseif KeyCode == Enum.KeyCode.Eight then
  896.             BackSavestate()
  897.         elseif KeyCode == Enum.KeyCode.C then
  898.             CollisionToggler()
  899.         elseif KeyCode == Enum.KeyCode.Six then
  900.             SaveRun()
  901.         elseif KeyCode == Enum.KeyCode.Five then
  902.             task.spawn(FrameForwardStart)
  903.         elseif KeyCode == Enum.KeyCode.Four then
  904.              task.spawn(FrameBackStart)
  905.         elseif KeyCode == Enum.KeyCode.Delete then
  906.             DisconnectAll()
  907.         elseif KeyCode == Enum.KeyCode.Zero then
  908.             if not ViewingTAS then
  909.                  local CurrentTASData = PrepareTasData()
  910.                  ViewTASPlayback(CurrentTASData)
  911.             end
  912.         end
  913.     end)
  914.  
  915.     InputEndConnect = UserInputService.InputEnded:Connect(function(Input, Typing)
  916.          if Typing or UserInputService.TouchEnabled then return end -- Ignore keyboard input on touch devices
  917.         local KeyCode = Input.KeyCode
  918.         if KeyCode == Enum.KeyCode.Four then
  919.             isFrameBackHeld = false
  920.         elseif KeyCode == Enum.KeyCode.Five then
  921.             isFrameForwardHeld = false
  922.         end
  923.     end)
  924.  
  925.     -- Handle player death - reconnect the Died event if the character respawns
  926.     local function setupDeathHandler(char)
  927.          local Hum = char:FindFirstChildOfClass("Humanoid")
  928.          if Hum then
  929.              if DiedConnect then DiedConnect:Disconnect() end -- Disconnect old handler if any
  930.              DiedConnect = Hum.Died:Connect(function()
  931.                  print("Character died. Attempting to respawn and go to last savestate.")
  932.                  task.wait(0.1) -- Small wait for character to fully die
  933.                  if not Pause then UserPauseToggle() end -- Pause on death
  934.  
  935.                  local charAddedConn
  936.                  charAddedConn = LocalPlayer.CharacterAdded:Connect(function(newChar)
  937.                       charAddedConn:Disconnect() -- Disconnect this handler once character is added
  938.                       task.wait(1) -- Wait for character to load and humanoid to be ready
  939.                       BackSavestate() -- Go back to the last savestate
  940.                       -- Decide if you want to automatically unpause after returning
  941.                       -- if not Pause then UserPauseToggle() end
  942.                  end)
  943.              end)
  944.          end
  945.     end
  946.  
  947.     -- Initial setup for death handler if character exists
  948.     if LocalPlayer.Character then
  949.        setupDeathHandler(LocalPlayer.Character)
  950.     end
  951.     -- Connect CharacterAdded to set up the death handler for future characters
  952.     LocalPlayer.CharacterAdded:Connect(setupDeathHandler)
  953.  
  954.  
  955.      print("TAS Recorder Initialized.")
  956.      -- Anchor the character initially until the user unpauses
  957.      if LocalPlayer.Character then
  958.         local RootPart = LocalPlayer.Character:FindFirstChild("HumanoidRootPart")
  959.         if RootPart then
  960.             RootPart.Anchored = true
  961.         end
  962.      end
  963.      if TimeTextLabel then TimeTextLabel.TextColor3 = Color3.fromRGB(255, 255, 0) end
  964.      if CapLockPauseLabel then
  965.          CapLockPauseLabel.Text = "Status: Paused"
  966.          CapLockPauseLabel.TextColor3 = Color3.fromRGB(255, 255, 0)
  967.      end
  968.      -- Initial state is paused
  969.      UserPauseToggle()
  970.      if not Pause then UserPauseToggle() end -- Ensure it starts paused
  971.  
  972. end
  973.  
  974. Initialize(
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement