How can I let a player play a series of animation tracks immediately after the player buy a developer product?

Hello fellow devs!

Now I am publishing Samurai Era and I want to add a new Donate & Pray system
for Big Budda, temples and shrines.

Under this system, if a player donate 5 R$ (buy a developer product) from Proximity Prompt, a player is supposed to play a series of animation tracks including vow and pray.
Now I made 3 animation files and want a player play these animations one by one
if the player purchase the developer product.

I created a local script under StarterCharacterScripts folder
for Proximity Prompt to open the purchase page.

Then I created a server script called Process Receipt under ServerScriptService.

These scripts are as follows:





–Local Script–

Blockquote
local pps = game:GetService(“ProximityPromptService”)

local plr = game:GetService(“Players”).LocalPlayer

local char = plr.Character or plr.CharacterAdded:Wait()

local hum = char:WaitForChild(“Humanoid”)

local hrp = char:WaitForChild(“HumanoidRootPart”)

local Animator = hum:WaitForChild(“Animator”)

local passID = 1283736714

local donateAndPrayPromptForBigBudda = game.Workspace.BigBudda.DonationBox.DonationBoxBody.DonateAndPray

local remoteDonateAndPray = game:GetService(“ReplicatedStorage”):WaitForChild(“DonateAndPray”)

local RS = game:GetService(“ReplicatedStorage”)

local animations = RS.Effects.Animations

local clap2Times = animations.Clap2Times

local deepOjigi = animations.DeepOjigi

local pray = animations.Pray

local function onPromptTriggered(prompt, plr)

if prompt.Name == “DonateAndPray” then

game:GetService(“MarketplaceService”):PromptProductPurchase(plr, passID)

end

end

pps.PromptTriggered:Connect(onPromptTriggered)

Blockquote

–Server Script–

Blockquote
local MarketplaceService = game:GetService(“MarketplaceService”)
local DataStoreService = game:GetService(“DataStoreService”)
local Players = game:GetService(“Players”)

– Data store for tracking purchases that were successfully processed
local purchaseHistoryStore = DataStoreService:GetDataStore(“PurchaseHistory”)

– Table setup containing product IDs and functions for handling purchases
local productFunctions = {}

productFunctions[1283736714] = function(_receipt, player)

local char = player.Character or player.CharacterAdded:Wait()
local hum = char:WaitForChild("Humanoid")
local hrp = char:WaitForChild("HumanoidRootPart")
local Animator = hum:WaitForChild("Animator")

local passID = 1283736714
local donateAndPrayPromptForBigBudda = game.Workspace.BigBudda.DonationBox.DonationBoxBody.DonateAndPray
local remoteDonateAndPray = game:GetService("ReplicatedStorage"):WaitForChild("DonateAndPray")

local RS = game:GetService("ReplicatedStorage")
local animations = RS.Effects.Animations
local clap2Times = animations.Clap2Times
local deepOjigi = animations.DeepOjigi
local pray = animations.Pray
local clap2TimesTrack = Animator:LoadAnimation(clap2Times)
local deepOjigiTrack = Animator:LoadAnimation(deepOjigi)
local prayTrack = Animator:LoadAnimation(pray)

local animTracks = {deepOjigiTrack, clap2TimesTrack, prayTrack}

for _, eachTrack in pairs (animTracks) do
	eachTrack.Priority = Enum.AnimationPriority.Action
	eachTrack.Looped = false
end

deepOjigiTrack:Play()
deepOjigiTrack.Stopped:wait()
wait(1)
deepOjigiTrack:Play()
deepOjigiTrack.Stopped:wait()
wait(1)

clap2TimesTrack:Play()
clap2TimesTrack.Stopped:wait()
wait(1)

prayTrack:Play()
prayTrack.Stopped:wait()
wait(1)

deepOjigiTrack:Play()
deepOjigiTrack.Stopped:wait()
wait(1)

player.leaderstats.Luck.Value += 10

return true

end

– The core ‘ProcessReceipt’ callback function
local function processReceipt(receiptInfo)
– Determine if the product was already granted by checking the data store
local playerProductKey = receiptInfo.PlayerId … “_” … receiptInfo.PurchaseId
local purchased = false
local success, result, errorMessage

success, errorMessage = pcall(function()
	purchased = purchaseHistoryStore:GetAsync(playerProductKey)
end)
-- If purchase was recorded, the product was already granted
if success and purchased then
	return Enum.ProductPurchaseDecision.PurchaseGranted
elseif not success then
	error("Data store error:" .. errorMessage)
end

-- Determine if the product was already granted by checking the data store  
local playerProductKey = receiptInfo.PlayerId .. "_" .. receiptInfo.PurchaseId

local success, isPurchaseRecorded = pcall(function()
	return purchaseHistoryStore:UpdateAsync(playerProductKey, function(alreadyPurchased)
		if alreadyPurchased then
			return true
		end

		-- Find the player who made the purchase in the server
		local player = Players:GetPlayerByUserId(receiptInfo.PlayerId)
		if not player then
			-- The player probably left the game
			-- If they come back, the callback will be called again
			return nil
		end

		local handler = productFunctions[receiptInfo.ProductId]

		local success, result = pcall(handler, receiptInfo, player)
		-- If granting the product failed, do NOT record the purchase in datastores.
		if not success or not result then
			error("Failed to process a product purchase for ProductId:", receiptInfo.ProductId, " Player:", player)
			return nil
		end

		-- Record the transcation in purchaseHistoryStore.
		return true
	end)
end)

if not success then
	error("Failed to process receipt due to data store error.")
	return Enum.ProductPurchaseDecision.NotProcessedYet
elseif isPurchaseRecorded == nil then
	-- Didn't update the value in data store.
	return Enum.ProductPurchaseDecision.NotProcessedYet
else	
	-- IMPORTANT: Tell Roblox that the game successfully handled the purchase
	return Enum.ProductPurchaseDecision.PurchaseGranted
end

end

– Set the callback; this can only be done once by one script on the server!
MarketplaceService.ProcessReceipt = processReceipt

Blockquote

What I see now is a player is just repeating vowing all the time in the experience.
I don’t know why it happens.
I will appreciate if someone help me.

2 Likes

Did you set the looping priority to true in the animator?

1 Like

Thank you for the reply.

I set the looping as false in the for loop:

for _, eachTrack in pairs (animTracks) do
eachTrack.Priority = Enum.AnimationPriority.Action
eachTrack.Looped = false
end