While upgrading Innovation Security’s Commends System (basically a points system for determining ranks), I was told there was a data corruption bug when players change servers. I have experienced this before, and the common cause of PlayerDataStore. To address this and have additional functionality for manipulating player data in other servers for administrative purposes, I rewrote it to have an OnUpdate
method for observing changes and added cross-server communicating of changing using the MessagingService
.
For those unfamiliar, PlayerDataStore was a module created by stravant after the release of the DataStoreService
for those who used Data Persistence, which didn’t have any limits for calls. It has some of the same design concepts of DataStore2 where requests are buffered and cached, but doesn’t rely on backups or duplcating data. Nexus Data Store adds cross-server communication of changes. The following is an example script from the GitHub pages (linked in the GitHub repository’s README):
local Players = game:GetService("Players")
local ServerScriptService = game:GetService("ServerScriptService")
local NexusDataStore = require(ServerScriptService:WaitForChild("NexusDataStore"))
Players.PlayerAdded:Connect(function(Player)
--Fetch the data.
--Even with GetAsync()s failing, the data can be loaded; it just won't be saved in case UpdateAsync() isn't failing.
local PlayerData = NexusDataStore:GetSaveData(Player)
--Create the leaderstats for the player's coins.
local Leaderstats = Instance.new("Folder")
Leaderstats.Name = "leaderstats"
Leaderstats.Parent = Player
local Coins = Instance.new("IntValue")
Coins.Name = "Coins"
Coins.Value = PlayerData:Get("Coins") or 0
Coins.Parent = Leaderstats
--Connect updating the value.
PlayerData:OnUpdate("Coins",function(NewCoins)
Coins.Value = NewCoins
end)
end)
Players.PlayerRemoving:Connect(function(Player)
--Flush the data and close the event connections by clearing the data.
--The data most likely has been flushed internally; this just clears up the resources.
NexusDataStore:RemoveFromCache(Player)
end)
--[[
Awards the player a set of coins.
Even if player data failed to load, this can be called
since the data will not be overwritten.
--]]
local function AwardCoins(Player,Coins)
--Can also call the following, but it isn't as easy to read:
--NexusDataStore:GetSaveData(Player):Set("Coins",(NexusDataStore:GetSaveData(Player):Get("Coins") or 0) + Coins)
NexusDataStore:GetSaveData(Player):Increment("Coins",Coins)
end
--[[
Remotely awards coins for a player.
--]]
local function AwardCoinsRemove(UserId,Coins)
--Set the coins.
local DataStore = NexusDataStore:GetSaveDataById(UserId)
DataStore:Incrementt("Coins",Coins)
--Remove the data from the cache. This flushes the data to the DataStores and disconnects events.
--Be aware Flush can throw errors if UpdateAsync fails.
if not Players:GetPlayerFromId(UserId) then
NexusDataStore:RemoveFromCache(UserId)
end
end
There is some additional functionality included, such as now allowing writes if the initial loading of data failed. For the most part, it is Ultimate Boxing’s data saving system as a module with cross-server communicating of data. Given Ultimate Boxing had less than 10 reported cases of data loss after 5,000,000 players and thousands of concurrent players, and that automation tests exist to test cross-server communication and failure cases, it has replaced PlayerDataStore in the Innovation Security Training Facility. Those who need cross-server communication with DataStore
s may find this more useful over the current version of DataStore2, or just those still using PlayerDataStore.