Recently, I decided to make a game with one of my friends, and as I was coding, I came across an idea that I wanted to use in my game: A VIP system, such as the one in world//zero where when you pay “x” amount of robux, you earn vip for 1 or 2 days.
I attempted to do that along side a daily rewards system, but , being the fairly new coder myself, I easily got overwhelmed by all the numbers and times involved.
I followed ( to an extent) a tutorial on daily rewards and attempted to edit it in order to have a vip count down as well but it just isnt working out for me.
I’m getting no errors, and its printing my stats, but for simplicities sake, I tried to set the daily reward timer to 1 minute in order to earn jewels at a faster rate, but even after waiting one minute in studio, I got nothing.
Here is the pastebin to my code since it is pretty lengthy, I added some notes inside as well. any help given would be a huge help because currently I’m so lost
Im not too good with the math aspect of os.time() so that could be one of my errors.
Havent tested it outside of studio, however, inside studio I turned on
which should make it compatible with studio tests shouldnt it?
EDIT: just tried waiting a minute in that actual roblox player, still doesnt work.
after waiting a minute, jewels should be 20 and reward day should be 2
Making timed memberships is quite easy, since all you have to do is
local expiration = os.time() + 86400
-- This would be the current time + 1 Day
Now you can check in your script if the user is a vip by comparing expiration with the current time.
if expiration > os.time() then
print("user is vip")
end
You can do this as well with daily rewards
By the way, I fixed the script a bit so it should work. I also commented every change I did, if you don't understand a change, a comment or I forgot to comment a change feel free to ask. (Errors may appear as I can not guarantee this will work since I did not test this, so there is a possibility that you will need to fix some errors yourself)
Code
local DatastoreService = game:GetService("DataStoreService")
local Datastore = DatastoreService:GetDataStore("PlayerInfo")
-- This allows the PlayerRemoving event to save the players data
local ServerUserData = {}
local TimeScale = {
SECOND = 0,
MINUTE = 60,
HOUR = 3600,
DAY = 86400
}
-- DailyRewardTime is now in seconds
local DailyRewardTime = TimeScale.DAY * 1 -- One day
local DailyRewards = {
DailyReward1 = 20,
DailyReward2 = 40,
DailyReward3 = 80,
DailyReward4 = 160,
DailyReward5 = 320,
DailyReward6 = 640,
}
-- I removed HasVip and changed RewardWait to LastReward
local Stats = {
VipTime = 0;
RewardWait = os.time();
RewardDay = 0;
HasBoughtPremium = false;
Jewels = 0
}
game.Players.PlayerAdded:Connect(function(plr)
-- We get the userdata within the event, and if it is nil, we set the userdata to Stats
local userdata = Datastore:GetAsync(plr.UserId)
userdata = userdata ~= nil and userdata or Stats
-- We moved the VIP check to the bottom to ensure we are using the updated value in case the user has a 7 day streak
-- Check if the last reward was within the DailyRewardTime span
-- Note: We are changing the LastReward to os.time()
local LastReward = userdata.LastReward - os.time()
if LastReward >= DailyRewardTime and LastReward < DailyRewardTime * 2 then
-- Increase the daily count since it is 1 day since the last reward
userdata.RewardDay = userdata.RewardDay + 1
elseif LastReward >= DailyRewardTime * 2 then
-- Reset the daily count since it is 2 days since the last reward
userdata.RewardDay = 0
end
-- In your old script, you checked if the RewardDay is 7 after you set it back to 0, so I moved it outside after the RewardDay check
if userdata.RewardDay == 7 then
-- They played 7 days in a row
userdata.VipTime = os.time() + TimeScale.HOUR * 1 -- Give them one hour of VipTime
else
userdata.Jewels = userdata.Jewels + DailyReward["DailyReward" .. userdata.RewardDay] -- No need to use tostring here
end
-- Check if the user is still VIP
-- Note: We are changing the VipTime to os.time() + seconds you want to add
if userdata.VipTime > os.time() then
print("user is vip")
end
-- Put userdata into the ServerUserData table we created above so we can save when the player leaves
ServerUserData[plr.Name] = userdata
-- Now print all values :)
for i,v in pairs(userdata) do
print(i,v)
end
end)
-- Utility function for saving
function nilAndDefault(value, default)
return value ~= nil and value or default
end
game.Players.PlayerRemoving:Connect(function(plr)
local userdata = ServerUserData[plr.Name]
Datastore:UpdateAsync(plr.UserId, function(oldData)
-- Check if oldData exists, if not use Stats as base
local newData = nilAndDefault(oldData, Stats)
-- Set each value
for i,v in pairs(userdata) do
newData[i] = v
end
-- Return newData so the Datastore saves
return newData
end)
end)
For line 47, when you defined “local LastReward” I’m getting an error that i’m subtracting nil from number, even after I changed “RewardWait” to “LastReward”
Say if I wanted to display a countdown for VIP, could I do this by firing over the number remaining for VIP, subtracting os.time and dividing it by roughly 3600 to get the amount in hours, then just have a repeat function count it down in game?
for now those are my only question, but again dude, seriously this helps me a lot
EDIT: Solved #1, i was using the old data store key which had nil values that correspond with this one.
To find out the time remaining in seconds, just do this userdata.VipTime - os.time(). If it is above > 0 then the user still has VIP and you have the time in seconds remaining. If it is below 0 then the user is not VIP and you don’t need the value.
Also, it doesnt seem to be saving the jewels / not giving the daily reward, I changed the daily reward so that the day goes up by 1 every minute and then i get my reward but I havent got anything and my rewards day is still printing 0.
Heres the edited code:
Code
local DatastoreService = game:GetService("DataStoreService")
local Datastore = DatastoreService:GetDataStore("PlayerInformation")
-- This allows the PlayerRemoving event to save the players data
local ServerUserData = {}
local TimeScale = {
SECOND = 0,
MINUTE = 60,
HOUR = 3600,
DAY = 86400
}
-- DailyRewardTime is now in seconds
local DailyRewardTime = TimeScale.MINUTE * 1 -- changed to one minute
local DailyRewards = {
DailyReward0 = 0, -- added this because without a day 0 it errors.
DailyReward1 = 20,
DailyReward2 = 40,
DailyReward3 = 80,
DailyReward4 = 160,
DailyReward5 = 320,
DailyReward6 = 640,
}
-- I removed HasVip and changed RewardWait to LastReward
local Stats = {
VipTime = 0;
LastReward = os.time();
RewardDay = 0;
HasBoughtPremium = false;
Jewels = 0
}
game.Players.PlayerAdded:Connect(function(plr)
-- We get the userdata within the event, and if it is nil, we set the userdata to Stats
local userdata = Datastore:GetAsync(plr.UserId)
userdata = userdata ~= nil and userdata or Stats
-- We moved the VIP check to the bottom to ensure we are using the updated value in case the user has a 7 day streak
-- Check if the last reward was within the DailyRewardTime span
-- Note: We are changing the LastReward to os.time()
local LastReward = userdata.LastReward - os.time()
if LastReward >= DailyRewardTime and LastReward < DailyRewardTime * 2 then
-- Increase the daily count since it is 1 day since the last reward
userdata.RewardDay = userdata.RewardDay + 1
elseif LastReward >= DailyRewardTime * 2 then
-- Reset the daily count since it is 2 days since the last reward
userdata.RewardDay = 0
end
-- In your old script, you checked if the RewardDay is 7 after you set it back to 0, so I moved it outside after the RewardDay check
if userdata.RewardDay == 7 then
-- They played 7 days in a row
userdata.VipTime = os.time() + TimeScale.HOUR * 1 -- Give them one hour of VipTime
else
userdata.Jewels = userdata.Jewels + DailyRewards["DailyReward" .. userdata.RewardDay] -- No need to use tostring here
end
-- Check if the user is still VIP
-- Note: We are changing the VipTime to os.time() + seconds you want to add
if userdata.VipTime > os.time() then
print("user is vip")
end
-- Put userdata into the ServerUserData table we created above so we can save when the player leaves
ServerUserData[plr.Name] = userdata
-- Now print all values :)
for i,v in pairs(userdata) do
print(i,v)
end
end)
-- Utility function for saving
function nilAndDefault(value, default)
return value ~= nil and value or default
end
game.Players.PlayerRemoving:Connect(function(plr)
local userdata = ServerUserData[plr.Name]
Datastore:UpdateAsync(plr.UserId, function(oldData)
-- Check if oldData exists, if not use Stats as base
local newData = nilAndDefault(oldData, Stats)
-- Set each value
for i,v in pairs(userdata) do
newData[i] = v
end
-- Return newData so the Datastore saves
return newData
end)
end)
I know its not wise, but do you think instead of :UpdateAsync() that I should use :SetAsync()?