Scripting Helpers is winding down operations and is now read-only. More info→
Ad
Log in to vote
0

How can I improve my Shop purchase script further?

Asked by 6 years ago

Hello!

I have a pretty nifty shop purchase script, but I want to streamline it further to put more of the work on the Server as opposed to the Client/Local. I've created a few Remote Events that seem to be working fine, but I'm not sure I'm utilizing them properly for max efficiency. Essentially, my goal here is to make sure the shop purchase script works properly, and never over/double charges the player, or sends their Coins into the negative. I'd had that happen previously, randomly, when I was relying entirely on the Client/Local doing the function, and that is not ideal for the player experience.

Here are my Remote Events inside the Script under ServerScriptStorage:

--//Get Services
local ReplicatedStorage = game:GetService("ReplicatedStorage")
--//EventFolder
local Events = ReplicatedStorage:WaitForChild("Events")
--//Remote Events
local CoinsPurchase = Events:WaitForChild("CoinsPurchase")
local ItemOwned = Events:WaitForChild("ItemOwned")
local CanAffordItem = Events:WaitForChild("CanAffordItem")

 -- PURCHASE WITH COINS --
CoinsPurchase.OnServerEvent:Connect(function(Player, Value, Amount)
if Player.leaderstats.Coins.Value >= Amount then
    print('Server says player has enough Coins for the purchase.')
        Player.leaderstats.Coins.Value = Player.leaderstats.Coins.Value - Amount 
        print(Value)
        Value.Value = true
    else
    print("Player does not have enough Coins for the purchase.")
end

end)

--CHECK IF ITEM OWNED --
ItemOwned.OnServerEvent:Connect(function(Player,Value)
if Value.Value == false then
    print('Player does not own this item.')
else
    print('Player does own item')
    end

end)

--CHECK IF PLAYER CAN AFFORD ITEM --
CanAffordItem.OnServerEvent:Connect(function(Player,Value, Amount)
if Player.leaderstats.Coins.Value >= Amount then
    print('Player CAN afford Item')
else
    print('Player Can NOT afford Item')
end

end)

And this is a slightly abbreviated version of my shop purchase Local Script. When the Item01 button is clicked, it makes visible the BuyButton script and fills in the variables:

--//Get Services
local RS = game:GetService("ReplicatedStorage")
local Players = game:GetService("Players")
local Player = Players.LocalPlayer
local currencyCOINS = Player.leaderstats.Coins

--//EventFolder
local Events = RS:WaitForChild("Events")

--//Events
local ToolPurchase = Events:WaitForChild("ToolPurchase")
local CoinsPurchase = Events:WaitForChild("CoinsPurchase")
local ItemOwned = Events:WaitForChild("ItemOwned")
local CanAffordItem = Events:WaitForChild("CanAffordItem")

--//SHOP FRAME
local PurchaseFrame = Frame.PurchaseFrame
local BuyButton = PurchaseFrame.BuyButton
local ItemDesc = PurchaseFrame.ItemDesc
local Price = PurchaseFrame.Price

local ItemTrackName = RS:WaitForChild("ItemTrackNameShop")
local ItemPurchased = RS:WaitForChild("ItemPurchased")
local ItemPriceAmount = RS:WaitForChild("ItemPriceAmount")


BuyButton.MouseButton1Click:Connect(function()
MenuClickSound:Play()
    local amount = Cost
    local Value = ItemPurchased.Value
    ItemDesc.Text = 'Purchase '..ItemTrackName.Value..'?'
    Price.Text = ItemPriceAmount.Value

ItemOwned:FireServer(Player.Inventory[Value]) -- Checks if the Item is owned.
CanAffordItem:FireServer(Player.Inventory[Value], amount) -- Checks if the Player can afford the Item.  
    if Player.Inventory[Value].Value == true then
            ItemDesc.Text = 'You have already purchased this Item!'
            wait(3)
        else

        if Player.leaderstats.Coins.Value >= amount then
            CoinsPurchase:FireServer(Player.Inventory[Value], amount)
            wait(1)
            PurchaseClickSound:Play()
            ItemDesc.Text = 'Purchase Complete for '..ItemTrackName.Value..'! Equip this Item from your Inventory!'
            wait(3)     
            PurchaseFrame.Visible = false
            ItemDesc.Text = 'Purchase '..ItemTrackName.Value..'?'
            wait(1)
        else
            local coinsrequired = amount - currencyCOINS.Value      
            ItemDesc.Text = 'You need '.. coinsrequired ..' more Coins to buy this item!'
            wait(2)
            ItemDesc.Text = 'Purchase '..ItemTrackName.Value..'?'
            wait(5)
            PurchaseFrame.Visible = false
        end
    end
end)--Closes Purchase Frame

