How can I save players custom built Vehicles?

Hey,

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:

local vehicle = {
[1] = "Engine",
[2] = "Tank",
[3] = "Cabin",
[4] = "Door"
}

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?

Any kind of help would be helpful

4 Likes

Well, with the new DataStore Size, you should be able to store it all in one data store.

1 Like

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
2 Likes

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.

1 Like