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

Having a tables contents contain further information?

Asked by 6 years ago
Edited 6 years ago

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

1
maybe use tables in tables abnotaddable 920 — 6y
0
wew worst remote event security ever hiimgoodpack 2009 — 6y

1 answer

Log in to vote
1
Answered by 6 years ago
Edited 6 years ago

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.

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. hiimgoodpack 2009 — 6y
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 NinjoOnline 1146 — 6y
0
So like, would I have the awardBucks function inside a module? Then what would I have it return? true? NinjoOnline 1146 — 6y
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 NinjoOnline 1146 — 6y
View all comments (2 more)
0
@hiimgoodpack: semicolons do not impact performance. I said that in table constructors, semicolons and commas are identical. chess123mate 5873 — 6y
0
@NinjoOnline: I've extended my answer chess123mate 5873 — 6y
Ad

Answer this question