Serversided Bindable Events considered nil as well as Animation playback difficulties

This is the situation I am in here:
So I have these bananas that a player can slip on.
When a player slips on a banana it does some various physics movements to fling them, bounce them off of walls etc.
During this slip state the player has an altered duplicate go over them in order to play out the animations due to abnormal animations on players causing physics issues.

Now here’s the problem:
In order for some specific bits of data to be transferred between the script that controls these slips and the clones Bindable Events are used due to both of them being on the server. Seems straightforward, however for some unknown reason ROBLOX considers these event instances nil and therefore cannot even attempt to fire to them.

To try fixing it I’ve also tried switching them to being Bindable Functions instead, and while that for some unholy reason actually made ROBLOX consider them valid instances, the slip script then freezes at the first Bindable Function call as it’s reliant on an animation playing, that animation being able to play just fine when Bindable Events are used.

Once again reiterating that all of this is taking place on the server, where all of this info should be easily accessible by the internals. While I could understand this sort of behavior from Client/Server interactions or vice versa, single-sided interactions are a little harder to understand here due to that side being completely able to access data on that side provided it was declared there ( which in the case of all of the instances discussed here, were ).

Ultimately, I require some help here in order to find a workaround that doesn’t majorly impact performance.

This is any additional info I can give that might be of use:

  • the clones and slip script are replicated from ReplicatedStorage via a script in ServerScriptService.
  • I have tried using one Bindable Function and three Bindable Functions for one part of the clone’s script that controls animation as using one was causing way too much delay from a necessary logic statement.
  • along with the event instances being considered nil, there have been instances where variables sent through them have come through as nil while not being like that prior.

I’d provide screenshots and such but honestly there isn’t really anything to show.

1 Like

Instead of screenshots, some code to show would be a bit more helpful than a description in helping others see what the issue could possibly be,

Make sure that your code is free of syntax errors, typos, and other mistakes that could be causing issues

how about both

all of the behind-the-scenes instances that are responsible for this

the script within the player clone

local ContentProvider = game:GetService("ContentProvider")
local Character = script.Parent
local Humanoid = Character:WaitForChild("Humanoid")
local CurrentAnimation = 0
local CharacterThing = nil

local FallBaseAnimation = Instance.new("Animation")

local StartR15Animation = Instance.new("Animation")
StartR15Animation.AnimationId = "rbxassetid://13054817280"
local StartR15Track = Humanoid:LoadAnimation(StartR15Animation)

local StartLoopR15Animation = Instance.new("Animation")
StartLoopR15Animation.AnimationId = "rbxassetid://13054821342"
local StartLoopR15Track = Humanoid:LoadAnimation(StartLoopR15Animation)

local LoopR15Animation = Instance.new("Animation")
LoopR15Animation.AnimationId = "rbxassetid://13054829432"
local LoopR15Track = Humanoid:LoadAnimation(LoopR15Animation)

local EndR15Animation = Instance.new("Animation")
EndR15Animation.AnimationId = "rbxassetid://13054848175"
local EndR15Track = Humanoid:LoadAnimation(EndR15Animation)

ContentProvider:PreloadAsync({StartR15Animation, StartLoopR15Animation, LoopR15Animation, EndR15Animation})

script.Parent.MorphinTime.OnInvoke = function(Appearance, ReceivedCharacter, FallAnimation)
	Humanoid:ApplyDescription(Appearance)
	FallBaseAnimation.AnimationId = FallAnimation
	local FallBaseTrack = Humanoid:LoadAnimation(FallBaseAnimation)
	FallBaseTrack:Play()
	CharacterThing = ReceivedCharacter
end

script.Parent.AnimationChange.OnInvoke = function(ReceivedAnimation)
	if ReceivedAnimation == 0 then
		CurrentAnimation = 0
		StartR15Track:Play()
		StartR15Track.Stopped:Wait()
		if CurrentAnimation == 0 then
			StartR15Track:Stop()
			StartLoopR15Track:Play()
		end
	elseif ReceivedAnimation == 1 then
		CurrentAnimation = 1
		StartR15Track:Stop()
		StartLoopR15Track:Stop()
		LoopR15Track:Play()
	elseif ReceivedAnimation == 2 then
		CurrentAnimation = 2
		LoopR15Track:Stop()
		EndR15Track:Play()
		EndR15Track.Stopped:Wait()
		CharacterThing.MakePlayerVisible:Fire()
	end
end

the slip script itself

