im currently creating a game where players can build modular vehicles.
However I can’t figure out on how to save their vehicles in DataStore(2).
So I asked my self how this game achieves it, because it really saves every single parts position.
So in my game for example I got a Vehicle with all its Modules sorted in a Table:
where the Index 1 is the lowest Part of the Vehicle and 4 the highest (sorted with Bubblesort Algorithm and Part.Position.Y)
So there would be no Problem saving this table and just adding those modules when a player wants to load it.
But how could I achieve this when a Player is adding Modules to the “side” of the Vehicle?
All components in a vehicle will be connected, either directly or indirectly through other components. That means the entire vehicle can be represented as a graph where nodes are components and edges are connections between components. To serialize such a graph, you’ll need to serialize the nodes and the edges.
Each node can be represented with it’s component type (ideally a number) and it’s CFrame.
Each edge can be represented as a reference to two different components that are connected through that edge. That means we must be able to tell which node is which, so nodes additionally need a unique ID. Something like this could work, although it’s completely untested but it shows the basic idea.
function tableValues(t: {any}): {any}
local values = {}
for _, value in pairs(t) do
table.insert(values, value)
end
return values
end
function vehicleToTable(vehicle: Model): {any}
local components = getVehicleComponents(vehicle)
local rootComponent = components[1]
local componentDatas = {}
for i, component in ipairs(components) do
componentDatas[component] = {
Id = i,
Type = component.Type.Value,
CFrame = rootComponent.PrimaryPart.CFrame:ToObjectSpace(component.PrimaryPart.CFrame)
}
end
local connectionDatas = {}
for _, component in ipairs(components) do
for _, otherComponent in ipairs(getConnectedComponents(component)) do
table.insert(connectionDatas, {
Component0 = componentDatas[component].Id,
Component1 = componentDatas[otherComponent].Id
})
end
end
return {
RootComponent = componentDatas[rootComponent].Id,
Components = tableValues(componentDatas),
Connections = connectionDatas,
}
end
function tableToVehicle(data: {any}, rootCFrame: CFrame): Model
local vehicle = Instance.new("Model")
local components = {}
local componentDatas = {}
local idComponents = {}
local rootComponent
for _, componentData in ipairs(data.Components) do
local component = game.ServerStorage.Components[componentData.Type]:Clone()
table.insert(components, component)
componentDatas[component] = componentData
idComponents[componentData.Id] = component
if componentData.Id == data.RootComponent then
rootComponent = component
end
end
rootComponent:SetPrimaryPartCFrame(rootCFrame)
for _, component in ipairs(components) do
component:SetPrimaryPartCFrame( rootCFrame * componentDatas[component].CFrame )
end
for _, connectionData in ipairs(data.Connections) do
local weld = Instance.new("WeldConstraint")
weld.Parent = idComponents[connectionData.Component0]
weld.Part0 = idComponents[connectionData.Component0].PrimaryPart
weld.Part0 = idComponents[connectionData.Component1].PrimaryPart
end
return vehicle
end
You need to serialize the data into a format which can be stored inside DataStores, so tables, numbers, strings etc. to represent the individual parts/properties of the vehicle. Then when you load this value from the DataStore you’ll need to deserialize it and appropriately convert the deserialized data into the physical vehicle again by instancing the parts and setting the values of certain properties as necessary.