Functions / Scripts break in Team Test and In Live Game

Functions, Systems, Scripts and more break inside of Team Test and a Live Game but remain perfectly fine in Solo Test + Local 2-Player.
A friend and I are working on a Group-owned game. Recently, when testing in Team Test or playing in a Live Published Server we notice several things felt „broken“.

Things like Animations, Scripts, whole systems no longer seemed to work.
Server logs were completely empty and unresponsive, Client outputs infinite yield errors.

We haven’t made major changes recently and these exact features worked fine in previous test sessions. Our last Team Test session was about 4-5 days ago, no issues during the time.

I can also confirm again that: (Test Solo) and (Local 2-Player Server & Clients) Works flawlessly as intended, so no problems there.

What exactly is happening here?
Has this or anything similar happened to someone else before?

3 Likes

Team test has historically been broken even for working live games, I would not test in there but it’s been a while maybe they’ve fixed it. For live breaking when it works in test, that can absolutely happen because assets take longer to load, there is actual network latency (you can simulate it in Studio but I doubt you have that on right now), etc. Can you please show me just one system that breaks in live servers?

2 Likes

Sure, this is the main local script for a movement system, Under starter character. It was an open source system, then modified to fit our game and had always worked without error, regardless of the environment. Specifically the Running function no longer seems to work properly, like it just stops working entirely.

At the time of writing this, My friend has rewritten and edited some parts of code from functions that previously broke and it looks like it has partly fixed things, but no idea if thats a temporary or a permanent solution. These edits were not made to the code below, and the Running function still doesn’t play properly.


local Figure = script.Parent
local Torso = Figure:WaitForChild("Torso")
local RightShoulder = Torso:WaitForChild("Right Shoulder")
local LeftShoulder = Torso:WaitForChild("Left Shoulder")
local RightHip = Torso:WaitForChild("Right Hip")
local LeftHip = Torso:WaitForChild("Left Hip")
local Neck = Torso:WaitForChild("Neck")
local Humanoid = Figure:WaitForChild("Humanoid")
local pose = "Standing"

local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local UserInputService
local ContentProvider = game:GetService("ContentProvider")
local TweenService = game:GetService("TweenService")
local camera = workspace.CurrentCamera
local defaultFOV = camera.FieldOfView
local fovTween

local runEvent = ReplicatedStorage:WaitForChild("UpdateRunningState")

local isRunning = false

local originalWalkSpeed = 12
local runSpeedBoost = 10
local runAcceleration = 30
local targetWalkSpeed = originalWalkSpeed

local currentAnim = ""
local currentAnimInstance = nil
local currentAnimTrack = nil
local currentAnimKeyframeHandler = nil
local currentAnimSpeed = 1
local animTable = {}
local animNames = {
	idle =     {
		{ id = "http://www.roblox.com/asset/?id=110289680912584", weight = 9 },
		{ id = "http://www.roblox.com/asset/?id=130816015656148", weight = 1 }
	},
	walk =     {
		{ id = "http://www.roblox.com/asset/?id=138579556200263", weight = 10 }
	},
	jump =     {
		{ id = "http://www.roblox.com/asset/?id=116017024363424", weight = 10 }
	},
	fall =     {
		{ id = "http://www.roblox.com/asset/?id=113973815730424", weight = 10 }
	},
	climb = {
		{ id = "http://www.roblox.com/asset/?id=91233198382683", weight = 10 }
	},
	sit =     {
		{ id = "http://www.roblox.com/asset/?id=98026166204289", weight = 10 }
	},
	run = {
		{ id = "http://www.roblox.com/asset/?id=80814009141191", weight = 10 }
	},
}






local function setupToolNone()
	local toolNoneAnim = Instance.new("Animation")
	toolNoneAnim.Name = "ToolNoneAnim"
	toolNoneAnim.AnimationId = "rbxassetid://0" 

	local toolNoneValue = Instance.new("StringValue")
	toolNoneValue.Name = "toolnone"
	toolNoneAnim.Parent = toolNoneValue
	toolNoneValue.Parent = script
end

setupToolNone()




local idleWalkTransitionTime = 0.35

— Mobile Buttons 
local PlayerGui = Players.LocalPlayer:WaitForChild("PlayerGui")
local MainGui = PlayerGui:WaitForChild("Main")
local RunButtonMobile = MainGui:WaitForChild("RunButtonMobile")
local RunImage = RunButtonMobile:WaitForChild("ImageLabel")

local function UpdateRunButtonVisual()
	if isRunning then
		RunImage.ImageColor3 = Color3.fromRGB(99, 255, 75)
	else
		RunImage.ImageColor3 = Color3.fromRGB(255, 255, 255)
	end
