CCCPaste

a4aa8dc9cf1c5

-- StarterPlayer/StarterPlayerScripts/RootMotionClient.lua
local Players = game:GetService("Players")
local RunService = game:GetService("RunService")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local UserInputService = game:GetService("UserInputService")
local AbilityEvent = ReplicatedStorage:WaitForChild("RootMotionAbility")
local player = Players.LocalPlayer
local AbilityConfig = {
	DashSlash = {
		Duration = 0.4,
		Range = 18,
	},
}
local Animations = {
	DashSlash = "", 
}
local CurrentAbility = nil
local function easeInOutQuad(t)
	if t <= 0 then
		return 0
	end
	if t >= 1 then
		return 1
	end
	if t < 0.5 then
		return 2 * t * t
	else
		local u = -2 * t + 2
		return 1 - (u * u) / 2
	end
end
local function getCharacterParts()
	local character = player.Character or player.CharacterAdded:Wait()
	local root = character:FindFirstChild("HumanoidRootPart")
	local humanoid = character:FindFirstChildOfClass("Humanoid")
	local animator = humanoid and humanoid:FindFirstChildOfClass("Animator")
	return character, root, humanoid, animator
end
local function playAbilityAnimation(abilityId)
	local animId = Animations[abilityId]
	if not animId or animId == "" then
		print("Client no animation id for", abilityId, "movement will still play")
		return
	end
	local _, _, humanoid, animator = getCharacterParts()
	if not humanoid then
		print("Client no humanoid for animation")
		return
	end
	local targetAnimator = animator or humanoid:FindFirstChildOfClass("Animator")
	if not targetAnimator then
		print("Client no animator for animation")
		return
	end
	local animation = Instance.new("Animation")
	animation.AnimationId = animId
	local track = targetAnimator:LoadAnimation(animation)
	track:Play()
end
local function onServerStart(abilityId, startTime, startCFrame)
	local config = AbilityConfig[abilityId]
	if not config then
		print("Client unknown ability", abilityId)
		return
	end
	local _, root = getCharacterParts()
	if not root then
		print("Client no root to start ability")
		return
	end
	if CurrentAbility then
		print("Client ability already active, ignoring", abilityId)
		return
	end
	CurrentAbility = {
		AbilityId = abilityId,
		StartTime = startTime,
		StartCFrame = startCFrame,
		Facing = startCFrame.LookVector,
		LastAlpha = 0,
	}
	print("Client ability start", abilityId, "at", startTime)
	playAbilityAnimation(abilityId)
end
AbilityEvent.OnClientEvent:Connect(function(action, abilityId, startTime, startCFrame)
	if action == "Start" then
		onServerStart(abilityId, startTime, startCFrame)
	end
end)
UserInputService.InputBegan:Connect(function(input, gameProcessed)
	if gameProcessed then
		return
	end
	if input.UserInputType == Enum.UserInputType.Keyboard and input.KeyCode == Enum.KeyCode.Q then
		if CurrentAbility then
			print("Client ability already active, cannot request")
			return
		end
		print("Client requesting DashSlash")
		AbilityEvent:FireServer("Request", "DashSlash")
	end
end)
RunService.RenderStepped:Connect(function()
	local state = CurrentAbility
	if not state then
		return
	end
	local config = AbilityConfig[state.AbilityId]
	if not config then
		print("Client missing config during ability, cancelling")
		CurrentAbility = nil
		return
	end
	local _, root = getCharacterParts()
	if not root then
		print("Client lost root during ability, cancelling")
		CurrentAbility = nil
		return
	end
	local now = os.clock()
	local alpha = (now - state.StartTime) / config.Duration
	if alpha >= 1 then
		print("Client ability finished", state.AbilityId)
		CurrentAbility = nil
		return
	end
	local distNow = config.Range * easeInOutQuad(alpha)
	local distLast = config.Range * easeInOutQuad(state.LastAlpha)
	state.LastAlpha = alpha
	local target = state.StartCFrame + state.Facing * distNow
	root.CFrame = root.CFrame:Lerp(target, 0.3)
end)