Usage
The purpose of this module is to save and load data with an incredible compression ratio. The basic usage of it can be seen in the following code.
What this code does is:
- Checks if the Player already has Leaderstats when the PlayerAdded function is called.
- If they don't have it, create a new BitBuffer.
- After the BitBuffer is created, check if they have any data saved on the DataStore. If they don't have any, set their data to the default created at the start of the script.
- Loads their data from the Base64 string that is stored in the DataStore using
FromBase64
. - Create the Leaderstats using the
loadFromBitBuffer
, which reads the Color3 first, and then the unsigned number second because that's what order they are stored in. - Parents the Leaderstats returned by
loadFromBitBuffer
to the Player. - When the player leaves, check if they have Leaderstats. If they do, create a new BitBuffer.
- Run the
saveToBitBuffer
function, which callsWriteColor3
first followed byWriteUnsigned
. - Sets the new data using
SetAsync
andToBase64
. Once that is complete, we callDestroy
on the BitBuffer and set it to nil.
Important
The order of which you read and write does matter. If you don't follow the same order, your data will not be correct.
Error
I do not recommend using the data saving part of this example in your code. Instead, it's suggested to use either DataStore2 or Quenty's DataStore system.
local Players = game:GetService("Players") local ServerStorage = game:GetService("ServerStorage") local DataStoreService = game:GetService("DataStoreService") local FastBitBuffer = require(ServerStorage.FastBitBuffer) local USER_DATA = {"FavoriteColor", "Stage"} local TOTAL_STAGES = 400 local BITS_REQUIRED = FastBitBuffer.BitsRequired(TOTAL_STAGES) local DEFAULT_DATA do local bitBuffer = FastBitBuffer.new() bitBuffer:WriteColor3(Color3.new()) bitBuffer:WriteUnsigned(BITS_REQUIRED, 1) DEFAULT_DATA = bitBuffer:ToBase64() bitBuffer:Destroy() bitBuffer = nil end local gameDataStore = DataStoreService:GetDataStore("GameDataStore") local function saveToBitBuffer(bitBuffer, leaderstats) for _, valueName in ipairs(USER_DATA) do assert(leaderstats:FindFirstChild(valueName), string.format("Expected ValueObject %s to exist but it doesn't.", valueName)) end bitBuffer:WriteColor3(leaderstats.favoriteColor.Value) bitBuffer:WriteUnsigned(BITS_REQUIRED, leaderstats.Stage.Value) end local function loadFromBitBuffer(bitBuffer) local leaderstats = Instance.new("Folder") leaderstats.Name = "Leaderstats" local favoriteColor = Instance.new("Color3Value") favoriteColor.Name = "FavoriteColor" favoriteColor.Value = bitBuffer:ReadColor3() favoriteColor.Parent = leaderstats local stage = Instance.new("IntValue") stage.Name = "Stage" stage.Value = bitBuffer:ReadUnsigned(BITS_REQUIRED) stage.Parent = leaderstats return leaderstats end local function playerAdded(player) if not player:FindFirstChild("Leaderstats") then local bitBuffer = FastBitBuffer.new() local success, playerData = pcall(gameDataStore.GetAsync, gameDataStore, player.UserId) if success then if not playerData then playerData = DEFAULT_DATA pcall(gameDataStore.SetAsync, gameDataStore, player.UserId, playerData) end bitBuffer:FromBase64(playerData) local leaderstats = loadFromBitBuffer(bitBuffer) leaderstats.Parent = player bitBuffer:Destroy() bitBuffer = nil end end end local function playerRemoving(player) local leaderstats = player:FindFirstChild("Leaderstats") if leaderstats then local bitBuffer = FastBitBuffer.new() saveToBitBuffer(bitBuffer, leaderstats) local success, error = pcall(gameDataStore.SetAsync, gameDataStore, player.UserId, bitBuffer:ToBase64()) if not success and error then warn("Failed to save PlayerData!", error) end bitBuffer:Destroy() bitBuffer = nil end end Players.PlayerAdded:Connect(playerAdded) Players.PlayerRemoving:Connect(playerRemoving) for _, player in ipairs(Players:GetPlayers()) do playerAdded(player) end