end

function configureAnimationSet(name, fileList)
	if (animTable[name] ~= nil) then
		for _, connection in pairs(animTable[name].connections) do
			connection:disconnect()
		end
	end
	animTable[name] = {}
	animTable[name].count = 0
	animTable[name].totalWeight = 0
	animTable[name].connections = {}

	local config = script:FindFirstChild(name)
	if (config ~= nil) then
		table.insert(animTable[name].connections, config.ChildAdded:connect(function(child) configureAnimationSet(name, fileList) end))
		table.insert(animTable[name].connections, config.ChildRemoved:connect(function(child) configureAnimationSet(name, fileList) end))
		local idx = 1
		for _, childPart in pairs(config:GetChildren()) do
			if (childPart:IsA("Animation")) then
				table.insert(animTable[name].connections, childPart.Changed:connect(function(property) configureAnimationSet(name, fileList) end))
				animTable[name][idx] = {}
				animTable[name][idx].anim = childPart
				local weightObject = childPart:FindFirstChild("Weight")
				if (weightObject == nil) then
					animTable[name][idx].weight = 1
				else
					animTable[name][idx].weight = weightObject.Value
				end
				animTable[name].count = animTable[name].count + 1
				animTable[name].totalWeight = animTable[name].totalWeight + animTable[name][idx].weight
				idx = idx + 1
			end
		end
	end

	if (animTable[name].count <= 0) then
		for idx, anim in pairs(fileList) do
			animTable[name][idx] = {}
			animTable[name][idx].anim = Instance.new("Animation")
			animTable[name][idx].anim.Name = name
			animTable[name][idx].anim.AnimationId = anim.id
			animTable[name][idx].weight = anim.weight
			animTable[name].count = animTable[name].count + 1
			animTable[name].totalWeight = animTable[name].totalWeight + anim.weight
		end
	end
end

function scriptChildModified(child)
	local fileList = animNames[child.Name]
	if (fileList ~= nil) then
		configureAnimationSet(child.Name, fileList)
	end
end

script.ChildAdded:connect(scriptChildModified)
script.ChildRemoved:connect(scriptChildModified)

local function setupRunAnimation()
	local runValue = script:FindFirstChild("run")
	if runValue and runValue:IsA("StringValue") and runValue.Value ~= "" then
		animNames.run = { { id = runValue.Value, weight = 10 } }
	end
end

setupRunAnimation()

for name, fileList in pairs(animNames) do
	configureAnimationSet(name, fileList)
end

local function preloadAnimations()
	local assetsToLoad = {}
	for animName, animSet in pairs(animTable) do
		for i = 1, animSet.count do
			table.insert(assetsToLoad, animSet[i].anim)
		end
	end

	local success, err = pcall(function()
		ContentProvider:PreloadAsync(assetsToLoad)
	end)
end

preloadAnimations()
setupRunAnimation()

local jumpAnimTime = 0
local jumpAnimDuration = 0.3
local fallTransitionTime = 0.3
local jumpMaxLimbVelocity = 0.75

function stopAllAnimations()
	local oldAnim = currentAnim

	currentAnim = ""
	currentAnimInstance = nil
	if (currentAnimKeyframeHandler ~= nil) then
		currentAnimKeyframeHandler:disconnect()
	end

	if (currentAnimTrack ~= nil) then
		currentAnimTrack:Stop()
		currentAnimTrack:Destroy()
		currentAnimTrack = nil
	end
	return oldAnim
end

function setAnimationSpeed(speed)
	if speed ~= currentAnimSpeed then
		currentAnimSpeed = speed
		if currentAnimTrack then
			currentAnimTrack:AdjustSpeed(currentAnimSpeed)
		end
	end
end

function keyFrameReachedFunc(frameName)
	if (frameName == "End") then
		local repeatAnim = currentAnim
		local animSpeed = currentAnimSpeed
		playAnimation(repeatAnim, 0.0, Humanoid)
		setAnimationSpeed(animSpeed)
	end
end

function playAnimation(animName, transitionTime, humanoid)
	local roll = math.random(1, animTable[animName].totalWeight)
	local origRoll = roll
	local idx = 1
	while (roll > animTable[animName][idx].weight) do
		roll = roll - animTable[animName][idx].weight
		idx = idx + 1
	end
	local anim = animTable[animName][idx].anim

	if (anim ~= currentAnimInstance) then

		if (currentAnimTrack ~= nil) then
			currentAnimTrack:Stop(transitionTime)
			currentAnimTrack:Destroy()
		end

		currentAnimSpeed = 1.0

		currentAnimTrack = humanoid:LoadAnimation(anim)
		currentAnim = animName 
		if currentAnim == "climb" or currentAnim == "jump" or currentAnim == "fall" then
			currentAnimTrack.Priority = Enum.AnimationPriority.Core
		else
			currentAnimTrack.Priority = Enum.AnimationPriority.Movement
		end
		currentAnimTrack:Play(transitionTime)

		currentAnim = animName
		currentAnimInstance = anim

		if (currentAnimKeyframeHandler ~= nil) then
			currentAnimKeyframeHandler:disconnect()
		end
		currentAnimKeyframeHandler = currentAnimTrack.KeyframeReached:connect(keyFrameReachedFunc)

	end