local Character = script.Parent
local Humanoid = Character:WaitForChild("Humanoid")
local Player = game.Players:GetPlayerFromCharacter(Character)
local RigClone = nil
local RunningValue

local ParentParts = {}
local ThingsToIgnore = {}
for _,w in pairs(Character:GetDescendants()) do
	if w.ClassName == "Part" or w.ClassName == "BasePart" or w.ClassName == "UnionOperation" or w.ClassName == "MeshPart" then
		table.insert(ParentParts, w)
	end
end
for i, v in pairs(ParentParts) do
	table.insert(ThingsToIgnore, v)
end

Character.SlipEvent.Event:Connect(function()
	game.ReplicatedStorage.DisableControls:FireClient(Player)
	game.ReplicatedStorage.DisableShiftlock:FireClient(Player)
	Character.BananaSlipBool.Value = true
	local SlipSoundClone = Character.SlipSounds:Clone()
	SlipSoundClone.Parent = Character
	SlipSoundClone:Play()
	game.Debris:AddItem(SlipSoundClone, 0.9)
	for _,w in pairs(ParentParts) do
		if w.Name == "Head" then
			w.face.Transparency = 1
		end
		w.Transparency = 1
	end
	RigClone.HumanoidRootPart.CFrame = Character.HumanoidRootPart.CFrame
	RigClone.HumanoidRootPart.Anchored = false
	RigClone.HumanoidRootPart.WeldConstraint.Part1 = Character.HumanoidRootPart
	RigClone.AnimationChange:Invoke(0)
	local BounceCount = 0
	local BounceMultiplier = 1
	local AntiGroundBounceTimer = 0.35
	local AntiWallBounceTimer = 0.15
	local ForwardVelocity = 50
	local UpVelocity = 40
	local GravityFactor = 0
	local BounceType = false
	RunningValue = nil
	Character.HumanoidRootPart.BananaLinearVelocity.Enabled = true
	while BounceMultiplier > 0.5 or BounceCount <= 4 do wait()
		Character.HumanoidRootPart.BananaLinearVelocity.VectorVelocity = (Character.HumanoidRootPart.CFrame.LookVector * (ForwardVelocity * BounceMultiplier))
		Character.HumanoidRootPart.BananaLinearVelocity.VectorVelocity = Vector3.new(Character.HumanoidRootPart.BananaLinearVelocity.VectorVelocity.X, Character.HumanoidRootPart.BananaLinearVelocity.VectorVelocity.Y + ((UpVelocity * BounceMultiplier) + GravityFactor), Character.HumanoidRootPart.BananaLinearVelocity.VectorVelocity.Z)	
		local HitASurface = false
		local RayInstance = Ray.new(Character.HumanoidRootPart.Position, Vector3.new(0, -4.5, 0))
		local Result = workspace:FindPartOnRayWithIgnoreList(RayInstance, ThingsToIgnore, false, true)
		if Result ~= nil then
			if Result.ClassName == "Part" or Result.ClassName == "BasePart" or Result.ClassName == "UnionOperation" or Result.ClassName == "MeshPart" then
				if Result.Transparency >= 0.9 or Result.CanCollide == false then
					table.insert(ThingsToIgnore, Result)
				else
					if AntiGroundBounceTimer <= 0 then
						print(Result:GetFullName())
						HitASurface = true
						GravityFactor = 0
						AntiGroundBounceTimer = 0.1
						AntiWallBounceTimer = 0.1
						BounceType = false
					end
				end
			end
		end
		
		local RayInstance = Ray.new(Character.HumanoidRootPart.Position, Character.HumanoidRootPart.CFrame.LookVector.Unit * 3)
		local Result = workspace:FindPartOnRayWithIgnoreList(RayInstance, ThingsToIgnore, false, true)
		local RayInstance2 = Ray.new(Character.HumanoidRootPart.Position, -Character.HumanoidRootPart.CFrame.LookVector.Unit * 3)
		local Result2 = workspace:FindPartOnRayWithIgnoreList(RayInstance2, ThingsToIgnore, false, true)
		if Result ~= nil then
			if Result.ClassName == "Part" or Result.ClassName == "BasePart" or Result.ClassName == "UnionOperation" or Result.ClassName == "MeshPart" then
				if Result.Transparency >= 0.9 or Result.CanCollide == false then
					table.insert(ThingsToIgnore, Result)
				else
					if AntiWallBounceTimer <= 0 then
						print(Result:GetFullName())
						HitASurface = true
						if ForwardVelocity == 50 then
							ForwardVelocity = -50
						else
							ForwardVelocity = 50
						end
						GravityFactor = 0
						AntiGroundBounceTimer = 0.1
						AntiWallBounceTimer = 0.1
						BounceType = true
					end
				end
			end
		elseif Result2 ~= nil then
			if Result2.ClassName == "Part" or Result2.ClassName == "BasePart" or Result2.ClassName == "UnionOperation" or Result2.ClassName == "MeshPart" then
				if Result2.Transparency >= 0.9 or Result2.CanCollide == false then
					table.insert(ThingsToIgnore, Result2)
				else
					if AntiWallBounceTimer <= 0 then
						print(Result2:GetFullName())
						HitASurface = true
						if ForwardVelocity == 50 then
							ForwardVelocity = -50
						else
							ForwardVelocity = 50
						end
						GravityFactor = 0
						AntiGroundBounceTimer = 0.1
						AntiWallBounceTimer = 0.1
						BounceType = true
					end
				end
			end
		end
		--Character.SightlineConfirmationPart.Size = Vector3.new(0.5, 0.5, 2)
		--Character.SightlineConfirmationPart.CFrame = CFrame.new(Character.HumanoidRootPart.Position,Character.HumanoidRootPart.Position + Vector3.new(0,-2,0))
		--Character.SightlineConfirmationPart2.Size = Vector3.new(0.5, 0.5, 2)
		--Character.SightlineConfirmationPart2.CFrame = CFrame.new(Character.HumanoidRootPart.Position,Character.HumanoidRootPart.CFrame.LookVector.Unit * 2)
		AntiGroundBounceTimer -= 0.01
		AntiWallBounceTimer -= 0.01
		GravityFactor -= 2
		if GravityFactor <= -100 then
			GravityFactor = -100
		end
		if HitASurface == true then
			local SoundRNG = math.random(1,8)
			if SoundRNG == 1 then
				local SlipSoundClone = Character.SlipSounds:Clone()
				SlipSoundClone.Parent = Character
				SlipSoundClone.TimePosition = 1
				SlipSoundClone:Play()
				game.Debris:AddItem(SlipSoundClone, 0.65)
			elseif SoundRNG == 2 then
				local SlipSoundClone = Character.SlipSounds:Clone()
				SlipSoundClone.Parent = Character
				SlipSoundClone.TimePosition = 2
				SlipSoundClone:Play()
				game.Debris:AddItem(SlipSoundClone, 0.5)
			elseif SoundRNG == 3 then
				local SlipSoundClone = Character.SlipSounds:Clone()
				SlipSoundClone.Parent = Character
				SlipSoundClone.TimePosition = 3
				SlipSoundClone:Play()
				game.Debris:AddItem(SlipSoundClone, 0.5)
			elseif SoundRNG == 4 then
				local SlipSoundClone = Character.SlipSounds:Clone()
				SlipSoundClone.Parent = Character
				SlipSoundClone.TimePosition = 4
				SlipSoundClone:Play()
				game.Debris:AddItem(SlipSoundClone, 0.5)
			elseif SoundRNG == 5 then
				local SlipSoundClone = Character.SlipSounds:Clone()
				SlipSoundClone.Parent = Character
				SlipSoundClone.TimePosition = 5
				SlipSoundClone:Play()
				game.Debris:AddItem(SlipSoundClone, 0.5)
			elseif SoundRNG == 6 then
				local SlipSoundClone = Character.SlipSounds:Clone()
				SlipSoundClone.Parent = Character
				SlipSoundClone.TimePosition = 6
				SlipSoundClone:Play()
				game.Debris:AddItem(SlipSoundClone, 1.5)
			elseif SoundRNG == 7 then
				local SlipSoundClone = Character.SlipSounds:Clone()
				SlipSoundClone.Parent = Character
				SlipSoundClone.TimePosition = 8
				SlipSoundClone:Play()
				game.Debris:AddItem(SlipSoundClone, 0.5)
			elseif SoundRNG == 8 then
				local SlipSoundClone = Character.SlipSounds:Clone()
				SlipSoundClone.Parent = Character
				SlipSoundClone.TimePosition = 9
				SlipSoundClone:Play()
				game.Debris:AddItem(SlipSoundClone, 0.5)
			end
			if BounceType == false then
				BounceMultiplier -= 0.1
			elseif BounceType == true then
				BounceMultiplier -= 0.1
			end
			BounceCount += 1
			if BounceCount == 1 then
				RigClone.AnimationChange:Invoke(1)
			end
		end
	end
	local SoundRNG = math.random(1,3)
	if SoundRNG == 1 then
		local SlipSoundClone = Character.SlipSounds:Clone()
		SlipSoundClone.Parent = Character
		SlipSoundClone.TimePosition = 10
		SlipSoundClone:Play()
		game.Debris:AddItem(SlipSoundClone, 1.5)
	elseif SoundRNG == 2 then
		local SlipSoundClone = Character.SlipSounds:Clone()
		SlipSoundClone.Parent = Character
		SlipSoundClone.TimePosition = 12
		SlipSoundClone:Play()
		game.Debris:AddItem(SlipSoundClone, 1.8)
	elseif SoundRNG == 3 then
		local SlipSoundClone = Character.SlipSounds:Clone()
		SlipSoundClone.Parent = Character
		SlipSoundClone.TimePosition = 14
		SlipSoundClone:Play()
		game.Debris:AddItem(SlipSoundClone, 1.5)
	end
	RigClone.AnimationChange:Invoke(2)
	Character.HumanoidRootPart.BananaLinearVelocity.Enabled = false
	Character.BananaSlipBool.Value = false
	local Value = game.ReplicatedStorage.RunActiveCheck:InvokeClient(Player)
	if Value == false then
		Humanoid.WalkSpeed = 16
	elseif Value == true then
		Humanoid.WalkSpeed = 50
	end
	game.ReplicatedStorage.EnableControls:FireClient(Player)
	game.ReplicatedStorage.EnableShiftlock:FireClient(Player)
end)

