…
looking at the code around 4 hours later
this won’t work properly, sigh
EDIT 1 HOUR LATER
i think it’s going to work now!!
-- Nothing here gets applied, it only gets saved
-- Except for settings of course!
local rStorage = game:GetService("ReplicatedStorage")
local dStoreService = game:GetService("DataStoreService")
local players = game:GetService("Players")
-- Path to events;
local eventsFolder = rStorage:WaitForChild("Events")
local fromClient = eventsFolder:WaitForChild("FromClient")
local functionalityEvents = fromClient:WaitForChild("Functionality")
-- Event;
local sendPlayerSettings = functionalityEvents.SendPlayerSettings
-- Table to store player data in (CURRENT SERVER ONLY, NOT DATASTORE)
local playerSettingsTable = {}
-- Valid settings (for safety purposes)
local validSettings = {
"Field of View",
"Classic Aim Down Sights",
"Vitals GUI Color",
"Weapon GUI Color",
"Visible Viewmodel",
"Show Crosshair",
}
-- Datastores;
local playerDataStorage = dStoreService:GetDataStore("Player_Data")
-- Misc values;
local previousValue = nil
-- Functions;
function GetOrCreateAttribute(plr: Player, attributeName: string, defaultValue: any)
if plr:GetAttribute(attributeName) == nil then
plr:SetAttribute(attributeName, defaultValue)
end
return plr:GetAttribute(attributeName)
end
function InitializePlayerData(plr: Player)
local totalKills = GetOrCreateAttribute(plr, "TotalKills", 0)
local totalDeaths = GetOrCreateAttribute(plr, "TotalDeaths", 0)
local totalCurrencyEarned = GetOrCreateAttribute(plr, "TotalCurrencyEarned", 0)
local totalXpEarned = GetOrCreateAttribute(plr, "TotalXpEarned", 0)
local currentLevel = GetOrCreateAttribute(plr, "CurrentLevel", 1)
local currentWhisper = GetOrCreateAttribute(plr, "CurrentWhisper", 0)
-- 'Whisper' is basically a rebirth, but with an edgy name
-- so think of 'Whisper' as 'Rebirth' if you find it easier
local success, result = pcall(function()
return playerDataStorage:GetAsync(plr.UserId)
end)
if not success then
warn("Failed to fetch " .. plr.UserId .. "'s data!")
warn("Error log: " .. result)
result = nil
end
if not playerSettingsTable[plr.UserId] then
-- Set data;
playerSettingsTable[plr.UserId] = {
TotalKills = totalKills,
TotalDeaths = totalDeaths,
TotalCurrencyEarned = totalCurrencyEarned,
TotalXpEarned = totalXpEarned,
CurrentLevel = currentLevel,
CurrentWhisper = currentWhisper,
Settings = {
-- Default values
["Field of View"] = 90,
["Classic Aim Down Sights"] = false,
["Vitals GUI Color"] = Color3.fromRGB(255,255,255),
["Weapon GUI Color"] = Color3.fromRGB(255,255,255),
["Visible Viewmodel"] = true,
["Show Crosshair"] = true,
}
}
end
if result then
playerSettingsTable[plr.UserId].TotalKills = result.TotalKills or totalKills
playerSettingsTable[plr.UserId].TotalDeaths = result.TotalDeaths or totalDeaths
playerSettingsTable[plr.UserId].TotalCurrencyEarned = result.TotalCurrencyEarned or totalCurrencyEarned
playerSettingsTable[plr.UserId].TotalXpEarned = result.TotalXpEarned or totalXpEarned
playerSettingsTable[plr.UserId].CurrentLevel = result.CurrentLevel or currentLevel
playerSettingsTable[plr.UserId].CurrentWhisper = result.CurrentWhisper or currentWhisper
if not result.Settings then return end
for setting, value in pairs(result.Settings) do
playerSettingsTable[plr.UserId].Settings[setting] = value
end
end
end
function OnPlayerJoined(plr: Player)
InitializePlayerData()
end
function OnSettingsReceived(plr: Player, setting: string, value: any)
if not table.find(validSettings, setting) then plr:Kick("Don't do that") return end
if value == previousValue then plr:Kick("Ummm you didn't change the value?") return end
if not playerSettingsTable[plr.UserId] then
-- If player data isn't found, then initialize it;
InitializePlayerData(plr)
end
-- Update that value!
playerSettingsTable[plr.UserId].Settings[setting] = value
-- Some sort of warning that's here specifically for debugging :^)
warn(plr.Name .. " changed " .. setting .. " to " .. tostring(value))
warn("Current settings of " .. plr.Name .. " are: ")
print(playerSettingsTable[plr.UserId].Settings)
previousValue = value
end
function AutosaveInIntervals()
coroutine.wrap(function()
while true do
local interval = math.random(300, 600) -- Random interval between 5 to 10 minutes
-- Probably the best choice for security :^)
task.wait(interval)
for userId, data in pairs(playerSettingsTable) do
local success, result = pcall(function()
local key = tostring(userId)
playerDataStorage:UpdateAsync(key, function(oldData)
oldData = oldData or {} -- No current data will instead initialize an empty table :^)
local newData = {
TotalKills = data.TotalKills or 0,
TotalDeaths = data.TotalDeaths or 0,
TotalCurrencyEarned = data.TotalCurrencyEarned or 0,
TotalXpEarned = data.TotalXpEarned or 0,
CurrentLevel = data.CurrentLevel or 1,
CurrentWhisper = data.CurrentWhisper or 0,
Settings = data.Settings or {
["Field of View"] = 90,
["Classic Aim Down Sights"] = false,
["Vitals GUI Color"] = Color3.fromRGB(255,255,255),
["Weapon GUI Color"] = Color3.fromRGB(255,255,255),
["Visible Viewmodel"] = true,
["Show Crosshair"] = true
}
}
return newData
end)
end)
if not success then
warn("Failed to save " .. userId .. "'s data!")
warn("Error information: ")
warn(result)
continue -- Skips to the next iteration so that print
-- below doesn't run
end
print("Successfully saved data for " .. userId)
end
end
end)()
end
-- Runtime;
sendPlayerSettings.OnServerEvent:Connect(OnSettingsReceived)
players.PlayerAdded:Connect(OnPlayerJoined)
AutosaveInIntervals()