end

local function tweenFOV(targetFOV)
	if fovTween then
		fovTween:Cancel()
	end

	local tweenInfo = TweenInfo.new(0.5, Enum.EasingStyle.Quad, Enum.EasingDirection.Out)
	fovTween = TweenService:Create(camera, tweenInfo, {FieldOfView = targetFOV})
	fovTween:Play()
end

local function getHumanoidRootPart()
	local hrp = Figure:FindFirstChild("HumanoidRootPart")
	return hrp
end

local function isCrouching()
	local hrp = getHumanoidRootPart()
	return hrp and hrp:GetAttribute("IsCrouching") == true
end

local function SetRunningState(running)
	if running then
		local stats = Players.LocalPlayer:FindFirstChild("Stats")
		local energy = stats and stats:FindFirstChild("Energy")
		if energy and energy.Value <= 0 then
			isRunning = false
			UpdateRunButtonVisual()
			return
		end
	end

	if running and isCrouching() then
		isRunning = false
	else
		isRunning = running
	end

	if isRunning then
		targetWalkSpeed = originalWalkSpeed + runSpeedBoost
	else
		targetWalkSpeed = originalWalkSpeed
	end

	UpdateRunButtonVisual()
	runEvent:FireServer(isRunning)
end

local stats = Players.LocalPlayer:WaitForChild("Stats")
local energy = stats:WaitForChild("Energy")

energy:GetPropertyChangedSignal("Value"):Connect(function()
	if energy.Value <= 0 and isRunning then
		SetRunningState(false)
	end
end)

function onRunning(speed)
	if speed > 0.01 then
		if isCrouching() then
			targetWalkSpeed = 8 
			return 
		end

		local backwards = false
		local HumanoidRootPart = getHumanoidRootPart()
		if HumanoidRootPart then
			local velocity = HumanoidRootPart.Velocity
			local look = HumanoidRootPart.CFrame.LookVector
			if velocity.Magnitude > 0.1 then
				local dot = velocity.Unit:Dot(look)
				if dot < -0.1 then backwards = true end
			end
		end
		

		local animToPlay = "walk"
		if backwards then
			targetWalkSpeed = originalWalkSpeed
			if isRunning then
				SetRunningState(false)
			end

			animToPlay = "walk"
			tweenFOV(defaultFOV)
			playAnimation(animToPlay, 0.1, Humanoid)
			setAnimationSpeed(-speed / 14.5)
		else
			if isRunning then
				animToPlay = "run"
				tweenFOV(defaultFOV + 15)
				setAnimationSpeed(1.3)
			else
				animToPlay = "walk"
				tweenFOV(defaultFOV)
				setAnimationSpeed(speed / 14.5)
			end
			playAnimation(animToPlay, 0.1, Humanoid)
		end
		pose = "Running"
	else
		playAnimation("idle", 0.1, Humanoid)
		pose = "Standing"
		tweenFOV(defaultFOV)
	end
end

function onDied()
	pose = "Dead"
end

function onJumping()
	playAnimation("jump", 0.1, Humanoid)
	jumpAnimTime = jumpAnimDuration
	pose = "Jumping"
end

function onClimbing(speed)
	playAnimation("climb", 0.1, Humanoid)
	setAnimationSpeed(speed / 12.0)
	pose = "Climbing"
end

function onGettingUp()
	pose = "GettingUp"
end

function onFreeFall()
	if (jumpAnimTime <= 0) then
		playAnimation("fall", fallTransitionTime, Humanoid)
	end
	pose = "FreeFall"
end

function onFallingDown()
	pose = "FallingDown"
end

function onSeated()
	pose = "Seated"
end

function onPlatformStanding()
	pose = "PlatformStanding"
end

function onSwimming(speed)
	if speed > 0 then
		pose = "Running"
	else
		pose = "Standing"
	end
end

function moveSit()
	RightShoulder.MaxVelocity = 0.15
	LeftShoulder.MaxVelocity = 0.15
	RightShoulder:SetDesiredAngle(3.14 /2)
	LeftShoulder:SetDesiredAngle(-3.14 /2)
	RightHip:SetDesiredAngle(3.14 /2)
	LeftHip:SetDesiredAngle(-3.14 /2)