Character.SetClone.Event:Connect(function(ReceivedClone)
	RigClone = ReceivedClone
	for _,w in pairs(RigClone:GetDescendants()) do
		if w.ClassName == "Part" or w.ClassName == "BasePart" or w.ClassName == "UnionOperation" or w.ClassName == "MeshPart" then
			table.insert(ThingsToIgnore, w)
		end
	end
end)

Character.MakePlayerVisible.Event:Connect(function()
	RigClone.HumanoidRootPart.WeldConstraint.Part1 = nil
	RigClone.HumanoidRootPart.Anchored = true
	RigClone.HumanoidRootPart.CFrame = CFrame.new(308.65, 70.5, 715.886)
	for _,w in pairs(ParentParts) do
		if w.Name == "Head" then
			w.face.Transparency = 0
			w.Transparency = 0
		elseif w.Name ~= "HumanoidRootPart" then
			w.Transparency = 0
		end
	end
end)

and the ServerScriptService respawn script

local Players = game:GetService("Players")

Players.PlayerAdded:Connect(function(player)
	local R15SlipClone = nil
	player.CharacterAdded:Connect(function(character)
		game.ReplicatedStorage.EnableControls:FireClient(player)
		local SlipSounds = game.ReplicatedStorage.SlipSounds:Clone()
		SlipSounds.Parent = character	
		local SlipEvent = game.ReplicatedStorage.SlipEvent:Clone()
		SlipEvent.Parent = character	
		local MakePlayerVisibleEvent = game.ReplicatedStorage.MakePlayerVisible:Clone()
		MakePlayerVisibleEvent.Parent = character
		local SetCloneEvent = game.ReplicatedStorage.SetClone:Clone()
		SetCloneEvent.Parent = character	
		local SlipScript = game.ReplicatedStorage.RatherGoofySlipScript:Clone()
		SlipScript.Parent = character	
		local BananaLinearVelocity = game.ReplicatedStorage.BananaLinearVelocity:Clone()
		BananaLinearVelocity.Parent = character.HumanoidRootPart
		local SlipAttachment = Instance.new("Attachment")
		SlipAttachment.Name = "SlipAttachment"
		SlipAttachment.Parent = character.HumanoidRootPart
		SlipAttachment.Position = Vector3.new(0,0,-0.5)
		SlipAttachment.Orientation = Vector3.new(0,90,0)
		BananaLinearVelocity.Attachment0 = SlipAttachment
		local BananaSlipBool = Instance.new("BoolValue")
		BananaSlipBool.Name = "BananaSlipBool"
		BananaSlipBool.Parent = character
		--local SightlineConfirmationPart = game.ReplicatedStorage.SightlineConfirmationPart:Clone()
		--SightlineConfirmationPart.Parent = character
		--local SightlineConfirmationPart2 = game.ReplicatedStorage.SightlineConfirmationPart2:Clone()
		--SightlineConfirmationPart2.Parent = character
		if R15SlipClone ~= nil then
			R15SlipClone:Destroy()
		end
		local Appearance = game:GetService("Players"):GetHumanoidDescriptionFromUserId(player.UserId)
		R15SlipClone = game.ReplicatedStorage.R15SlipClone:Clone()
		local AnimateScriptClone
		if character:FindFirstChild("LowerTorso") then
			AnimateScriptClone = character.Animate:Clone()
			AnimateScriptClone.Parent = R15SlipClone
		else
			AnimateScriptClone = game.ReplicatedStorage.StockAnimateScriptForEmergencies:Clone()
			AnimateScriptClone.Parent = R15SlipClone
		end
		R15SlipClone.Parent = workspace
		R15SlipClone.Humanoid.DisplayName = character.Humanoid.DisplayName
		R15SlipClone.MorphinTime:Invoke(Appearance, character, AnimateScriptClone.fall.FallAnim.AnimationId)
		SetCloneEvent:Fire(R15SlipClone)
		--game.Workspace.HideAndSeekLobbyHitbox.PlayerRespawnedServer:Fire(player)
	end)
end)