Item01.MouseButton1Click:Connect(function() 
PurchaseFrame.Visible =  true 
ItemTrackName.Value = 'Item01' 
ItemDesc.Text = 'Purchase Item01?'
 ItemPurchased.Value = 'Item01' 
Cost = 10 
ItemPriceAmount.Value =  Cost 
end)        

As you can see in the shop purchase script above, I first run the Remote Events to see if the Player already owns the item, and then if they can afford the item, before following it up with the local/client determining the same thing, and then the Remote Event fires that actually grants the Item, and deducts the amount/cost of the Item.

Am I using the Remote Events correctly here? Can I improve upon it further?

Thank you!

1
One problem I noticed is the code gives the Client too much power. An example is the CanAffordItem event. Since it sends the required amount from the Client, it can be manipulated to send the required amount to 0, making everything free - yes there is a conditional prior, but even that can be changed to work around it. Solution: Store all amounts and make checks on Server PreciseLogic 271 — 6y
0
Thank you for your response and insight! Could you possibly provide some example code? I think I'm following you here, but I really want to make sure I get this process exact. :) Never2Humble 90 — 6y

1 answer

Log in to vote
1
Answered by 6 years ago

This can easily be exploited which isn't a good thing. A simple change I did in my script was make it where you need to have the GUI open in order to make a purchase. Not only that you can't get a certain weapon with a certain price. It has its own event for each item. before you say it's too much work, think about what will happen with no exploiter for about a few more minutes of work to a few minutes but you have a ton of exploiters in your game. This is what I did for me event.

Local Script in GUI

script.Parent.MouseButton1Down:connect(function()
    local plr = game.Players.LocalPlayer
    local money = plr.stats.Money --Checks it 
    if money.value >= Price then
        GunShop.Glock:FireServer(plr)
        script.Parent.Parent.Parent.Information.Price.Text = "Thank you for your purchase!"
        wait(3)
        if script.Parent.Parent.Parent.Information.Price.Text == "Thank you for your purchase!" then
            script.Parent.Parent.Parent.Information.Price.Text = Price else

        end
    end
end)

Script in ServerScriptStorage.

GunShop.Glock.OnServerEvent:connect(function(plr)
    local Cost = 500  --What ever the price is--
    if plr.IsLTCOwner.value == true then --Checks if they own a license just something in my game--
        if plr.PlayerGui.Shop then --Checks for the GUI--
                if plr.stats.Money.Value >= Cost then --Checks for money--
                local Weapon = game.ServerStorage.GunShop:FindFirstChild("Glock")
                local Cash = plr.stats.Money
                Cash.Value = Cash.value - Cost --Bye bye money--
                local Cloned = Weapon:Clone()
                Cloned.Parent = plr.Backpack --Now they have it--
            end
        end
    end
end)

Its good to learn to do this so people are not able to exploit your game. They can spawn anything but need money and the GUI so there is almost no point.

Hope this helped you out a bit.

0
Thank you for this very detailed response, it's quite helpful! I should have specified that my purchase script is inside a gui. :) and every time a different item for purchase is clicked, it changes the variables inside the gui. I like how you setup each item purchase as a remote event. I'm a bit hesitant to do that, as my game has 150 items for purchase in the shop, and then 600+ additional - Never2Humble 90 — 6y
0
- random variants from "mystery gift" purchases. But if this is the best option, I'll do it. :) Never2Humble 90 — 6y
0
Actually, making an event for each item is quite an inefficient method, especially if you plan to have so many different items in your shop. I would use only one event for purchasing items, and make a table that defines the cost for each item. As long as that table is in the server script, the cost can't be manipulated. ThatPreston 354 — 6y
0
Yeah this is only meant for anti exploit pretty much bc its harder to find the hack and can also help if u have a game shop where it dissapears once u walk away. But this is really great if your willing to spend a bit of time changign the script a bit at a time Sergiomontani10 236 — 5y
Ad

Answer this question