end

local lastTick = 0

function move(time)
	local amplitude = 1
	local frequency = 1
	local deltaTime = time - lastTick
	lastTick = time

	if Humanoid.WalkSpeed < targetWalkSpeed then
		Humanoid.WalkSpeed = math.min(Humanoid.WalkSpeed + runAcceleration * deltaTime, targetWalkSpeed)
	elseif Humanoid.WalkSpeed > targetWalkSpeed then
		Humanoid.WalkSpeed = math.max(Humanoid.WalkSpeed - runAcceleration * deltaTime, targetWalkSpeed)
	end

	local climbFudge = 0
	local setAngles = false

	if (jumpAnimTime > 0) then
		jumpAnimTime = jumpAnimTime - deltaTime
	end

	if (pose == "FreeFall" and jumpAnimTime <= 0) then
		playAnimation("fall", fallTransitionTime, Humanoid)
	elseif (pose == "Seated") then
		playAnimation("sit", 0.5, Humanoid)
		return
	elseif (pose == "Running") then
	elseif (pose == "Dead" or pose == "GettingUp" or pose == "FallingDown" or pose == "Seated" or pose == "PlatformStanding") then
		stopAllAnimations()
		amplitude = 0.1
		frequency = 1
		setAngles = true
	end

	if (setAngles) then
		local desiredAngle = amplitude * math.sin(time * frequency)

		RightShoulder:SetDesiredAngle(desiredAngle + climbFudge)
		LeftShoulder:SetDesiredAngle(desiredAngle - climbFudge)
		RightHip:SetDesiredAngle(-desiredAngle)
		LeftHip:SetDesiredAngle(-desiredAngle)
	end

end

local function onInputBegan(input, gameProcessed)
	if gameProcessed then return end
	if input.KeyCode == Enum.KeyCode.LeftShift or input.KeyCode == Enum.KeyCode.ButtonL2 then
		SetRunningState(true)
	end
end

local function onInputEnded(input, gameProcessed)
	if input.KeyCode == Enum.KeyCode.LeftShift or input.KeyCode == Enum.KeyCode.ButtonL2 then
		SetRunningState(false)
	end
end

local function setupInputConnection()
	local player = Players.LocalPlayer
	if player then
		UserInputService = game:GetService("UserInputService")
		if player.Character == Figure or player.CharacterAdded:Wait() == Figure then
			local success, err = pcall(function()
				UserInputService.InputBegan:Connect(onInputBegan)
				UserInputService.InputEnded:Connect(onInputEnded)
			end)
		end
	end
end

spawn(function()
	wait(1)
	setupInputConnection()
end)

Humanoid.Died:connect(onDied)
Humanoid.Running:connect(onRunning)
Humanoid.Jumping:connect(onJumping)
Humanoid.Climbing:connect(onClimbing)
Humanoid.GettingUp:connect(onGettingUp)
Humanoid.FreeFalling:connect(onFreeFall)
Humanoid.FallingDown:connect(onFallingDown)
Humanoid.Seated:connect(onSeated)
Humanoid.PlatformStanding:connect(onPlatformStanding)
Humanoid.Swimming:connect(onSwimming)

local RootPart = getHumanoidRootPart()
if RootPart then
	RootPart:GetAttributeChangedSignal("IsCrouching"):Connect(function()
		local crouching = RootPart:GetAttribute("IsCrouching")

		if crouching then
			SetRunningState(false) 
			targetWalkSpeed = 8
		else
			targetWalkSpeed = originalWalkSpeed
			if isRunning then
				targetWalkSpeed = originalWalkSpeed + runSpeedBoost
			end
		end
	end)
end

playAnimation("idle", idleWalkTransitionTime, Humanoid)
pose = "Standing"

RunButtonMobile.Activated:Connect(function()
	SetRunningState(not isRunning)
end)


while Figure.Parent ~= nil do
	local _, time = wait(0.1)
	move(time)
end

Replace getHumanoidRootPart with

return Figure:WaitForChild("HumanoidRootPart", 2)

Tell me what happens, although this is just a guess. What happens in the console? Does an attempt to index nil with Velocity (or any other property) error occur

No errors relating to the movement system, and the running function actually appears working again, tested on a mobile device in a Live Experience, Not Team Test. So this is a issue related to character loading? Thank you for the assistance so far :sweat_smile:

1 Like

Great if it works you can mark it as a solution, and yes it does seem like you were trying to index HumanoidRootPart before it loaded

This goes for all systems; you are probably indexing stuff before it loads. Use wait for child

2 Likes

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.