Scripting HelpersARCHIVE
A little piece of Roblox history. Preserved for everyone, one question at a time.Read about the archive →
COMMUNITY QUESTION

Having a tables contents contain further information?

ServerScript

local marketplaceService = game:GetService("MarketplaceService")

local dataStoreService = game:GetService("DataStoreService")
local purchaseHistory = dataStoreService:GetDataStore("PurchaseHistory")

local replicatedStorage = game:GetService("ReplicatedStorage")
local eventsFolder = replicatedStorage:WaitForChild("EventsFolder")
local purchaseEvent = eventsFolder:WaitForChild("PurchaseEvent")

local products = 
{
	["Gold50"] = {ID = 100122331, Gold = 50};
	["Gold100"] = {ID = 111111111, Gold = 100};
	["Gold250"] = {ID = 11111112, Gold = 250};
	["Gold500"] = {ID = 111111113, Gold = 500};
	["Gold1000"] = {ID = 111111114, Gold = 1000};
	["Gold1500"] = {ID = 111111115, Gold = 1500};
}

purchaseEvent.OnClientEvent:connect(function(...)
	local tuple = {...}
	if tuple then
		marketplaceService.ProcessReceipt = function(receiptInfo)
			for _, player in ipairs(game.Players:GetChildren()) do
				if player.userId == receiptInfo.PlayerId then
					if receiptInfo.ProductId == products["Gold" .. tuple[1][2]] then
						-- Give the gold
					end
				end
			end
			return Enum.ProductPurchaseDecision.PurchaseGranted
		end
	end
end)

LocalScript:

for _, v in pairs(buttonFrame:GetChildren()) do
	if v:IsA("ImageButton") then
		v.MouseButton1Down:connect(function()
			player:FireClient(v.Gold.Value)
		end)
	end
end

Gold.Value == 50

2 comments

1

maybe use tables in tables

0

wew worst remote event security ever

1 answer

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:

--For simplicity I'll assume you're using IntValues to store everything
function GiveGold(player, gold)
	player.Gold.Value = player.Gold.Value + gold
end
function GiveXP(player, xp)
	player.XP.Value = player.XP.Value + xp
end
--etc
--In your Purchase function, say you've got the variable "name" referring to "Gold"/"XP"/etc and "amount" referring to the amount they're purchasing, you'd then have this code:
	if name == "Gold" then
		GiveGold(player, amount)
	elseif name == "XP" then
		GiveXP(player, amount)
	--etc
	end

--Notice how, though the variable names differ, the format is the same. We can change the code to look like this:

function GiveResource(player, resource, amount)
	player[resource].Value = player[resource].Value + amount
end
--In the purchase function, that 'if' block can be reduced to:
	GiveResource(player, name, amount)

In my opinion, you would ideally have three scripts:

  1. A ModuleScript in ReplicatedStorage that contains the products table.
  2. 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.
  3. 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.

6 comments

0

Semicolons do work. I use them because semicolons can be for ending lines which increase the performance slightly, so I am just used to using that key.

0

Kinda confused with a lot of that ;D I'm not really that familiar with using modules and how to utilize them properly with dev products

0

So like, would I have the awardBucks function inside a module? Then what would I have it return? true?

0

Editted my code to how it is now. How would I go about the next part though, that's what I'm confused about

0

@hiimgoodpack: semicolons do not impact performance. I said that in table constructors, semicolons and commas are identical.

0

@NinjoOnline: I've extended my answer

This discussion is preserved as it was. New answers, comments, and votes are closed.