Trail shop not working

Hello, I made a trail shop (GUI fully working) and trails already made but I’m having problems with equipping the trails, so for example if I click a button for the trail that costs 300 coins, the coins are removed from the balance of the player but the trail doesn’t appear (video below) and gives no error in output.
The trails are in a folder named “Trails” in ServerStorage.

Below I’m leaving the scripts:

TrailHandler This should handle all of the trails, inside of ReplicatedStorage I have placed a RemoteEvent named “EquipTrail”

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Trails = ReplicatedStorage.Trails

local EquipTrail = ReplicatedStorage.EquipTrail



EquipTrail.OnServerEvent:Connect(function(player, trail)
	local character = player.Character
	if not character:FindFirstChild(trail) then
		for i,v in pairs(character:GetChildren()) do
			if v:IsA("Trail") then
				v:remove()
			end
		end
		local trailCopy = Trails[trail]:Clone()
		trailCopy.Parent = character
		trailCopy.Attachment0 = character.Head.At1
		trailCopy.Attachment1 = character.HumanoidRootPart.At2
	end
end)

Leaderstats that controls the jumps and coins. From line 59 to 68 there is the function regarding the trails.

local DataStoreService = game:GetService("DataStoreService")
local jumpsDatastore = DataStoreService:GetDataStore("JumpsDataStore")

local function loadData(datastore, key)
	local success, data = pcall(function()
		return datastore:GetAsync(key)
	end)

	return data
end

local function saveData(datastore, key, value)
	local success, err = pcall(function() 
		datastore:SetAsync(key, value)
	end)

	if err then print(err) end
end

game.Players.PlayerAdded:Connect(function(player)
	local leaderstats = Instance.new("Folder")
	leaderstats.Name = "leaderstats"
	leaderstats.Parent = player 

	local jumpCount = Instance.new("IntValue")
	jumpCount.Name = "Jumps"
	jumpCount.Parent = leaderstats
	jumpCount.Value = loadData(jumpsDatastore, player.UserId) or 0
	
	local coins = Instance.new("NumberValue")
	coins.Parent = player.leaderstats
	coins.Name = "Coins"


	player.CharacterAdded:Connect(function(character) 

		local humanoid = character:WaitForChild("Humanoid")
		local debounce = true

		humanoid:GetPropertyChangedSignal("Jump"):Connect(function()
			if debounce == true then
				debounce = false
				if humanoid.Jump == true then
					jumpCount.Value = jumpCount.Value + 1
				end
				wait(0.2)
				debounce = true 
			end
		end)
	end)
end)

game.Players.PlayerRemoving:Connect(function(player)
	local jumps = player.leaderstats.Jumps
	saveData(jumpsDatastore, player.UserId, jumps.Value) 
end)


game.Players.PlayerAdded:Connect(function(NewPlayer)
	NewPlayer.CharacterAdded:Connect(function()
	local character = NewPlayer.Character
	local At1 = Instance.new("Attachment", character:WaitForChild("Head"))
	local At2 = Instance.new("Attachment", character:WaitForChild("HumanoidRootPart"))
	At1.Name = "At1"
		At2.Name = "At2"
	end)
	
end)

ShopHandler This should control how the shop works

local HolderFrame = script.Parent.Holder
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Trails = ReplicatedStorage.Trails

local EquipTrail = ReplicatedStorage.EquipTrail

local player = game.Players.LocalPlayer
local character = player.Character

if not character or not character.Parent then
	character = player.CharacterAdded:wait()
end

for i,v in pairs(HolderFrame:GetChildren()) do
	if v:IsA("TextButton") then
		v.MouseButton1Click:Connect(function()
			if v.Purchased.Value == false then
				if player.leaderstats.Coins.Value >= v.Cost.Value then
					player.leaderstats.Coins.Value = player.leaderstats.Coins.Value - v.Cost.Value
					v.Purchased.Value = true
					v.Status.Text = "Purchased"
				else
					print("Not Enough")
				end
			elseif v.Purchased.Value == true then
				local trail = v.Name
				EquipTrail:FireServer(trail)
			end
		end)
	end