and lastly a demonstration of it in action

if you need to know the specifics of anything then ask away

1 Like

One possible solution could be to use RemoteEvents instead of Bindable Events. RemoteEvents are similar to Bindable Events but are designed to be used for communication between the client and the server. However, they can also be used for communication between different parts of the server. Using RemoteEvents might help to resolve the issue with the event instances being considered nil

remote events can communicate with different bits of the server?
the more you know I guess

I’ll give that a shot

Edit: ok I misunderstood that you just meant that they can go to the client and then to other bits of the server, ehh I guess I can also try that just incase

Edit 2: ok that just gave the same result as using a Bindable / Remote Function, that being that it either froze entirely or returned nil

also none to clean up, I already went and fixed the displayed ones earlier so it either just has no output at all or errors telling me that these clearly server-sided and visible instances are nil

Hm, another possible solution could be to restructure the code to eliminate the need for the altered duplicate of the player. Instead of creating a duplicate, the slip state could be handled by changing the player’s properties directly. This would eliminate the need for the Bindable Events and Bindable Functions and might help to resolve the issue

as much as I’d love to do that, that just isn’t an option at all.
( and I can say that with confidence after testing during the process of getting to how it is now )

as mentioned before the duplicate is needed to handle animations due to player physics being randomly different from any other ordinary rig and thus causing the jarring animations the slip uses to push and/or fling the player off course.
but additionally trying to force it all onto the player results in equally jarring rotations which cause the lookvector-based velocity to act up as well as flinging and other nonsense which mess with the raycasts used to identify when bounces should happen.

