I can save objects/models in-game and their positions. I want to know how I can have these objects destroyed/removed from the data-store and not reappear anymore. Basically, I want to purge/omit/overwrite the saved model of data from the game/date-store.
So the following code below here is what let's me gather the "deployables", which would be models that a player had placed in the game. That deployable will be saved for position and the next time a game starts, the duplicate template will be cloned to take place for that saved data position of the original deployable.
Of course, this is only an example of how it saves the deployable. I do not have any sample codes that can destroy/remove the saved data of the deployable. Which is why I want to make a code that allows me to do just that.
Note: I did not create this code, I'm a mere editor of the code.
local DataStore = game:GetService("DataStoreService"):GetDataStore("Deployables") --The magical realm of data! local ServerScriptService = Game:GetService("ServerScriptService") --The operating service for scripts in the server! local ReplicatedStorage = Game:GetService("ReplicatedStorage") --A storage, that's all. local EncodeInstance = require(ServerScriptService.EncodeInstance) --Transforming it better to save in data store. local Deployables = Workspace.DeployableInstances --The models themselves local DeployableTemplates = ReplicatedStorage.Items --The templates that are duplicated for the models. local function UpdateList() --The stuff that it will update the process of it. local DeployableList = DataStore:GetAsync("DeployableList") local BrandNewDataTable = {} for _,DeployableSaveData in pairs(ReplicatedStorage.NewDeployables:GetChildren()) do -- Save the value using the encoder! local SaveData = EncodeInstance.Encode(DeployableSaveData) -- Insert it into the table that we got from DataStore:GetAsync("DeployableList") if DeployableList then table.insert(DeployableList, SaveData) else table.insert(BrandNewDataTable, SaveData) end DeployableSaveData:Destroy() --Purge end -- Save it to the DataStore! if DeployableList then DataStore:SetAsync("DeployableList", DeployableList) else DataStore:SetAsync("DeployableList", BrandNewDataTable) end -- Done! print("Saved Instances") end local function InstanceNewDeployableFromDataStore() local DeployableList = DataStore:GetAsync("DeployableList") if DeployableList then for _,DeployableEntry in pairs(DeployableList) do DeployableEntry = EncodeInstance.Decode(DeployableEntry) for _,ItemFolder in pairs(DeployableTemplates:GetChildren()) do if ItemFolder.Name == DeployableEntry.Name then -- Create a deployable based on the saved value! local NewDeployable = ItemFolder.Assets.Variation1:Clone() NewDeployable.Name = ItemFolder.Name NewDeployable.Parent = Deployables NewDeployable:SetPrimaryPartCFrame(DeployableEntry.Value) end end end end -- Can't be bothered updating each and every local script for this, so I'll do it here instead. Deployables.ChildAdded:connect(function(Child) if Child:IsA("Model") and Child.PrimaryPart ~= nil then local SaveValue = Instance.new("CFrameValue") SaveValue.Name = Child.Name SaveValue.Value = Child.PrimaryPart.CFrame SaveValue.Parent = ReplicatedStorage.NewDeployables end end) print("Loaded Instances") --Yeah, just a message to let ya know when it loaded the instances. end InstanceNewDeployableFromDataStore() while Wait(5) do --Waiting before updating the list! UpdateList() --Ok, it updates the list. end --The end.
How to approach on this based on the code provided. Which is what helps saves the object(s) and process the data into the data store.
This might be too vague to answer but any sort of guidance or information that will help me figure a way to solve my problem will be much appreciated.
Update 1: The encode script (There's actually more scripts within the encodeinstance script that helps encode the data.)
EncodeInstance:
local BitBuffer = require(script.BitBuffer) local BitEncodeInstance = require(script.BitEncodeInstance) local EncodeInstance = {} function EncodeInstance.Encode(instance) local buffer = BitBuffer.Create() BitEncodeInstance.Write(buffer, instance) return buffer:ToBase64() end function EncodeInstance.Decode(text) local buffer = BitBuffer.Create() buffer:FromBase64(text) return BitEncodeInstance.Read(buffer) end return EncodeInstance
The Bitbuffer instructions (without the actual code) script below.
======================================================================= API
Constructor: BitBuffer.Create()
Read/Write pairs for reading data from or writing data to the BitBuffer: BitBuffer:WriteUnsigned(bitWidth, value) BitBuffer:ReadUnsigned(bitWidth) Read / Write an unsigned value with a given number of bits. The value must be a positive integer. For instance, if bitWidth is 4, then there will be 4 magnitude bits, for a value in the range [0, 2^4-1] = [0, 15]
BitBuffer:WriteSigned(bitWidth, value) BitBuffer:ReadSigned(bitWidth) Read / Write a a signed value with a given number of bits. For instance, if bitWidth is 4 then there will be 1 sign bit and 3 magnitude bits, a value in the range [-2^3+1, 2^3-1] = [-7, 7] BitBuffer:WriteFloat(mantissaBitWidth, exponentBitWidth, value) BitBuffer:ReadFloat(mantissaBitWidth, exponentBitWidth) Read / Write a floating point number with a given mantissa and exponent size in bits. BitBuffer:WriteFloat32(value) BitBuffer:ReadFloat32() BitBuffer:WriteFloat64(value) BitBuffer:ReadFloat64() Read and write the common types of floating point number that are used in code. If you want to 100% accurately save an arbitrary Lua number, then you should use the Float64 format. If your number is known to be smaller, or you want to save space and don't need super high precision, then a Float32 will often suffice. For instance, the Transparency of an object will do just fine as a Float32. BitBuffer:WriteBool(value) BitBuffer:ReadBool() Read / Write a boolean (true / false) value. Takes one bit worth of space to store. BitBuffer:WriteString(str) BitBuffer:ReadString() Read / Write a variable length string. The string may contain embedded nulls. Only 7 bits / character will be used if the string contains no non-printable characters (greater than 0x80). BitBuffer:WriteBrickColor(color) BitBuffer:ReadBrickColor() Read / Write a roblox BrickColor. Provided as an example of reading / writing a derived data type. BitBuffer:WriteRotation(cframe) BitBuffer:ReadRotation() Read / Write the rotation part of a given CFrame. Encodes the rotation in question into 64bits, which is a good size to get a pretty dense packing, but still while having errors well within the threshold that Roblox uses for stuff like MakeJoints() detecting adjacency. Will also perfectly reproduce rotations which are orthagonally aligned, or inverse-power-of-two rotated on only a single axix. For other rotations, the results may not be perfectly stable through read-write cycles (if you read/write an arbitrary rotation thousands of times there may be detectable "drift")
From/To pairs for dumping out the BitBuffer to another format: BitBuffer:ToString() BitBuffer:FromString(str) Will replace / dump out the contents of the buffer to / from a binary chunk encoded as a Lua string. This string is NOT suitable for storage in the Roblox DataStores, as they do not handle non-printable characters well.
BitBuffer:ToBase64() BitBuffer:FromBase64(str) Will replace / dump out the contents of the buffer to / from a set of Base64 encoded data, as a Lua string. This string only consists of Base64 printable characters, so it is ideal for storage in Roblox DataStores.
Buffer / Position Manipulation BitBuffer:ResetPtr() Will Reset the point in the buffer that is being read / written to back to the start of the buffer.
BitBuffer:Reset() Will reset the buffer to a clean state, with no contents.
Example Usage: local function SaveToBuffer(buffer, userData) buffer:WriteString(userData.HeroName) buffer:WriteUnsigned(14, userData.Score) --> 14 bits -> [0, 2^14-1] -> [0, 16383] buffer:WriteBool(userData.HasDoneSomething) buffer:WriteUnsigned(10, #userData.ItemList) --> [0, 1023] for _, itemInfo in pairs(userData.ItemList) do buffer:WriteString(itemInfo.Identifier) buffer:WriteUnsigned(10, itemInfo.Count) --> [0, 1023] end end local function LoadFromBuffer(buffer, userData) userData.HeroName = buffer:ReadString() userData.Score = buffer:ReadUnsigned(14) userData.HasDoneSomething = buffer:ReadBool() local itemCount = buffer:ReadUnsigned(10) for i = 1, itemCount do local itemInfo = {} itemInfo.Identifier = buffer:ReadString() itemInfo.Count = buffer:ReadUnsigned(10) table.insert(userData.ItemList, itemInfo) end end --... local buff = BitBuffer.Create() SaveToBuffer(buff, someUserData) myDataStore:SetAsync(somePlayer.userId, buff:ToBase64()) --... local data = myDataStore:GetAsync(somePlayer.userId) local buff = BitBuffer.Create() buff:FromBase64(data) LoadFromBuffer(buff, someUserData)
Bit Buffer Script
local BitBuffer = {} --[[ String Encoding: Char 1 Char 2 str: LSB--MSB LSB--MSB Bit# 1,2,...8 9,...,16 --]] local DISABLE_WARNINGS = false local NumberToBase64; local Base64ToNumber; do NumberToBase64 = {} Base64ToNumber = {} local chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" for i = 1, #chars do local ch = chars:sub(i, i) NumberToBase64[i-1] = ch Base64ToNumber[ch] = i-1 end end local PowerOfTwo; do PowerOfTwo = {} for i = 0, 64 do PowerOfTwo[i] = 2^i end end local BrickColorToNumber; local NumberToBrickColor; do BrickColorToNumber = {} NumberToBrickColor = {} for i = 0, 63 do local color = BrickColor.palette(i) BrickColorToNumber[color.Number] = i NumberToBrickColor[i] = color end end local floor,insert = math.floor, table.insert function ToBase(n, b) n = floor(n) if not b or b == 10 then return tostring(n) end local digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" local t = {} local sign = "" if n < 0 then sign = "-" n = -n end repeat local d = (n % b) + 1 n = floor(n / b) insert(t, 1, digits:sub(d, d)) until n == 0 return sign..table.concat(t, "") end function BitBuffer.Create() local this = {} -- Tracking local mBitPtr = 0 local mBitBuffer = {} function this:ResetPtr() mBitPtr = 0 end function this:Reset() mBitBuffer = {} mBitPtr = 0 end -- Set debugging on local mDebug = false function this:SetDebug(state) mDebug = state end -- Read / Write to a string function this:FromString(str) this:Reset() for i = 1, #str do local ch = str:sub(i, i):byte() for i = 1, 8 do mBitPtr = mBitPtr + 1 mBitBuffer[mBitPtr] = ch % 2 ch = math.floor(ch / 2) end end mBitPtr = 0 end function this:ToString() local str = "" local accum = 0 local pow = 0 for i = 1, math.ceil((#mBitBuffer) / 8)*8 do accum = accum + PowerOfTwo[pow]*(mBitBuffer[i] or 0) pow = pow + 1 if pow >= 8 then str = str..string.char(accum) accum = 0 pow = 0 end end return str end -- Read / Write to base64 function this:FromBase64(str) this:Reset() for i = 1, #str do local ch = Base64ToNumber[str:sub(i, i)] assert(ch, "Bad character: 0x"..ToBase(str:sub(i, i):byte(), 16)) for i = 1, 6 do mBitPtr = mBitPtr + 1 mBitBuffer[mBitPtr] = ch % 2 ch = math.floor(ch / 2) end assert(ch == 0, "Character value 0x"..ToBase(Base64ToNumber[str:sub(i, i)], 16).." too large") end this:ResetPtr() end function this:ToBase64() local strtab = {} local accum = 0 local pow = 0 for i = 1, math.ceil((#mBitBuffer) / 6)*6 do accum = accum + PowerOfTwo[pow]*(mBitBuffer[i] or 0) pow = pow + 1 if pow >= 6 then table.insert(strtab, NumberToBase64[accum]) accum = 0 pow = 0 end end return table.concat(strtab) end -- Dump function this:Dump() local str = "" local str2 = "" local accum = 0 local pow = 0 for i = 1, math.ceil((#mBitBuffer) / 8)*8 do str2 = str2..(mBitBuffer[i] or 0) accum = accum + PowerOfTwo[pow]*(mBitBuffer[i] or 0) --print(pow..": +"..PowerOfTwo[pow].."*["..(mBitBuffer[i] or 0).."] -> "..accum) pow = pow + 1 if pow >= 8 then str2 = str2.." " str = str.."0x"..ToBase(accum, 16).." " accum = 0 pow = 0 end end print("Bytes:", str) print("Bits:", str2) end -- Read / Write a bit local function writeBit(v) mBitPtr = mBitPtr + 1 mBitBuffer[mBitPtr] = v end local function readBit(v) mBitPtr = mBitPtr + 1 return mBitBuffer[mBitPtr] end function this:PrintPtr() print(mBitPtr.." / "..#mBitBuffer) end -- Read / Write an unsigned number function this:WriteUnsigned(w, value, printoff) assert(w, "Bad arguments to BitBuffer::WriteUnsigned (Missing BitWidth)") assert(value, "Bad arguments to BitBuffer::WriteUnsigned (Missing Value)") assert(value >= 0, "Negative value to BitBuffer::WriteUnsigned") assert(math.floor(value) == value, "Non-integer value to BitBuffer::WriteUnsigned") if mDebug and not printoff then print("WriteUnsigned["..w.."]:", value) end -- Store LSB first for i = 1, w do writeBit(value % 2) value = math.floor(value / 2) end assert(value == 0, "Value "..tostring(value).." has width greater than "..w.."bits") end function this:ReadUnsigned(w, printoff) local value = 0 for i = 1, w do value = value + readBit() * PowerOfTwo[i-1] end if mDebug and not printoff then print("ReadUnsigned["..w.."]:", value) end return value end -- Read / Write a signed number function this:WriteSigned(w, value) assert(w and value, "Bad arguments to BitBuffer::WriteSigned (Did you forget a bitWidth?)") assert(math.floor(value) == value, "Non-integer value to BitBuffer::WriteSigned") if mDebug then print("WriteSigned["..w.."]:", value) end -- Write sign if value < 0 then writeBit(1) value = -value else writeBit(0) end -- Write value this:WriteUnsigned(w-1, value, true) end function this:ReadSigned(w) -- Read sign local sign = (-1)^readBit() -- Read value local value = this:ReadUnsigned(w-1, true) if mDebug then print("ReadSigned["..w.."]:", sign*value) end return sign*value end -- Read / Write a string. May contain embedded nulls (string.char(0)) function this:WriteString(s) -- First check if it's a 7 or 8 bit width of string local bitWidth = 7 for i = 1, #s do if s:sub(i, i):byte() > 127 then bitWidth = 8 break end end -- Write the bit width flag if bitWidth == 7 then this:WriteBool(false) else this:WriteBool(true) -- wide chars end -- Now write out the string, terminated with "0x10, 0b0" -- 0x10 is encoded as "0x10, 0b1" for i = 1, #s do local ch = s:sub(i, i):byte() if ch == 0x10 then this:WriteUnsigned(bitWidth, 0x10) this:WriteBool(true) else this:WriteUnsigned(bitWidth, ch) end end -- Write terminator this:WriteUnsigned(bitWidth, 0x10) this:WriteBool(false) end function this:ReadString() -- Get bit width local bitWidth; if this:ReadBool() then bitWidth = 8 else bitWidth = 7 end -- Loop local str = "" while true do local ch = this:ReadUnsigned(bitWidth) if ch == 0x10 then local flag = this:ReadBool() if flag then str = str..string.char(0x10) else break end else str = str..string.char(ch) end end return str end -- Read / Write a bool function this:WriteBool(v) if mDebug then print("WriteBool[1]:", v and "1" or "0") end if v then this:WriteUnsigned(1, 1, true) else this:WriteUnsigned(1, 0, true) end end function this:ReadBool() local v = (this:ReadUnsigned(1, true) == 1) if mDebug then print("ReadBool[1]:", v and "1" or "0") end return v end -- Read / Write a floating point number with |wfrac| fraction part -- bits, |wexp| exponent part bits, and one sign bit. function this:WriteFloat(wfrac, wexp, f) assert(wfrac and wexp and f) -- Sign local sign = 1 if f < 0 then f = -f sign = -1 end -- Decompose local mantissa, exponent = math.frexp(f) if exponent == 0 and mantissa == 0 then this:WriteUnsigned(wfrac + wexp + 1, 0) return else mantissa = ((mantissa - 0.5)/0.5 * PowerOfTwo[wfrac]) end -- Write sign if sign == -1 then this:WriteBool(true) else this:WriteBool(false) end
(Missing some parts of the code, due to the limit of 10,000 characters on posting answers/questions.)