I was recently looking over my crate system, and realised that there’s a massive potential flaw, that could allow exploiters to win any item.
local AllItems = {}
local Result
local FrameTimes = math.random(45, 47) -- How many frames it goes through before stopping
local RewardItem
-- Making the item list
for i, item in pairs(CrateData[crate]) do
local RarityNumber = RarityTimes[crate][item.Rarity]
local Times = math.max(RarityNumber + chance)
for i = 1, Times do
table.insert(AllItems, item)
end
end
math.randomseed(tick())
-- Chooses the item
for i = 1, FrameTimes + 5 do
local Item = AllItems[math.random(1, #AllItems)]
local NewFrame = SampleItem:Clone()
NewFrame.Visible = true
NewFrame.Parent = Inner
NewFrame.ImageColor3 = Colors[Item.Rarity]
--NewFrame.Icon.Image = Item.Image.Value
NewFrame.ItemName.Text = Item.Item
NewFrame.Position = UDim2.new((i - 1) * 0.25, 0, 0, 0)
if i == FrameTimes then
RewardItem = NewFrame
Result = Item
--wonItem:FireServer(item.Item.Value, item.Name)
end
end
for i = 0.01, 5, 0.01 do
if RewardItem.Position.X.Scale == 0.5 then
break
end
for i, v in pairs(Inner:GetChildren()) do
v.Position = UDim2.new(v.Position.X.Scale - 0.25, 0, 0, 0)
if v.Position.X.Scale <= -0.15 then
v:Destroy()
end
end
script.Tick:Play()
wait(i)
end
This all handled on the client, and then at the end I fire a RemoteEvent which passes through the ‘RewardItem’, which an exploiter could make any item that. How can I transfer as much of this to the server as possible? Since a lot of it handles UI and what not
You may do a codified remote so it doesn’t fire if it doesn’t return a code as second value. Like: :FireServer(put code here with item to create) and server side a if that checks if code is returned
Crates should already be handled by the server for say opening them, to remove the crate from the user’s inventory or whatever you do, like buying a crate and it instantly goes to opening. All currency should go through the server and anything that involves any type of data change.
Simply have the server determine the item and reward the player with that when they open the crate and remove the crate from their inventory, so if they leave they don’t lose the item. Then just fire the client, or return, could be a remotefunction or event, and then have the crate go through as normal with the item the server says.
Edit: Don’t let the client really say anything, the client should instead ask. The client asks the server to open/buy the crate, the server does the checks, generates the item and rewards it while removing whatever it needs to, then it tells the client to go ahead and do what it’s supposed to do.
No need for coded examples here, the animation and everything can be done on the client but you should pre-determine the item beforehand and then tell the client to do the animation that ends up telling them the item they got.
I don’t wanna redo my system tho. Already looked at that, and it’s a lot of unneccsary stuff. I just want to be able to convert what I have already to make it safe, not redo it entirely
Okay, have the server generate the item and tell the client, and when you generate the frames, simply replace the frame instead of it being random, make the reward frame based off your numbers and everything be the reward item. The server will still decide what the winning item is, and it’ll finish on that item every time since you set it to that as it’s generating the frames.
This way the client never has to tell the server what item they got, and instead just match up to what the server actually gave them.
local AllFrames, WinningItem = Spin:InvokeServer(crate, chance)
local AllItems = {}
local Result
local FrameTimes = math.random(45, 50)
local RewardItem
-- Making the item list
for i, item in pairs(CrateData[crate]) do
local RarityNumber = RarityTimes[crate][item.Rarity]
local Times = math.max(RarityNumber + chance)
for i = 1, Times do
table.insert(AllItems, item)
end
end
math.randomseed(tick())
For your purpose you can randomly assign items to the first several frames, and then append the winning item as the last frame. If you need padding, ofcourse you can append a few more to ensure that it doesn’t just dead stop, and make sure the item == winningitem
Guess that may be a bad way to word it.
Being you’re using a random number of times, you can force the stop frame to be the winning item.
local function SpinStart(player, crate, chance)
local AllItems = {}
local FrameTimes = math.random(45, 50)
local RewardItem
-- Making the item list
for i, item in pairs(CrateData[crate]) do
local RarityNumber = RarityTimes[crate][item.Rarity]
local Times = math.max(RarityNumber + chance)
for i = 1, Times do
table.insert(AllItems, item)
end
end
math.randomseed(tick())
local RewardItem = AllItems[math.random(1, #AllItems)]
return AllItems, RewardItem
end
Client
local AllItems, WinningItem = Spin:InvokeServer(crate, chance)
local WinningFrame
print(WinningItem.Item)
for i = 1, #AllItems do
local Item = AllItems[math.random(1, #AllItems)]
local NewFrame = SampleItem:Clone()
NewFrame.Visible = true
NewFrame.Parent = Inner
NewFrame.ImageColor3 = Colors[Item.Rarity]
--NewFrame.Icon.Image = Item.Image.Value
NewFrame.ItemName.Text = Item.Item
NewFrame.Position = UDim2.new((i - 1) * 0.25, 0, 0, 0)
if WinningItem.Item == Item.Item then
WinningFrame = NewFrame
end
end
for i = 0.01, 5, 0.01 do
print(WinningFrame, WinningFrame.Position.X.Scale)
if WinningFrame.Position.X.Scale == 0.5 then
break
end
for i, v in pairs(Inner:GetChildren()) do
v.Position = UDim2.new(v.Position.X.Scale - 0.25, 0, 0, 0)
if v.Position.X.Scale <= -0.15 then
v:Destroy()
end
end
script.Tick:Play()
wait(i)
end
Problem is, with the print in the client, it prints
The wait is osmething I want, as if you spin like a wheel, it’ll be fast at the start, and slow down towards the end, eventually stopping on the winning frame