end

image


I want to find a solution of this problem as I’ve been brainstorming for about 8 hours and still can’t find anything :sweat_smile:
Sorry in advance for the many scripts and requests.


Thanks to everyone that tries to help :grinning:

is the trail enabled and attached to a attachment

Trails are enabled and attached.

maybe because the attachments are in separate parts?

I might cannot help you how to find the solution but i think you must do coins checking inside server because hacker could easily exploit.

They are in separate parts but I believe the problem is in this part of the script

game.Players.PlayerAdded:Connect(function(NewPlayer)
	NewPlayer.CharacterAdded:Connect(function()
	local character = NewPlayer.Character
	local At1 = Instance.new("Attachment", character:WaitForChild("Head"))
	local At2 = Instance.new("Attachment", character:WaitForChild("HumanoidRootPart"))
	At1.Name = "At1"
		At2.Name = "At2"
	end)
	
end)

because it is in the same script as the jumps and coins. That’s just a hypothesis tho.

How would I do it in server side?

i think it’s the separate parts, that should work in theory

Whenever the player presses the trail button, and you’re firing that event, instead of checking on the client, check on the server script if they have enough to buy the trail. And from there give them if they can afford.

So I just attach the trail to the same part?

I’ll look into what I can do to fix that

yeah, and make a attachment inside of the humanoidrootpart that appears to look like it is inside of the head instead

also confirm that it is actually firing by printing something

1 Like

Instead of this part, you could simply invoke a function to the server,[using a remotefunction]

   if player.leaderstats.Coins.Value >= v.Cost.Value then
	    player.leaderstats.Coins.Value = player.leaderstats.Coins.Value - v.Cost.Value
		v.Purchased.Value = true
		v.Status.Text = "Purchased"
	else
		print("Not Enough")
    end
	

And on the server side, you’ll have to put something like this -

game.ReplicatedStorage.BuyTrail.OnServerInvoke = function(Player,TrailName)
    local Trail = game.ServerStorage.Trails:FindFirstChild(TrailName) -- or use ReplicatedStorage
    local Price = Trail.Price
    if Player.leaderstats.Coins.Value >= Price.Value then
      --Give him the trail here, etc.. Also check if he owns that trail or not already.
    else
      --If we dont have enough cash, then we'll return this to the client, telling him why he cant buy it.
      return "Insufficient Amount of Coins"
    end
end

And then, on the client simply do something like this -

local RS = game:GetService("ReplicatedStorage")
local Remote = RS:WaitForChild("BuyTrail")

for i,v in pairs(HolderFrame:GetChildren()) do
	if v:IsA("TextButton") then
		v.MouseButton1Click:Connect(function()
           local Check = Remote:InvokeServer(v.Name)
           if Check == "Insufficient Amount of Coins" then
             print("Player couldn't buy this Trail")
           end
        end)
    end
end

I’ll try to do it once I get in studio again

1 Like

it appears i was wrong, attachments work with multiple parts

are you sure your trail is actually functional? because sometimes people forget to check stuff like facecamera

I’ve placed the trails on two parts and it worked, I don’t think facecamera affects the trail as I have a “rainbow trail” gamepass which works perfectly. So I think the problem is about the scripts, not the trails themselves.

2 Likes

I’ve put something like this:

game.Players.PlayerAdded:Connect(function(NewPlayer)
	NewPlayer.CharacterAdded:Connect(function()
	local character = NewPlayer.Character
	local At1 = Instance.new("Attachment", character:WaitForChild("Head"))
	local At2 = Instance.new("Attachment", character:WaitForChild("HumanoidRootPart"))
	At1.Name = "At1"
		At2.Name = "At2"
		
		print("is this working")
	end)
	
end)

But nothing is being printed

aha, see if there is a while loop or another loop going on in the script, if so, create another script for that loop or make a new thread for it with coroutines (or a wait() might be interfering, also use task.wait() wait might be deprecated soon)

I’ve put it in a new script and now it prints:
image

1 Like

awesome, does it work now?