I don’t think relying on the communication between separate scripts that get enabled/defined right as the players character is loaded in is a very healthy practice. Specially since you are invoking functions/events from one script that are defined in another, like the wacky stuff going on between the slip script invoking functions that only get defined in the rigclone model’s script. I can think of potential scenarios where a bindable function is invoked before it has been defined yet, and other inconsistent behavior from cloning scripts onto a character.

Since basically all of the behavior for your scripts relies on the player’s character, why not script all the slipping logic upon the player’s character obtained from the characteradded event? in a serverscriptservice script?

It can even be fragmented like how you’ve done it, defining the bindable functions and events separately, where you could instead send the character object as a parameter rather than having to clone the event for every character that loads in.
It just seems really hardcoded and dependant on everything working exactly as expected when the scripts are cloned onto the character

yeah I think that could work, infact you’ve given me an idea of how to simplify all of this

Edit: on a side note, don’t you just love how sometimes in Studio something will work basically perfectly but then when you test it in an actual game it just spontaneously combusts on itself through some unspoken bug?

What is it returning nil for as there are 2 bindable functions I believe

1 Like

Alright, after reading through your post it gave me the idea to just combine the clone script into the regular one, and the results have been pretty great. The banana works in the actual game now without causing problems and I diagnosed that the other cause of problems in the actual game was Animation.Stopped:Wait() functions which I just replaced with wait()s ( bit of a bandaid fix but it’ll suffice ).

There’s just one problem: for some reason the animations for the slip don’t even show up, like, they are preloaded and everything and even after multiple times of slipping they just straight up don’t play which looks pretty off.

it’s definitely an improvement, it actually works ingame now, but that animation problem is a little too notable to go unfixed

turns out those animation errors were just attributed to asset permissions, problems solved

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