Original post moved to pastebin, as original question has been completely redone. Link: https://pastebin.com/Gmdc90wc
Note: for tables you can do products.Gold50 or products["Gold50"] -- these are identical. You only need to use the [] for when you want to have a key that is not a string of the form of a variable. ex, products.50 is not allowed because 50 is not a legal variable name.
Based on your comments, I didn't explain the purpose of using all these classes/functions. The purpose is generally to let you make changes later without having to rewrite lots of bits of code. Ideally you make a change in one place and the rest of the script just works with it. To do this, the product table should have fields that are as general as you can make them -- ex, specifying "Amount" instead of "Gold". It's the difference between having 4 functions for granting Silver, Gold, XP, and Prestige (for example) and having just 1 function to do all four. On the other hand, if each product is completely unique (ex one grants gold, another gives an inventory item, another gives you the ability to run faster), then there's nothing wrong with being specific and using "Gold". Don't worry about getting this right the first time, as you may not have even invented all the products you want yet. Instead, as you continue to work with the script, keep on the look out for bits of code that are doing almost exactly the same thing and see if you can combine them into a single function. ex, say you did have a function for each of granting Silver, Gold, XP, and Prestige; here's how you'd simplify them:
function GiveGold(player, gold)
player.Gold.Value = player.Gold.Value + gold
end
function GiveXP(player, xp)
player.XP.Value = player.XP.Value + xp
end
if name == "Gold" then
GiveGold(player, amount)
elseif name == "XP" then
GiveXP(player, amount)
end
function GiveResource(player, resource, amount)
player[resource].Value = player[resource].Value + amount
end
GiveResource(player, name, amount)
In my opinion, you would ideally have three scripts:
- A ModuleScript in ReplicatedStorage that contains the
products table.
- A LocalScript that generates or modifies the GUI based on those product offers. If set up correctly, you can change the deals you are offering on Gold in script #1 without changing this script or the gui at all.
- Your Marketplace script (it can be server-only, stored in ServerScriptService).
However, for simplicity, I'll work with the scripts you've provided and I'll leave the LocalScript alone (though you'll need to change line 4 to player:FireClient("Gold", v.Gold.Value), and player should be the PurchaseEvent). Here's the server script:
(Too long for this post, see https://pastebin.com/HftR2qqe)
Note: Ideally the price is fetched using GetProductInfo instead of input manually (since then you can change it on the Roblox website and you don't have to remember to update your scripts). You don't even need it on the server, so if you are updating the GUI manually, you can delete Price entirely.
Note 2: The errors in purchaseEvent could occur either because you set up something wrong in the LocalScripts or because an exploiter is sending invalid data.
Note 3: I took some of the code from Handling Multiple Developer Products. As such, _G.awardGold (or the ApplyFunc parameter) must return true if successful.
Note 4: I deleted purchaseHistory and replaced it with local storage. You could add it back in again if you ever might need to browse the global purchase history (but I doubt it would be useful). The local system I replaced it with only saves the information for 5 minutes, but the whole point of it is to prevent anything undesirable from happening should Roblox call ProcessReceipt multiple times. The Datastore method in the wiki would actually fail at preventing you from giving the player more than they purchased if ProcessReceipt was called quickly 2x in a row.
2 comments
maybe use tables in tables
wew worst remote event security ever