Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- -- Services
- local GuiService = game:GetService("GuiService")
- local RunService = game:GetService("RunService")
- local ReplicatedStorage = game:GetService("ReplicatedStorage")
- local TweenService = game:GetService("TweenService")
- local Players = game:GetService("Players")
- local player = Players.LocalPlayer
- local playerGui = player.PlayerGui
- local favoriteCooldown = 0.5
- -- Modules
- local Knit = require(ReplicatedStorage.Packages.Knit)
- local EffectsUtil = require(ReplicatedStorage.SharedSource.Externals.Utilities.Effects)
- local OthersUtil = require(ReplicatedStorage.SharedSource.Externals.Utilities.Others)
- local FXSoundsUtil = EffectsUtil.Sounds
- local FXGuiUtil = EffectsUtil.GUI
- local DancesDatas = require(ReplicatedStorage.SharedSource.Datas:WaitForChild("DancesDatas"))
- local assets = ReplicatedStorage:WaitForChild("Assets")
- local animsDatas = DancesDatas.Animations
- local sounds = DancesDatas.Sounds
- local clickSound = assets.Sounds.Click
- local DanceGui = playerGui:WaitForChild("DanceGui")
- local danceFrame = DanceGui:WaitForChild("DanceFrame")
- local danceSearchBar = danceFrame.SearchBar
- local danceScroll = danceFrame.DanceScroll
- local promptFrame = danceFrame.PromptFrame
- local templateButton = assets.GUIs.Dances.DanceButtonTemplate
- local tweenInfo = TweenInfo.new(0.5, Enum.EasingStyle.Sine, Enum.EasingDirection.Out)
- local plr = game.Players.LocalPlayer
- local DanceController = Knit.CreateController({
- Name = "DanceController",
- -- other
- CurrentPromptFrame = nil,
- IsPurchaseInProgress = false,
- IsPromptActive = false,
- IsProccessing = false,
- DanceOrder = {},
- })
- ---- Services
- local DanceService, ProfileService
- ---- Controllers
- local DataController, WarningsController, GuiController, AnimSoundController
- local ProfileData
- local DancesUnlocked
- local favoriteDances
- function DanceController:FindDancesDataByName(name)
- for i, data in ipairs(DancesDatas.Animations) do
- if data.Name == name then
- return data, i
- end
- end
- for _, data in ipairs(DancesDatas["Gacha Animations"]) do
- if data.Name == name then
- return data
- end
- end
- for _, data in ipairs(DancesDatas["Roblox-Made Animations"]) do
- if data.Name == name then
- return data
- end
- end
- return nil -- Return nil if no match is found
- end
- function DanceController:GetSortedDancesDatas()
- local unlockableDatas = table.clone(DancesDatas["Gacha Animations"])
- local unlockedDatas = {}
- local i = 1 -- Initialize the counter
- while i <= #DancesDatas.Animations or i <= #DancesDatas["Roblox-Made Animations"] do
- -- Add from Animations if it exists.
- if DancesDatas.Animations[i] then
- table.insert(unlockedDatas, DancesDatas.Animations[i])
- end
- -- Add from Roblox-Made Animations if it exists.
- if DancesDatas["Roblox-Made Animations"][i] then
- table.insert(unlockedDatas, DancesDatas["Roblox-Made Animations"][i])
- end
- i = i + 1 -- Increment the counter
- end
- local lockedDatas = {}
- for i=1, #unlockableDatas do
- local danceData = unlockableDatas[i]
- if DanceController:IsDanceOwned(danceData.Name) then
- table.insert(unlockedDatas, danceData)
- else
- table.insert(lockedDatas, danceData)
- end
- end
- local sortedData = {}
- for i=1,#unlockedDatas do
- table.insert(sortedData, unlockedDatas[i])
- end
- for i=1,#lockedDatas do
- table.insert(sortedData, lockedDatas[i])
- end
- local lockedDatasNames = {}
- local unlockedDatasNames = {}
- for i=1,#lockedDatas do
- table.insert(lockedDatasNames, lockedDatas[i].Name)
- end
- for i=1,#unlockedDatas do
- table.insert(unlockedDatasNames, unlockedDatas[i].Name)
- end
- return sortedData, unlockedDatasNames, lockedDatasNames
- end
- function DanceController:IsDanceOwned(danceName)
- ProfileData = DataController.Data
- -- update
- DancesUnlocked = DataController.Data.DancesUnlocked
- -- check purchased Dance
- return table.find(ProfileData.DancesUnlocked, danceName)
- end
- function DanceController:IsDanceFavorited(danceName)
- ProfileData = DataController.Data
- -- update
- favoriteDances = DataController.Data.FavoriteDances
- -- check purchased Dance
- return favoriteDances[danceName] == true
- end
- local function SetDanceLayoutOrder(templateClone, danceName, val0, val1)
- local isDanceOwned = DanceController:IsDanceOwned(danceName)
- if isDanceOwned then
- templateClone.LayoutOrder = val0
- else
- templateClone.LayoutOrder = val1
- end
- end
- function DanceController:UpdateOrderDance()
- DanceController.DanceOrder = {}
- for danceName, isFavorited in pairs(favoriteDances) do
- if isFavorited then
- table.insert(DanceController.DanceOrder, danceName)
- end
- end
- for _, data in pairs(animsDatas) do
- local danceName = data.Name
- if not favoriteDances[danceName] then
- table.insert(DanceController.DanceOrder, danceName)
- end
- end
- end
- function DanceController:ReorderDances()
- for _, danceName in pairs(DanceController.DanceOrder) do
- local isFavorited = DanceController:IsDanceFavorited(danceName)
- local isDanceOwned = DanceController:IsDanceOwned(danceName)
- local templateClone = danceScroll:WaitForChild(danceName)
- local favoriteButton = templateClone:WaitForChild("FavoriteButton")
- if isFavorited then
- favoriteButton.Image = "rbxassetid://1178571805"
- SetDanceLayoutOrder(templateClone, danceName, -3, -1)
- else
- favoriteButton.Image = "rbxassetid://279798627"
- SetDanceLayoutOrder(templateClone, danceName, -2, 0)
- end
- if isDanceOwned then
- templateClone.TextLabel.TextColor3 = Color3.fromRGB(255, 255, 255)
- templateClone.TextLabel.TextTransparency = 0
- if isFavorited then
- templateClone.LayoutOrder = -3
- else
- templateClone.LayoutOrder = -2
- end
- else
- templateClone.TextLabel.TextColor3 = Color3.fromRGB(144, 144, 144)
- templateClone.TextLabel.TextTransparency = 0.5
- if isFavorited then
- templateClone.LayoutOrder = -1
- else
- templateClone.LayoutOrder = -0
- end
- end
- end
- end
- local function createTemplateClone(template, parent, templateName, text, additionalText, imageId)
- local templateClone = template:Clone()
- templateClone.Name = templateName
- if text then
- templateClone.Text = ""
- if additionalText then
- templateClone.TextLabel.Text = text .. additionalText
- else
- templateClone.TextLabel.Text = text
- end
- elseif imageId then
- templateClone.Image = imageId
- end
- templateClone.Parent = parent
- return templateClone
- end
- function DanceController:FindCarryAnimationDataByName(name)
- for _, data in ipairs(animsDatas) do
- if data.Name == name then
- return data
- end
- end
- return nil -- Return nil if no match is found
- end
- function DanceController:Dance(danceName)
- local animData = DanceController:FindCarryAnimationDataByName(danceName)
- local soundData = sounds[danceName]
- DanceService.SyncDance:Fire()
- DanceController:SyncDance(nil, player)
- local track, sound = AnimSoundController:PlayAnimationAndSound(animData, soundData, danceName, true)
- if track then
- DanceService.ChangeDance:Fire(danceName)
- else
- DanceService.ChangeDance:Fire()
- end
- end
- local favoriteMouseConnections = {}
- local templateMouseConnections = {}
- function DanceController:CreateDances()
- for _, danceName in ipairs(DanceController.DanceOrder) do
- local animData = DanceController:FindCarryAnimationDataByName(danceName)
- local soundData = sounds[danceName]
- if animData then
- local char = player.Character or player.CharacterAdded:Wait()
- local humanoid = char:WaitForChild("Humanoid")
- local templateClone = danceScroll:FindFirstChild(danceName)
- if not templateClone then
- templateClone =
- createTemplateClone(templateButton, danceScroll, danceName, danceName, nil)
- end
- local favoriteButton = templateClone:WaitForChild("FavoriteButton")
- -- Favorite Dance
- if not favoriteMouseConnections[danceName] then
- favoriteMouseConnections[danceName] = favoriteButton.Activated:Connect(function()
- AnimSoundController:FavoriteAnimationAndSound(favoriteButton, favoriteDances, "Dances")
- end)
- end
- -- Buying Dance Proccess
- if not templateMouseConnections[danceName] then
- templateMouseConnections[danceName] = templateClone.Activated:Connect(function()
- local isDanceOwned = DanceController:IsDanceOwned(danceName)
- if isDanceOwned then
- DanceController:Dance(danceName)
- end
- end)
- end
- end
- end
- end
- function DanceController:LoadAnimation()
- -- no preload needed
- --for _, animationName in pairs(DanceController.DanceOrder) do
- -- local animData = DanceController:FindCarryAnimationDataByName(animationName)
- -- if animData then
- -- AnimSoundController:LoadAnimation(animData, animationName)
- -- end
- --end
- end
- function DanceController:TweenToLeft(toTween, goal)
- local tweenInfo = TweenInfo.new(0.5, Enum.EasingStyle.Sine, Enum.EasingDirection.Out)
- local tween = TweenService:Create(toTween, tweenInfo, goal)
- return tween
- end
- function DanceController:ToggleFrameVisible(frame, boolVal, isTweenToLeft, goal)
- local tween
- if isTweenToLeft and goal then
- tween = DanceController:TweenToLeft(frame, goal)
- tween:Play()
- if boolVal == true then
- frame.Visible = boolVal
- return
- end
- tween.Completed:Wait()
- end
- frame.Visible = boolVal
- end
- -- Function to check if an animation is a dance
- function DanceController:IsDancing(humanoid)
- for _, danceTrack in pairs(humanoid:GetPlayingAnimationTracks()) do
- for i=1,#DancesDatas.Animations do
- local animData = DancesDatas.Animations[i]
- local animIds = {
- "Id",
- "WalkId",
- "LoopId"
- }
- local danceName = animData.Name
- for i2=1,#animIds do
- local dataName = animIds[i2]
- if animData[dataName] == danceTrack.Animation.AnimationId then
- return true, danceName, danceTrack
- end
- end
- end
- end
- return false
- end
- local function stopDances(humanoid)
- local bool, danceName, danceTrack
- repeat
- task.wait()
- bool, danceName, danceTrack = DanceController:IsDancing(humanoid)
- if danceTrack then
- danceTrack:Stop()
- AnimSoundController:StopSound(humanoid.Parent.HumanoidRootPart, danceName)
- end
- until not bool
- end
- local syncDanceThreads = {}
- local syncDanceThreads2 = {}
- function DanceController:SyncDance(player2,
- specificPlayer,
- dontDestroyThreads -- true = threads won't get destroyed
- )
- if not player2 then
- stopDances(specificPlayer.Character.Humanoid)
- if not dontDestroyThreads then
- if syncDanceThreads[specificPlayer] and coroutine.status(syncDanceThreads[specificPlayer]) ~= "dead" then
- task.cancel(syncDanceThreads[specificPlayer])
- syncDanceThreads[specificPlayer] = nil
- end
- if syncDanceThreads2[specificPlayer] and coroutine.status(syncDanceThreads2[specificPlayer]) ~= "dead" then
- task.cancel(syncDanceThreads2[specificPlayer])
- syncDanceThreads2[specificPlayer] = nil
- end
- else
- if specificPlayer == player then
- AnimSoundController:StopAnimationAndSound(specificPlayer.Character.HumanoidRootPart, AnimSoundController.CurrentSoundName)
- end
- end
- return
- end
- local character = player2.Character
- local humanoid = character and character:FindFirstChild("Humanoid")
- if humanoid then
- local bool, danceName, danceTrack
- local animData
- for i=1, 10 do
- bool, danceName, danceTrack = DanceController:IsDancing(humanoid)
- animData = DanceController:FindCarryAnimationDataByName(danceName)
- if animData then
- break
- end
- task.wait(0.1)
- end
- local targetPlayer = player
- if specificPlayer then
- targetPlayer = specificPlayer
- if specificPlayer == player then
- specificPlayer = nil
- end
- end
- if syncDanceThreads[targetPlayer] and coroutine.status(syncDanceThreads[targetPlayer]) ~= "dead" then
- task.cancel(syncDanceThreads[targetPlayer])
- end
- syncDanceThreads[targetPlayer] = task.spawn(function()
- if specificPlayer then
- -- other players
- local track = specificPlayer.Character.Humanoid:WaitForChild("Animator"):LoadAnimation(danceTrack.Animation)
- repeat task.wait() until track.Length ~= 0
- track:Play()
- track.TimePosition = danceTrack.TimePosition
- else
- -- self
- local loadedAnimTrack = AnimSoundController:LoadAnimation(animData, danceName)
- repeat task.wait() until loadedAnimTrack.Length ~= 0
- local soundData = sounds[danceName]
- local track, sound = AnimSoundController:PlayAnimationAndSound(animData, soundData, danceName, true)
- if track then
- track.TimePosition = danceTrack.TimePosition
- if sound then
- sound.TimePosition = danceTrack.TimePosition
- end
- DanceService.SyncDance:Fire(player2)
- else
- DanceService.SyncDance:Fire()
- DanceController:SyncDance(nil, player, true)
- if syncDanceThreads2[targetPlayer] and coroutine.status(syncDanceThreads2[targetPlayer]) ~= "dead" then
- task.cancel(syncDanceThreads2[targetPlayer])
- end
- return
- end
- if syncDanceThreads2[targetPlayer] and coroutine.status(syncDanceThreads2[targetPlayer]) ~= "dead" then
- task.cancel(syncDanceThreads2[targetPlayer])
- end
- syncDanceThreads2[targetPlayer] = task.spawn(function()
- while true do
- task.wait(0.1)
- local bool2, danceName2, danceTrack2 = DanceController:IsDancing(humanoid)
- if not bool2 then
- stopDances(player.Character.Humanoid)
- elseif danceName2 ~= danceName then
- -- resets dance syncer when player2 changes dance
- task.delay(0.1, function()
- if bool then
- DanceController:SyncDance(player2, specificPlayer)
- else
- AnimSoundController:StopAnimationAndSound(player.Character.HumanoidRootPart, AnimSoundController.CurrentSoundName)
- end
- end)
- if bool then
- return
- end
- end
- end
- end)
- end
- end)
- end
- end
- function DanceController:SetupSyncDanceButton(player2, bool, danceName)
- local char = player2.Character
- local syncDancePrompt = char.HumanoidRootPart:FindFirstChild("SyncDancePrompt")
- if bool then
- if not syncDancePrompt then
- syncDancePrompt = Instance.new("ProximityPrompt")
- syncDancePrompt.Name = "SyncDancePrompt"
- syncDancePrompt.ActionText = "Sync Dance"
- syncDancePrompt.ObjectText = danceName or ""
- syncDancePrompt.Style = Enum.ProximityPromptStyle.Custom
- syncDancePrompt.KeyboardKeyCode = Enum.KeyCode.F
- syncDancePrompt.GamepadKeyCode = Enum.KeyCode.DPadUp
- syncDancePrompt.RequiresLineOfSight = false
- syncDancePrompt.Parent = char.HumanoidRootPart
- syncDancePrompt.Triggered:Connect(function()
- clickSound:Play()
- DanceService:GetSyncedDancers(player2):andThen(function(player2_syncedDanceTable)
- local toSync = player2_syncedDanceTable.ToSync or player2
- if toSync == player then
- WarningsController:WarnPlayer("This player is currently dance-synced to you. Failed to sync.", Color3.fromRGB(255, 0, 0),{
- Duration = 4
- })
- return
- end
- DanceController:SyncDance(toSync)
- end)
- end)
- -- repositions all proximity prompt
- OthersUtil.ProximityPromptSetup(char.HumanoidRootPart, nil, Vector2.new(0, 60))
- end
- else
- if syncDancePrompt then
- syncDancePrompt:Destroy()
- -- repositions all proximity prompt
- OthersUtil.ProximityPromptSetup(char.HumanoidRootPart)
- end
- end
- end
- function DanceController:KnitStart()
- -- waits for profile to load on client
- DataController:WaitUntilProfileLoaded()
- ProfileData = DataController.Data
- DancesUnlocked = ProfileData.DancesUnlocked
- favoriteDances = ProfileData.FavoriteDances
- DanceController:UpdateOrderDance()
- DanceController:LoadAnimation()
- DanceController:CreateDances()
- DanceController:ReorderDances()
- player.CharacterAdded:Connect(function(character)
- repeat
- task.wait()
- until not character or character.Parent == workspace.Characters
- if not character then
- return
- end
- DanceController:LoadAnimation()
- end)
- local danceGui = playerGui:WaitForChild("DanceGui")
- local DanceFrame = danceGui:WaitForChild("DanceFrame")
- local ToHideLeftValue = { Position = UDim2.new(-0.16, 0, 0.25, 0) }
- local ToShowLeftValue = { Position = UDim2.new(0.137, 0, 0.25, 0) }
- local isTweening = false
- local function ShowLeftFrame(frame1)
- if not isTweening then
- isTweening = true
- FXSoundsUtil.CreateSoundThenPlay(clickSound, {}, plr, 2)
- if frame1.Visible then
- -- close frame
- DanceController:ToggleFrameVisible(frame1, false, true, ToHideLeftValue)
- isTweening = false
- else
- -- open frame
- DanceController:ToggleFrameVisible(frame1, true, true, ToShowLeftValue)
- isTweening = false
- end
- end
- end
- local mainGui = playerGui:WaitForChild("MainGui")
- --local openDanceButton = mainGui:WaitForChild("DancesButton")
- --openDanceButton.Activated:Connect(function()
- -- ShowLeftFrame(DanceFrame)
- --end)
- danceSearchBar:GetPropertyChangedSignal("Text"):Connect(function()
- local search = string.lower(danceSearchBar.Text)
- for _, Button in pairs(DanceFrame.DanceScroll:GetChildren()) do
- if Button:IsA("GuiButton") then
- if search ~= "" then
- local item = string.lower(Button.TextLabel.Text)
- if string.find(item, search) then
- Button.Visible = true
- else
- Button.Visible = false
- end
- else
- Button.Visible = true
- end
- end
- end
- end)
- ProfileService.UpdateSpecificData:Connect(function(Redirectories,newValue)
- task.wait()
- if Redirectories[1] == "FavoriteDances" or Redirectories[1] == "DancesUnlocked" then
- DanceController:UpdateOrderDance()
- DanceController:ReorderDances()
- end
- end)
- DanceService.SyncDance:Connect(function(...)
- DanceController:SyncDance(...)
- end)
- task.spawn(function()
- while true do
- game["Run Service"].RenderStepped:Wait()
- local succ, err = pcall(function()
- for _,player2 in pairs(game.Players:GetPlayers()) do
- if player2 ~= plr then
- local char = player2.Character
- local HRP = char and char:FindFirstChild("HumanoidRootPart")
- if not HRP then
- continue
- end
- local bool, danceName = DanceController:IsDancing(char.Humanoid)
- if bool then
- DanceController:SetupSyncDanceButton(player2, true, danceName)
- else
- DanceController:SetupSyncDanceButton(player2, false, danceName)
- end
- end
- end
- end)
- if not succ then
- warn(err)
- end
- end
- end)
- end
- function DanceController:KnitInit()
- ---- Services
- DanceService = Knit.GetService("DanceService")
- ProfileService = Knit.GetService("ProfileService")
- ---- Controllers
- DataController = Knit.GetController("DataController")
- WarningsController = Knit.GetController("WarningsController")
- GuiController = Knit.GetController("GuiController")
- AnimSoundController = Knit.GetController("AnimSoundController")
- end
- return DanceController
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement